diff --git a/.gitignore b/.gitignore index 3c761969d..13689e55f 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,5 @@ nbproject/ *.out resources/3rdparty/cudd-3.0.0/Makefile.in resources/3rdparty/cudd-3.0.0/aclocal.m4 -# Python config -stormpy/setup.cfg # Travis helpers travis/mtime_cache/cache.json diff --git a/.travis.yml b/.travis.yml index 2a08f13c7..edeac6e25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,9 @@ sudo: required dist: trusty language: cpp +git: + depth: false + # Enable caching cache: timeout: 1000 @@ -25,7 +28,7 @@ notifications: on_failure: always on_success: change recipients: - secure: "Q9CW/PtyWkZwExDrfFFb9n1STGYsRfI6awv1bZHcGwfrDvhpXoMCuF8CwviIfilm7fFJJEoKizTtdRpY0HrOnY/8KY111xrtcFYosxdndv7xbESodIxQOUoIEFCO0mCNHwWYisoi3dAA7H3Yn661EsxluwHjzX5vY0xSbw0n229hlsFz092HwGLSU33zHl7eXpQk+BOFmBTRGlOq9obtDZ17zbHz1oXFZntHK/JDUIYP0b0uq8NvE2jM6CIVdcuSwmIkOhZJoO2L3Py3rBbPci+L2PSK4Smv2UjCPF8KusnOaFIyDB3LcNM9Jqq5ssJMrK/KaO6BiuYrOZXYWZ7KEg3Y/naC8HjOH1dzty+P7oW46sb9F03pTsufqD4R7wcK+9wROTztO6aJPDG/IPH7EWgrBTxqlOkVRwi2eYuQouZpZUW6EMClKbMHMIxCH2S8aOk/r1w2cNwmPEcunnP0nl413x/ByHr4fTPFykPj8pQxIsllYjpdWBRQfDOauKWGzk6LcrFW0qpWP+/aJ2vYu/IoZQMG5lMHbp6Y1Lg09pYm7Q983v3b7D+JvXhOXMyGq91HyPahA2wwKoG1GA4uoZ2I95/IFYNiKkelDd3WTBoFLNF9YFoEJNdCywm1fO2WY4WkyEFBuQcgDA+YpFMJJMxjTbivYk9jvHk2gji//2w=" + - secure: "VWnsiQkt1xjgRo1hfNiNQqvLSr0fshFmLV7jJlUixhCr094mgD0U2bNKdUfebm28Byg9UyDYPbOFDC0sx7KydKiL1q7FKKXkyZH0k04wUu8XiNw+fYkDpmPnQs7G2n8oJ/GFJnr1Wp/1KI3qX5LX3xot4cJfx1I5iFC2O+p+ng6v/oSX+pewlMv4i7KL16ftHHHMo80N694v3g4B2NByn4GU2/bjVQcqlBp/TiVaUa5Nqu9DxZi/n9CJqGEaRHOblWyMO3EyTZsn45BNSWeQ3DtnMwZ73rlIr9CaEgCeuArc6RGghUAVqRI5ao+N5apekIaILwTgL6AJn+Lw/+NRPa8xclgd0rKqUQJMJCDZKjKz2lmIs3bxfELOizxJ3FJQ5R95FAxeAZ6rb/j40YqVVTw2IMBDnEE0J5ZmpUYNUtPti/Adf6GD9Fb2y8sLo0XDJzkI8OxYhfgjSy5KYmRj8O5MXcP2MAE8LQauNO3MaFnL9VMVOTZePJrPozQUgM021uyahf960+QNI06Uqlmg+PwWkSdllQlxHHplOgW7zClFhtSUpnJxcsUBzgg4kVg80gXUwAQkaDi7A9Wh2bs+TvMlmHzBwg+2SaAfWDgjeJIeOaipDkF1uSGzC+EHAiiKYMLd4Aahoi8SuelJUucoyJyLAq00WdUFQIh/izVhM4Y=" # # Configurations @@ -37,32 +40,32 @@ jobs: # Stage: Build Carl ### - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build Carl os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: - travis/build_carl.sh after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit carl mvolk/carl:travis-debug; - - docker push mvolk/carl:travis-debug; - # ubuntu-17.10 - DefaultReleaseTravis + - docker commit carl movesrwth/carl:travis-debug; + - docker push movesrwth/carl:travis-debug; + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build Carl os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: - travis/build_carl.sh after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit carl mvolk/carl:travis; - - docker push mvolk/carl:travis; + - docker commit carl movesrwth/carl:travis; + - docker push movesrwth/carl:travis; ### # Stage: Build (1st run) @@ -96,11 +99,25 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis + - stage: Build (1st run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc + install: + - rm -rf build + - travis/install_linux.sh + script: + - travis/build.sh Build1 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (1st run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - rm -rf build - travis/install_linux.sh @@ -110,11 +127,25 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultDebug - stage: Build (1st run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - rm -rf build + - travis/install_linux.sh + script: + - travis/build.sh Build1 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (1st run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc install: - rm -rf build - travis/install_linux.sh @@ -155,11 +186,37 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis + - stage: Build (2nd run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build2 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultReleaseTravis + - stage: Build (2nd run) + os: linux + compiler: gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build2 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug - stage: Build (2nd run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -168,11 +225,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultRelease - stage: Build (2nd run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -212,11 +269,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build (3rd run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -225,11 +282,37 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (3rd run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build3 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug + - stage: Build (3rd run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh Build3 + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (3rd run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -269,11 +352,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Build (4th run) os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -282,11 +365,37 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultReleaseTravis + # ubuntu-18.04 - DefaultReleaseTravis - stage: Build (4th run) os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh BuildLast + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultDebug + - stage: Build (4th run) + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh BuildLast + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + # ubuntu-18.04 - DefaultRelease + - stage: Build (4th run) + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -326,11 +435,11 @@ jobs: - docker cp storm:/opt/storm/. . after_failure: - find build -iname '*err*.log' -type f -print -exec cat {} \; - # ubuntu-17.10 - DefaultDebugTravis + # ubuntu-18.04 - DefaultDebugTravis - stage: Test all os: linux compiler: gcc - env: CONFIG=DefaultDebugTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultDebugTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -341,13 +450,13 @@ jobs: - find build -iname '*err*.log' -type f -print -exec cat {} \; after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit storm mvolk/storm:travis-debug; - - docker push mvolk/storm:travis-debug; - # ubuntu-17.10 - DefaultReleaseTravis + - docker commit storm movesrwth/storm:travis-debug; + - docker push movesrwth/storm:travis-debug; + # ubuntu-18.04 - DefaultReleaseTravis - stage: Test all os: linux compiler: gcc - env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-17.10 COMPILER=gcc + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc install: - travis/install_linux.sh script: @@ -358,6 +467,48 @@ jobs: - find build -iname '*err*.log' -type f -print -exec cat {} \; after_success: - docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"; - - docker commit storm mvolk/storm:travis; - - docker push mvolk/storm:travis; + - docker commit storm movesrwth/storm:travis; + - docker push movesrwth/storm:travis; + # ubuntu-18.04 - DefaultDebug + - stage: Test all + os: linux + compiler: gcc + env: CONFIG=DefaultDebug LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh TestAll + 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 + os: linux + compiler: gcc + env: CONFIG=DefaultRelease LINUX=ubuntu-18.04 COMPILER=gcc + install: + - travis/install_linux.sh + script: + - travis/build.sh TestAll + before_cache: + - docker cp storm:/opt/storm/. . + after_failure: + - find build -iname '*err*.log' -type f -print -exec cat {} \; + allow_failures: + - stage: Build (1st run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + - stage: Build (2nd run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + - stage: Build (3rd run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + - stage: Build (4th run) + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc + - stage: Test all + os: linux + env: CONFIG=DefaultReleaseTravis LINUX=ubuntu-18.04 COMPILER=gcc diff --git a/CHANGELOG.md b/CHANGELOG.md index 2de8e7f05..eb2345e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,33 @@ The releases of major and minor versions contain an overview of changes since th Version 1.2.x ------------- -### Version 1.2.2 (to be released) +### Version 1.2.4 (2018/08) +- New binary `storm-conv` that handles conversions between model files (currently: prism to jani) +- Added support for expected time properties for discrete time models +- Bug fix in the parser for DRN (MDPs and MAs might have been affected). +- Several bug fixes related to jani +- `storm-gspn`: Improved .pnpro parser +- `storm-gspn`: Added support for single/infinite/k-server semantics for GSPNs given in the .pnpro format +- `storm-gspn`: Added option to set a global capacity for all places +- `storm-gspn`: Added option to include a set of standard properties when converting GSPNs to jani + +### Version 1.2.3 (2018/07) +- Fix in version parsing + +### Version 1.2.2 (2018/07) +- Sound value iteration (SVI) for DTMCs and MDPs +- Topological solver for linear equation systems and MinMax equation systems (enabled by default) +- Added support for expected total rewards in the sparse engine +- By default, iteration-based solvers are no longer aborted after a given number of steps. +- Improved export for jani models +- A fix in parsing jani properties +- Several extensions to high-level counterexamples +- `storm-parsers` extracted to reduce linking time +- `storm-counterexamples` extracted to reduce linking time +- `storm-dft`: improvements in Galileo parser +- `storm-dft`: test cases for DFT analysis +- Improved Storm installation +- Several bug fixes ### Version 1.2.1 (2018/02) - Multi-dimensional reward bounded reachability properties for DTMCs. diff --git a/CMakeLists.txt b/CMakeLists.txt index f284dae11..2dec13d80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,15 @@ set(BIN_INSTALL_DIR lib/ CACHE PATH "Installation directory for executables") set(DEF_INSTALL_CMAKE_DIR "lib/CMake/storm") set(CMAKE_INSTALL_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") -message("CMAKE_INSTALL_DIR: ${CMAKE_INSTALL_DIR}") +# Add CMake install prefix +foreach(p LIB BIN INCLUDE CMAKE) + set(var ${p}_INSTALL_DIR) + if(NOT IS_ABSOLUTE "${${var}}") + set(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") + endif() +endforeach() + +message(STATUS "Storm - CMake install dir: ${CMAKE_INSTALL_DIR}") # If the STORM_DEVELOPER option was turned on, by default we target a debug version, otherwise a release version. if (STORM_DEVELOPER) @@ -145,15 +153,15 @@ elseif (WIN32) set(STATIC_EXT ".lib") set(LIB_PREFIX "") endif() -message(STATUS "Assuming extension for shared libraries: ${DYNAMIC_EXT}") -message(STATUS "Assuming extension for static libraries: ${STATIC_EXT}") +message(STATUS "Storm - Assuming extension for shared libraries: ${DYNAMIC_EXT}") +message(STATUS "Storm - Assuming extension for static libraries: ${STATIC_EXT}") if(BUILD_SHARED_LIBS) set(LIB_EXT ${DYNAMIC_EXT}) - message(STATUS "Build dynamic libraries.") + message(STATUS "Storm - Build dynamic libraries.") else() set(LIB_EXT ${STATIC_EXT}) - message(STATUS "Build static libraries.") + message(STATUS "Storm - Build static libraries.") endif() ############################################################# @@ -179,17 +187,12 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") set(STORM_COMPILER_APPLECLANG ON) set(CLANG ON) set(STORM_COMPILER_ID "AppleClang") - set(CMAKE_MACOSX_RPATH ON) + set(CMAKE_MACOSX_RPATH ON) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(GCC ON) # using GCC if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "gcc version must be at least 5.0.") - elseif (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0) - if (STORM_USE_LTO) - set(STORM_USE_LTO OFF) - message(WARNING "Disabling link-time optimization, because of known incompatibility of LTO with gcc >= 7.") - endif() endif() set(STORM_COMPILER_GCC ON) @@ -228,16 +231,16 @@ if (STORM_COMPILER_CLANG OR STORM_COMPILER_APPLECLANG) if(FORCE_COLOR) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics") endif() - + if (LINUX) set(CLANG_STDLIB libstdc++) else() set(CLANG_STDLIB libc++) endif() - + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -stdlib=${CLANG_STDLIB} -ftemplate-depth=1024") - set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math -fno-finite-math-only") - + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + if(LINUX) set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") @@ -247,20 +250,20 @@ if (STORM_COMPILER_CLANG OR STORM_COMPILER_APPLECLANG) endif() elseif (STORM_COMPILER_GCC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprefetch-loop-arrays -ffast-math -fno-finite-math-only") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fprefetch-loop-arrays") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") endif () if (STORM_USE_LTO) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") - + # Fix for problems that occurred when using LTO on gcc. This should be removed when it # is not needed anymore as it makes the the already long link-step potentially longer. if (STORM_COMPILER_GCC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto-partition=none") endif() - + message(STATUS "Storm - Enabling link-time optimizations.") else() message(STATUS "Storm - Disabling link-time optimizations.") @@ -408,7 +411,7 @@ endif(DOXYGEN_FOUND) # try to obtain the current version from git. include(GetGitRevisionDescription) get_git_head_revision(STORM_VERSION_REFSPEC STORM_VERSION_GIT_HASH) -git_describe_checkout(STORM_GIT_VERSION_STRING) +git_describe(STORM_GIT_VERSION_STRING) # parse the git tag into variables # start with major.minor.patch @@ -417,22 +420,22 @@ set(STORM_VERSION_MAJOR "${CMAKE_MATCH_1}") set(STORM_VERSION_MINOR "${CMAKE_MATCH_2}") set(STORM_VERSION_PATCH "${CMAKE_MATCH_3}") set(STORM_GIT_VERSION_REST "${CMAKE_MATCH_4}") -# parse rest of the form (-label)-commitsahead-hash-appendix +# parse rest of the form (-label)-commitsahead-hash(-appendix) string(REGEX MATCH "^(\\-([a-z][a-z0-9\\.]+))?\\-([0-9]+)\\-([a-z0-9]+)(\\-.*)?$" STORM_VERSION_REST_MATCH "${STORM_GIT_VERSION_REST}") set(STORM_VERSION_LABEL "${CMAKE_MATCH_2}") # might be empty set(STORM_VERSION_COMMITS_AHEAD "${CMAKE_MATCH_3}") -set(STORM_VERSION_TAG_HASH "${CMAKE_MATCH_4}") +set(STORM_VERSION_TAG_HASH "${CMAKE_MATCH_4}") # is not used set(STORM_VERSION_APPENDIX "${CMAKE_MATCH_5}") # might be empty -# now check whether the git version lookup failed -if (STORM_VERSION_MAJOR MATCHES "NOTFOUND") - include(version.cmake) - set(STORM_VERSION_LABEL "") +# check whether the git version lookup failed +if (STORM_GIT_VERSION_STRING MATCHES "NOTFOUND") + set(STORM_VERSION_SOURCE "VersionSource::Static") set(STORM_VERSION_COMMITS_AHEAD 0) - set(STORM_VERSION_GIT_HASH "") set(STORM_VERSION_DIRTY boost::none) - message(WARNING "Storm - git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") + include(version.cmake) + message(WARNING "Storm - Git version information not available, statically assuming version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}.") else() + set(STORM_VERSION_SOURCE "VersionSource::Git") if ("${STORM_VERSION_APPENDIX}" MATCHES "^.*dirty.*$") set(STORM_VERSION_DIRTY "true") else() @@ -448,18 +451,19 @@ else() endif() # check for development version with commits ahead of latest tag -set(STORM_VERSION_DEV "false") -set(STORM_VERSION_DEV_STRING "") if(STORM_VERSION_COMMITS_AHEAD) + set(STORM_VERSION_DEV "true") + set(STORM_VERSION_DEV_STRING " (dev)") if ("${STORM_VERSION_LABEL}" STREQUAL "") # increase patch number to indicate newer version MATH(EXPR STORM_VERSION_DEV_PATCH "${STORM_VERSION_PATCH}+1") else() set(STORM_VERSION_DEV_PATCH "${STORM_VERSION_PATCH}") endif() - set(STORM_VERSION_DEV "true") - set(STORM_VERSION_DEV_STRING " (dev)") else() + set(STORM_VERSION_COMMITS_AHEAD 0) + set(STORM_VERSION_DEV "false") + set(STORM_VERSION_DEV_STRING "") set(STORM_VERSION_DEV_PATCH ${STORM_VERSION_PATCH}) endif() @@ -467,7 +471,7 @@ endif() set(STORM_VERSION "${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_DEV_PATCH}") set(STORM_VERSION_STRING "${STORM_VERSION}${STORM_VERSION_LABEL_STRING}${STORM_VERSION_DEV_STRING}") -message(STATUS "Storm - version is ${STORM_VERSION_STRING} (version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}${STORM_VERSION_LABEL_STRING} + ${STORM_VERSION_COMMITS_AHEAD} commits), building from git: ${STORM_VERSION_GIT_HASH} (dirty: ${STORM_VERSION_DIRTY}).") +message(STATUS "Storm - Version is ${STORM_VERSION_STRING} (version ${STORM_VERSION_MAJOR}.${STORM_VERSION_MINOR}.${STORM_VERSION_PATCH}${STORM_VERSION_LABEL_STRING} + ${STORM_VERSION_COMMITS_AHEAD} commits), building from git: ${STORM_VERSION_GIT_HASH} (dirty: ${STORM_VERSION_DIRTY}).") # Configure a header file to pass some of the CMake settings to the source code @@ -502,4 +506,8 @@ add_subdirectory(src) include(export) +install(FILES ${CMAKE_BINARY_DIR}/stormConfig.install.cmake DESTINATION ${CMAKE_INSTALL_DIR} RENAME stormConfig.cmake) +install(FILES ${CMAKE_BINARY_DIR}/stormConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_DIR}) +install(EXPORT storm_Targets FILE stormTargets.cmake DESTINATION ${CMAKE_INSTALL_DIR}) + include(StormCPackConfig.cmake) diff --git a/README.md b/README.md index a415b376e..6dcf702a0 100644 --- a/README.md +++ b/README.md @@ -30,15 +30,15 @@ Authors Storm has been developed at RWTH Aachen University. ###### Principal developers -* Christian Dehnert +* Christian Hensel * Sebastian Junges * Joost-Pieter Katoen +* Tim Quatmann * Matthias Volk ###### Developers (lexicographical order) * Philipp Berger * David Korzeniewski -* Tim Quatmann ###### Contributors (lexicographical order) * Dimitri Bohlender diff --git a/doc/checklist_new_release.md b/doc/checklist_new_release.md index 05be534aa..a55349ef5 100644 --- a/doc/checklist_new_release.md +++ b/doc/checklist_new_release.md @@ -1,5 +1,5 @@ The following steps should be performed before releasing a new storm version. -Note that in most case a simultaneous release of [carl](https://github.com/smtrat/carl), [storm](https://github.com/moves-rwth/storm), [pycarl](https://github.com/moves-rwth/pycarl/) and [stormpy](https://github.com/moves-rwth/stormpy/) is preferred. +Note that in most cases a simultaneous release of [carl](https://github.com/smtrat/carl), [storm](https://github.com/moves-rwth/storm), [pycarl](https://github.com/moves-rwth/pycarl/) and [stormpy](https://github.com/moves-rwth/stormpy/) is preferred. 1. Update `CHANGELOG.md` To get all the commits from an author since the last tag execute: diff --git a/resources/3rdparty/CMakeLists.txt b/resources/3rdparty/CMakeLists.txt index 979c5cbe8..ae3f0ee85 100644 --- a/resources/3rdparty/CMakeLists.txt +++ b/resources/3rdparty/CMakeLists.txt @@ -141,33 +141,46 @@ find_package(Z3 QUIET) # Z3 Defines set(STORM_HAVE_Z3 ${Z3_FOUND}) + if(Z3_FOUND) - # Check whether the version of z3 supports optimization - if (Z3_EXEC) - execute_process (COMMAND ${Z3_EXEC} -version - OUTPUT_VARIABLE z3_version_output - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) + # Get the z3 version by compiling and running a simple program + try_run(version_run_result version_compile_result "${STORM_3RDPARTY_BINARY_DIR}/z3/" "${PROJECT_SOURCE_DIR}/resources/3rdparty/z3/output_version.cpp" CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${Z3_INCLUDE_DIR}" LINK_LIBRARIES "${Z3_LIBRARIES}" RUN_OUTPUT_VARIABLE z3_version_output) + if (version_compile_result AND version_run_result EQUAL 0) if (z3_version_output MATCHES "([0-9]*\\.[0-9]*\\.[0-9]*)") set(Z3_VERSION "${CMAKE_MATCH_1}") - if(NOT "${Z3_VERSION}" VERSION_LESS "4.5.0") - set(STORM_HAVE_Z3_OPTIMIZE ON) - endif() endif() endif() - if(STORM_HAVE_Z3_OPTIMIZE) - message (STATUS "Storm - Linking with Z3. (Z3 version supports optimization)") + if(Z3_VERSION) + # Split Z3 version into its components + string(REPLACE "." ";" Z3_VERSION_LIST ${Z3_VERSION}) + list(GET Z3_VERSION_LIST 0 STORM_Z3_VERSION_MAJOR) + list(GET Z3_VERSION_LIST 1 STORM_Z3_VERSION_MINOR) + list(GET Z3_VERSION_LIST 2 STORM_Z3_VERSION_PATCH) + + # Check whether the version of z3 supports optimization + if(NOT "${Z3_VERSION}" VERSION_LESS "4.5.0") + set(STORM_HAVE_Z3_OPTIMIZE ON) + message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version supports optimization)") + else() + message (STATUS "Storm - Linking with Z3 (version ${Z3_VERSION}). (Z3 version does not support optimization)") + endif() + if (NOT "${Z3_VERSION}" VERSION_LESS "4.7.1") + set(STORM_Z3_API_USES_STANDARD_INTEGERS ON) + endif() + + add_imported_library(z3 SHARED ${Z3_LIBRARIES} ${Z3_INCLUDE_DIRS}) + list(APPEND STORM_DEP_TARGETS z3_SHARED) else() - message (STATUS "Storm - Linking with Z3. (Z3 version does not support optimization)") + message(WARNING "Storm - Could not obtain Z3 version. Building of Prism/JANI models will not be supported.") + set(Z3_FOUND FALSE) endif() - add_imported_library(z3 SHARED ${Z3_LIBRARIES} ${Z3_INCLUDE_DIRS}) - list(APPEND STORM_DEP_TARGETS z3_SHARED) else() message (WARNING "Storm - Z3 not found. Building of Prism/JANI models will not be supported.") endif(Z3_FOUND) + ############################################################# ## ## glpk @@ -209,6 +222,7 @@ include(${STORM_3RDPARTY_SOURCE_DIR}/include_cudd.cmake) set(STORM_HAVE_CARL OFF) set(CARL_MINVERSION "17.12") +set(CARL_C14VERSION "14.1") if (NOT STORM_FORCE_SHIPPED_CARL) if (NOT "${STORM_CARL_DIR_HINT}" STREQUAL "") find_package(carl QUIET PATHS ${STORM_CARL_DIR_HINT} NO_DEFAULT_PATH) @@ -226,7 +240,9 @@ if(carl_FOUND AND NOT STORM_FORCE_SHIPPED_CARL) else() message(SEND_ERROR "File ${carlLOCATION} does not exist, did you build carl?") endif() - if("${carl_VERSION_MAJOR}.${carl_VERSION_MINOR}" VERSION_LESS "${CARL_MINVERSION}") + if("${carl_VERSION_MAJOR}.${carl_VERSION_MINOR}" STREQUAL "${CARL_C14VERSION}") + # empty on purpose. Maybe put a warning here? + elseif("${carl_VERSION_MAJOR}.${carl_VERSION_MINOR}" VERSION_LESS "${CARL_MINVERSION}") message(SEND_ERROR "Carl outdated, require ${CARL_MINVERSION}, have ${carl_VERSION}") endif() @@ -239,16 +255,16 @@ if(carl_FOUND AND NOT STORM_FORCE_SHIPPED_CARL) else() set(STORM_SHIPPED_CARL ON) # The first external project will be built at *configure stage* - message("START CARL CONFIG PROCESS") - file(MAKE_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download) + message(STATUS "Carl - Start of config process") + file(MAKE_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download) execute_process( COMMAND ${CMAKE_COMMAND} ${STORM_3RDPARTY_SOURCE_DIR}/carl "-DSTORM_3RDPARTY_BINARY_DIR=${STORM_3RDPARTY_BINARY_DIR}" "-DBoost_LIBRARY_DIRS=${Boost_LIBRARY_DIRS}" "-DBoost_INCLUDE_DIRS=${Boost_INCLUDE_DIRS}" WORKING_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download OUTPUT_VARIABLE carlconfig_out RESULT_VARIABLE carlconfig_result) - + if(NOT carlconfig_result) - message("${carlconfig_out}") + message(STATUS "${carlconfig_out}") endif() execute_process( COMMAND ${CMAKE_COMMAND} --build . --target carl-config @@ -257,10 +273,10 @@ else() RESULT_VARIABLE carlconfig_result ) if(NOT carlconfig_result) - message("${carlconfig_out}") + message(STATUS "${carlconfig_out}") endif() - message("END CARL CONFIG PROCESS") - + message(STATUS "Carl - End of config process") + message(STATUS "Storm - Using shipped version of carl.") ExternalProject_Add( carl @@ -285,7 +301,7 @@ else() set(STORM_HAVE_CARL ON) message(STATUS "Storm - Linking with shipped carl ${carl_VERSION} (include: ${carl_INCLUDE_DIR}, library ${carl_LIBRARIES}, CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}, CARL_USE_GINAC: ${CARL_USE_GINAC}).") - + # install the carl dynamic library if we built it install(FILES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl.${carl_VERSION}${DYNAMIC_EXT} DESTINATION lib) endif() diff --git a/resources/3rdparty/carl/CMakeLists.txt b/resources/3rdparty/carl/CMakeLists.txt index 4b819682d..e74d53de6 100644 --- a/resources/3rdparty/carl/CMakeLists.txt +++ b/resources/3rdparty/carl/CMakeLists.txt @@ -4,11 +4,11 @@ include(ExternalProject) option(STORM_3RDPARTY_BINARY_DIR "3rd party bin dir") -message(STORM_3RDPARTY_BINARY_DIR: ${STORM_3RDPARTY_BINARY_DIR}) +message(STATUS "Carl - Storm 3rdparty binary dir: ${STORM_3RDPARTY_BINARY_DIR}") ExternalProject_Add(carl-config GIT_REPOSITORY https://github.com/smtrat/carl - GIT_TAG 17.12 + GIT_TAG 18.06 PREFIX here SOURCE_DIR source_dir BINARY_DIR ${STORM_3RDPARTY_BINARY_DIR}/carl @@ -22,4 +22,4 @@ ExternalProject_Add(carl-config add_custom_target(build-carl) add_dependencies(build-carl carl-config) -message("done") +message(STATUS "Carl - Finished configuration.") diff --git a/resources/3rdparty/cudd-3.0.0/Makefile.in b/resources/3rdparty/cudd-3.0.0/Makefile.in deleted file mode 100644 index c18a9a946..000000000 --- a/resources/3rdparty/cudd-3.0.0/Makefile.in +++ /dev/null @@ -1,3191 +0,0 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2014 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -@DDDMP_TRUE@am__append_1 = dddmp/dddmp.h -@OBJ_TRUE@am__append_2 = cplusplus/cuddObj.hh -check_PROGRAMS = cudd/testcudd$(EXEEXT) cudd/testextra$(EXEEXT) \ - st/testst$(EXEEXT) mtr/testmtr$(EXEEXT) \ - dddmp/testdddmp$(EXEEXT) cplusplus/testobj$(EXEEXT) \ - cplusplus/testmulti$(EXEEXT) nanotrav/nanotrav$(EXEEXT) -@CROSS_COMPILING_FALSE@am__append_3 = cudd/test_cudd.test \ -@CROSS_COMPILING_FALSE@ st/test_st.test mtr/test_mtr.test \ -@CROSS_COMPILING_FALSE@ dddmp/test_dddmp.test \ -@CROSS_COMPILING_FALSE@ cplusplus/test_obj.test \ -@CROSS_COMPILING_FALSE@ nanotrav/test_ntrv.test -@DDDMP_TRUE@am__append_4 = $(dddmp_sources) -@DDDMP_FALSE@am__append_5 = dddmp/libdddmp.la -@OBJ_TRUE@am__append_6 = $(cplusplus_sources) -@OBJ_FALSE@am__append_7 = cplusplus/libobj.la -@HAVE_PDFLATEX_TRUE@am__append_8 = doc/cudd.pdf doc/cudd.aux doc/cudd.idx doc/cudd.ilg doc/cudd.ind \ -@HAVE_PDFLATEX_TRUE@ doc/cudd.log doc/cudd.out doc/cudd.toc - -subdir = . -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/modern_cxx.m4 $(top_srcdir)/m4/w32.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(dist_check_DATA) \ - $(am__include_HEADERS_DIST) $(am__DIST_COMMON) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = Doxyfile doc/cudd.tex dddmp/exp/test1.sh \ - dddmp/exp/test2.sh dddmp/exp/test3.sh dddmp/exp/test4.sh \ - dddmp/exp/test5.sh dddmp/exp/test6.sh dddmp/exp/test7.sh -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" -LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) -cplusplus_libobj_la_LIBADD = -am__cplusplus_libobj_la_SOURCES_DIST = cplusplus/cuddObj.hh \ - cplusplus/cuddObj.cc -am__dirstamp = $(am__leading_dot)dirstamp -am__objects_1 = cplusplus/cplusplus_libobj_la-cuddObj.lo -@OBJ_FALSE@am_cplusplus_libobj_la_OBJECTS = $(am__objects_1) -cplusplus_libobj_la_OBJECTS = $(am_cplusplus_libobj_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -@OBJ_FALSE@am_cplusplus_libobj_la_rpath = -cudd_libcudd_la_DEPENDENCIES = -am__cudd_libcudd_la_SOURCES_DIST = cudd/cudd.h cudd/cuddInt.h \ - cudd/cuddAddAbs.c cudd/cuddAddApply.c cudd/cuddAddFind.c \ - cudd/cuddAddInv.c cudd/cuddAddIte.c cudd/cuddAddNeg.c \ - cudd/cuddAddWalsh.c cudd/cuddAndAbs.c cudd/cuddAnneal.c \ - cudd/cuddApa.c cudd/cuddAPI.c cudd/cuddApprox.c \ - cudd/cuddBddAbs.c cudd/cuddBddCorr.c cudd/cuddBddIte.c \ - cudd/cuddBridge.c cudd/cuddCache.c cudd/cuddCheck.c \ - cudd/cuddClip.c cudd/cuddCof.c cudd/cuddCompose.c \ - cudd/cuddDecomp.c cudd/cuddEssent.c cudd/cuddExact.c \ - cudd/cuddExport.c cudd/cuddGenCof.c cudd/cuddGenetic.c \ - cudd/cuddGroup.c cudd/cuddHarwell.c cudd/cuddInit.c \ - cudd/cuddInteract.c cudd/cuddLCache.c cudd/cuddLevelQ.c \ - cudd/cuddLinear.c cudd/cuddLiteral.c cudd/cuddMatMult.c \ - cudd/cuddPriority.c cudd/cuddRead.c cudd/cuddRef.c \ - cudd/cuddReorder.c cudd/cuddSat.c cudd/cuddSign.c \ - cudd/cuddSolve.c cudd/cuddSplit.c cudd/cuddSubsetHB.c \ - cudd/cuddSubsetSP.c cudd/cuddSymmetry.c cudd/cuddTable.c \ - cudd/cuddUtil.c cudd/cuddWindow.c cudd/cuddZddCount.c \ - cudd/cuddZddFuncs.c cudd/cuddZddGroup.c cudd/cuddZddIsop.c \ - cudd/cuddZddLin.c cudd/cuddZddMisc.c cudd/cuddZddPort.c \ - cudd/cuddZddReord.c cudd/cuddZddSetop.c cudd/cuddZddSymm.c \ - cudd/cuddZddUtil.c util/util.h util/cstringstream.h \ - util/cpu_stats.c util/cpu_time.c util/cstringstream.c \ - util/datalimit.c util/pathsearch.c util/pipefork.c \ - util/prtime.c util/safe_mem.c util/strsav.c util/texpand.c \ - util/ucbqsort.c st/st.h st/st.c epd/epd.c epd/epdInt.h \ - epd/epd.h mtr/mtr.h mtr/mtrInt.h mtr/mtrBasic.c mtr/mtrGroup.c \ - dddmp/dddmp.h dddmp/dddmpInt.h dddmp/dddmpBinary.c \ - dddmp/dddmpConvert.c dddmp/dddmpDbg.c dddmp/dddmpLoad.c \ - dddmp/dddmpLoadCnf.c dddmp/dddmpNodeAdd.c dddmp/dddmpNodeBdd.c \ - dddmp/dddmpNodeCnf.c dddmp/dddmpStoreAdd.c \ - dddmp/dddmpStoreBdd.c dddmp/dddmpStoreCnf.c \ - dddmp/dddmpStoreMisc.c dddmp/dddmpUtil.c cplusplus/cuddObj.hh \ - cplusplus/cuddObj.cc -am__objects_2 = dddmp/cudd_libcudd_la-dddmpBinary.lo \ - dddmp/cudd_libcudd_la-dddmpConvert.lo \ - dddmp/cudd_libcudd_la-dddmpDbg.lo \ - dddmp/cudd_libcudd_la-dddmpLoad.lo \ - dddmp/cudd_libcudd_la-dddmpLoadCnf.lo \ - dddmp/cudd_libcudd_la-dddmpNodeAdd.lo \ - dddmp/cudd_libcudd_la-dddmpNodeBdd.lo \ - dddmp/cudd_libcudd_la-dddmpNodeCnf.lo \ - dddmp/cudd_libcudd_la-dddmpStoreAdd.lo \ - dddmp/cudd_libcudd_la-dddmpStoreBdd.lo \ - dddmp/cudd_libcudd_la-dddmpStoreCnf.lo \ - dddmp/cudd_libcudd_la-dddmpStoreMisc.lo \ - dddmp/cudd_libcudd_la-dddmpUtil.lo -@DDDMP_TRUE@am__objects_3 = $(am__objects_2) -am__objects_4 = cplusplus/cudd_libcudd_la-cuddObj.lo -@OBJ_TRUE@am__objects_5 = $(am__objects_4) -am_cudd_libcudd_la_OBJECTS = cudd/cudd_libcudd_la-cuddAddAbs.lo \ - cudd/cudd_libcudd_la-cuddAddApply.lo \ - cudd/cudd_libcudd_la-cuddAddFind.lo \ - cudd/cudd_libcudd_la-cuddAddInv.lo \ - cudd/cudd_libcudd_la-cuddAddIte.lo \ - cudd/cudd_libcudd_la-cuddAddNeg.lo \ - cudd/cudd_libcudd_la-cuddAddWalsh.lo \ - cudd/cudd_libcudd_la-cuddAndAbs.lo \ - cudd/cudd_libcudd_la-cuddAnneal.lo \ - cudd/cudd_libcudd_la-cuddApa.lo \ - cudd/cudd_libcudd_la-cuddAPI.lo \ - cudd/cudd_libcudd_la-cuddApprox.lo \ - cudd/cudd_libcudd_la-cuddBddAbs.lo \ - cudd/cudd_libcudd_la-cuddBddCorr.lo \ - cudd/cudd_libcudd_la-cuddBddIte.lo \ - cudd/cudd_libcudd_la-cuddBridge.lo \ - cudd/cudd_libcudd_la-cuddCache.lo \ - cudd/cudd_libcudd_la-cuddCheck.lo \ - cudd/cudd_libcudd_la-cuddClip.lo \ - cudd/cudd_libcudd_la-cuddCof.lo \ - cudd/cudd_libcudd_la-cuddCompose.lo \ - cudd/cudd_libcudd_la-cuddDecomp.lo \ - cudd/cudd_libcudd_la-cuddEssent.lo \ - cudd/cudd_libcudd_la-cuddExact.lo \ - cudd/cudd_libcudd_la-cuddExport.lo \ - cudd/cudd_libcudd_la-cuddGenCof.lo \ - cudd/cudd_libcudd_la-cuddGenetic.lo \ - cudd/cudd_libcudd_la-cuddGroup.lo \ - cudd/cudd_libcudd_la-cuddHarwell.lo \ - cudd/cudd_libcudd_la-cuddInit.lo \ - cudd/cudd_libcudd_la-cuddInteract.lo \ - cudd/cudd_libcudd_la-cuddLCache.lo \ - cudd/cudd_libcudd_la-cuddLevelQ.lo \ - cudd/cudd_libcudd_la-cuddLinear.lo \ - cudd/cudd_libcudd_la-cuddLiteral.lo \ - cudd/cudd_libcudd_la-cuddMatMult.lo \ - cudd/cudd_libcudd_la-cuddPriority.lo \ - cudd/cudd_libcudd_la-cuddRead.lo \ - cudd/cudd_libcudd_la-cuddRef.lo \ - cudd/cudd_libcudd_la-cuddReorder.lo \ - cudd/cudd_libcudd_la-cuddSat.lo \ - cudd/cudd_libcudd_la-cuddSign.lo \ - cudd/cudd_libcudd_la-cuddSolve.lo \ - cudd/cudd_libcudd_la-cuddSplit.lo \ - cudd/cudd_libcudd_la-cuddSubsetHB.lo \ - cudd/cudd_libcudd_la-cuddSubsetSP.lo \ - cudd/cudd_libcudd_la-cuddSymmetry.lo \ - cudd/cudd_libcudd_la-cuddTable.lo \ - cudd/cudd_libcudd_la-cuddUtil.lo \ - cudd/cudd_libcudd_la-cuddWindow.lo \ - cudd/cudd_libcudd_la-cuddZddCount.lo \ - cudd/cudd_libcudd_la-cuddZddFuncs.lo \ - cudd/cudd_libcudd_la-cuddZddGroup.lo \ - cudd/cudd_libcudd_la-cuddZddIsop.lo \ - cudd/cudd_libcudd_la-cuddZddLin.lo \ - cudd/cudd_libcudd_la-cuddZddMisc.lo \ - cudd/cudd_libcudd_la-cuddZddPort.lo \ - cudd/cudd_libcudd_la-cuddZddReord.lo \ - cudd/cudd_libcudd_la-cuddZddSetop.lo \ - cudd/cudd_libcudd_la-cuddZddSymm.lo \ - cudd/cudd_libcudd_la-cuddZddUtil.lo \ - util/cudd_libcudd_la-cpu_stats.lo \ - util/cudd_libcudd_la-cpu_time.lo \ - util/cudd_libcudd_la-cstringstream.lo \ - util/cudd_libcudd_la-datalimit.lo \ - util/cudd_libcudd_la-pathsearch.lo \ - util/cudd_libcudd_la-pipefork.lo \ - util/cudd_libcudd_la-prtime.lo \ - util/cudd_libcudd_la-safe_mem.lo \ - util/cudd_libcudd_la-strsav.lo util/cudd_libcudd_la-texpand.lo \ - util/cudd_libcudd_la-ucbqsort.lo st/cudd_libcudd_la-st.lo \ - epd/cudd_libcudd_la-epd.lo mtr/cudd_libcudd_la-mtrBasic.lo \ - mtr/cudd_libcudd_la-mtrGroup.lo $(am__objects_3) \ - $(am__objects_5) -cudd_libcudd_la_OBJECTS = $(am_cudd_libcudd_la_OBJECTS) -cudd_libcudd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ - $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ - $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(cudd_libcudd_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -dddmp_libdddmp_la_LIBADD = -am__dddmp_libdddmp_la_SOURCES_DIST = dddmp/dddmp.h dddmp/dddmpInt.h \ - dddmp/dddmpBinary.c dddmp/dddmpConvert.c dddmp/dddmpDbg.c \ - dddmp/dddmpLoad.c dddmp/dddmpLoadCnf.c dddmp/dddmpNodeAdd.c \ - dddmp/dddmpNodeBdd.c dddmp/dddmpNodeCnf.c \ - dddmp/dddmpStoreAdd.c dddmp/dddmpStoreBdd.c \ - dddmp/dddmpStoreCnf.c dddmp/dddmpStoreMisc.c dddmp/dddmpUtil.c -am__objects_6 = dddmp/dddmp_libdddmp_la-dddmpBinary.lo \ - dddmp/dddmp_libdddmp_la-dddmpConvert.lo \ - dddmp/dddmp_libdddmp_la-dddmpDbg.lo \ - dddmp/dddmp_libdddmp_la-dddmpLoad.lo \ - dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo \ - dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo \ - dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo \ - dddmp/dddmp_libdddmp_la-dddmpUtil.lo -@DDDMP_FALSE@am_dddmp_libdddmp_la_OBJECTS = $(am__objects_6) -dddmp_libdddmp_la_OBJECTS = $(am_dddmp_libdddmp_la_OBJECTS) -@DDDMP_FALSE@am_dddmp_libdddmp_la_rpath = -am_cplusplus_testmulti_OBJECTS = \ - cplusplus/cplusplus_testmulti-testmulti.$(OBJEXT) -cplusplus_testmulti_OBJECTS = $(am_cplusplus_testmulti_OBJECTS) -@OBJ_FALSE@cplusplus_testmulti_DEPENDENCIES = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testmulti_DEPENDENCIES = cudd/libcudd.la -cplusplus_testmulti_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ - $(AM_CXXFLAGS) $(CXXFLAGS) $(cplusplus_testmulti_LDFLAGS) \ - $(LDFLAGS) -o $@ -am_cplusplus_testobj_OBJECTS = \ - cplusplus/cplusplus_testobj-testobj.$(OBJEXT) -cplusplus_testobj_OBJECTS = $(am_cplusplus_testobj_OBJECTS) -@OBJ_FALSE@cplusplus_testobj_DEPENDENCIES = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testobj_DEPENDENCIES = cudd/libcudd.la -am_cudd_testcudd_OBJECTS = cudd/cudd_testcudd-testcudd.$(OBJEXT) -cudd_testcudd_OBJECTS = $(am_cudd_testcudd_OBJECTS) -cudd_testcudd_DEPENDENCIES = cudd/libcudd.la -am_cudd_testextra_OBJECTS = cudd/cudd_testextra-testextra.$(OBJEXT) -cudd_testextra_OBJECTS = $(am_cudd_testextra_OBJECTS) -cudd_testextra_DEPENDENCIES = cudd/libcudd.la -am_dddmp_testdddmp_OBJECTS = \ - dddmp/dddmp_testdddmp-testdddmp.$(OBJEXT) -dddmp_testdddmp_OBJECTS = $(am_dddmp_testdddmp_OBJECTS) -@DDDMP_FALSE@dddmp_testdddmp_DEPENDENCIES = dddmp/libdddmp.la \ -@DDDMP_FALSE@ cudd/libcudd.la -@DDDMP_TRUE@dddmp_testdddmp_DEPENDENCIES = cudd/libcudd.la -am_mtr_testmtr_OBJECTS = mtr/mtr_testmtr-testmtr.$(OBJEXT) -mtr_testmtr_OBJECTS = $(am_mtr_testmtr_OBJECTS) -mtr_testmtr_DEPENDENCIES = cudd/libcudd.la -am_nanotrav_nanotrav_OBJECTS = \ - nanotrav/nanotrav_nanotrav-bnet.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-chkMterm.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-main.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrBddTest.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntr.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrHeap.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrMflow.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrShort.$(OBJEXT) \ - nanotrav/nanotrav_nanotrav-ntrZddTest.$(OBJEXT) -nanotrav_nanotrav_OBJECTS = $(am_nanotrav_nanotrav_OBJECTS) -@DDDMP_FALSE@nanotrav_nanotrav_DEPENDENCIES = dddmp/libdddmp.la \ -@DDDMP_FALSE@ cudd/libcudd.la -@DDDMP_TRUE@nanotrav_nanotrav_DEPENDENCIES = cudd/libcudd.la -am_st_testst_OBJECTS = st/st_testst-testst.$(OBJEXT) -st_testst_OBJECTS = $(am_st_testst_OBJECTS) -st_testst_DEPENDENCIES = cudd/libcudd.la -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CXXFLAGS) $(CXXFLAGS) -AM_V_CXX = $(am__v_CXX_@AM_V@) -am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) -am__v_CXX_0 = @echo " CXX " $@; -am__v_CXX_1 = -CXXLD = $(CXX) -CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ - $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) -am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) -am__v_CXXLD_0 = @echo " CXXLD " $@; -am__v_CXXLD_1 = -SOURCES = $(cplusplus_libobj_la_SOURCES) $(cudd_libcudd_la_SOURCES) \ - $(dddmp_libdddmp_la_SOURCES) $(cplusplus_testmulti_SOURCES) \ - $(cplusplus_testobj_SOURCES) $(cudd_testcudd_SOURCES) \ - $(cudd_testextra_SOURCES) $(dddmp_testdddmp_SOURCES) \ - $(mtr_testmtr_SOURCES) $(nanotrav_nanotrav_SOURCES) \ - $(st_testst_SOURCES) -DIST_SOURCES = $(am__cplusplus_libobj_la_SOURCES_DIST) \ - $(am__cudd_libcudd_la_SOURCES_DIST) \ - $(am__dddmp_libdddmp_la_SOURCES_DIST) \ - $(cplusplus_testmulti_SOURCES) $(cplusplus_testobj_SOURCES) \ - $(cudd_testcudd_SOURCES) $(cudd_testextra_SOURCES) \ - $(dddmp_testdddmp_SOURCES) $(mtr_testmtr_SOURCES) \ - $(nanotrav_nanotrav_SOURCES) $(st_testst_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__include_HEADERS_DIST = cudd/cudd.h mtr/mtr.h dddmp/dddmp.h \ - cplusplus/cuddObj.hh -HEADERS = $(include_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ - $(LISP)config.h.in -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -CSCOPE = cscope -AM_RECURSIVE_TARGETS = cscope check recheck -am__tty_colors_dummy = \ - mgn= red= grn= lgn= blu= brg= std=; \ - am__color_tests=no -am__tty_colors = { \ - $(am__tty_colors_dummy); \ - if test "X$(AM_COLOR_TESTS)" = Xno; then \ - am__color_tests=no; \ - elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ - am__color_tests=yes; \ - elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ - am__color_tests=yes; \ - fi; \ - if test $$am__color_tests = yes; then \ - red=''; \ - grn=''; \ - lgn=''; \ - blu=''; \ - mgn=''; \ - brg=''; \ - std=''; \ - fi; \ -} -am__recheck_rx = ^[ ]*:recheck:[ ]* -am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* -am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* -# A command that, given a newline-separated list of test names on the -# standard input, print the name of the tests that are to be re-run -# upon "make recheck". -am__list_recheck_tests = $(AWK) '{ \ - recheck = 1; \ - while ((rc = (getline line < ($$0 ".trs"))) != 0) \ - { \ - if (rc < 0) \ - { \ - if ((getline line2 < ($$0 ".log")) < 0) \ - recheck = 0; \ - break; \ - } \ - else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ - { \ - recheck = 0; \ - break; \ - } \ - else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ - { \ - break; \ - } \ - }; \ - if (recheck) \ - print $$0; \ - close ($$0 ".trs"); \ - close ($$0 ".log"); \ -}' -# A command that, given a newline-separated list of test names on the -# standard input, create the global log from their .trs and .log files. -am__create_global_log = $(AWK) ' \ -function fatal(msg) \ -{ \ - print "fatal: making $@: " msg | "cat >&2"; \ - exit 1; \ -} \ -function rst_section(header) \ -{ \ - print header; \ - len = length(header); \ - for (i = 1; i <= len; i = i + 1) \ - printf "="; \ - printf "\n\n"; \ -} \ -{ \ - copy_in_global_log = 1; \ - global_test_result = "RUN"; \ - while ((rc = (getline line < ($$0 ".trs"))) != 0) \ - { \ - if (rc < 0) \ - fatal("failed to read from " $$0 ".trs"); \ - if (line ~ /$(am__global_test_result_rx)/) \ - { \ - sub("$(am__global_test_result_rx)", "", line); \ - sub("[ ]*$$", "", line); \ - global_test_result = line; \ - } \ - else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ - copy_in_global_log = 0; \ - }; \ - if (copy_in_global_log) \ - { \ - rst_section(global_test_result ": " $$0); \ - while ((rc = (getline line < ($$0 ".log"))) != 0) \ - { \ - if (rc < 0) \ - fatal("failed to read from " $$0 ".log"); \ - print line; \ - }; \ - printf "\n"; \ - }; \ - close ($$0 ".trs"); \ - close ($$0 ".log"); \ -}' -# Restructured Text title. -am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } -# Solaris 10 'make', and several other traditional 'make' implementations, -# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it -# by disabling -e (using the XSI extension "set +e") if it's set. -am__sh_e_setup = case $$- in *e*) set +e;; esac -# Default flags passed to test drivers. -am__common_driver_flags = \ - --color-tests "$$am__color_tests" \ - --enable-hard-errors "$$am__enable_hard_errors" \ - --expect-failure "$$am__expect_failure" -# To be inserted before the command running the test. Creates the -# directory for the log if needed. Stores in $dir the directory -# containing $f, in $tst the test, in $log the log. Executes the -# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and -# passes TESTS_ENVIRONMENT. Set up options for the wrapper that -# will run the test scripts (or their associated LOG_COMPILER, if -# thy have one). -am__check_pre = \ -$(am__sh_e_setup); \ -$(am__vpath_adj_setup) $(am__vpath_adj) \ -$(am__tty_colors); \ -srcdir=$(srcdir); export srcdir; \ -case "$@" in \ - */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ - *) am__odir=.;; \ -esac; \ -test "x$$am__odir" = x"." || test -d "$$am__odir" \ - || $(MKDIR_P) "$$am__odir" || exit $$?; \ -if test -f "./$$f"; then dir=./; \ -elif test -f "$$f"; then dir=; \ -else dir="$(srcdir)/"; fi; \ -tst=$$dir$$f; log='$@'; \ -if test -n '$(DISABLE_HARD_ERRORS)'; then \ - am__enable_hard_errors=no; \ -else \ - am__enable_hard_errors=yes; \ -fi; \ -case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ - am__expect_failure=yes;; \ - *) \ - am__expect_failure=no;; \ -esac; \ -$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) -# A shell command to get the names of the tests scripts with any registered -# extension removed (i.e., equivalently, the names of the test logs, with -# the '.log' extension removed). The result is saved in the shell variable -# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, -# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", -# since that might cause problem with VPATH rewrites for suffix-less tests. -# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. -am__set_TESTS_bases = \ - bases='$(TEST_LOGS)'; \ - bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ - bases=`echo $$bases` -RECHECK_LOGS = $(TEST_LOGS) -TEST_SUITE_LOG = test-suite.log -TEST_EXTENSIONS = @EXEEXT@ .test -am__test_logs1 = $(TESTS:=.log) -am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) -TEST_LOGS = $(am__test_logs2:.test.log=.log) -TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ - $(TEST_LOG_FLAGS) -am__set_b = \ - case '$@' in \ - */*) \ - case '$*' in \ - */*) b='$*';; \ - *) b=`echo '$@' | sed 's/\.log$$//'`; \ - esac;; \ - *) \ - b='$*';; \ - esac -am__DIST_COMMON = $(srcdir)/Doxyfile.in $(srcdir)/Makefile.in \ - $(srcdir)/config.h.in $(top_srcdir)/build-aux/ar-lib \ - $(top_srcdir)/build-aux/compile \ - $(top_srcdir)/build-aux/config.guess \ - $(top_srcdir)/build-aux/config.sub \ - $(top_srcdir)/build-aux/depcomp \ - $(top_srcdir)/build-aux/install-sh \ - $(top_srcdir)/build-aux/ltmain.sh \ - $(top_srcdir)/build-aux/missing \ - $(top_srcdir)/build-aux/tap-driver.sh \ - $(top_srcdir)/cplusplus/Included.am \ - $(top_srcdir)/cudd/Included.am $(top_srcdir)/dddmp/Included.am \ - $(top_srcdir)/dddmp/exp/test1.sh.in \ - $(top_srcdir)/dddmp/exp/test2.sh.in \ - $(top_srcdir)/dddmp/exp/test3.sh.in \ - $(top_srcdir)/dddmp/exp/test4.sh.in \ - $(top_srcdir)/dddmp/exp/test5.sh.in \ - $(top_srcdir)/dddmp/exp/test6.sh.in \ - $(top_srcdir)/dddmp/exp/test7.sh.in \ - $(top_srcdir)/doc/Included.am $(top_srcdir)/doc/cudd.tex.in \ - $(top_srcdir)/epd/Included.am $(top_srcdir)/mtr/Included.am \ - $(top_srcdir)/nanotrav/Included.am \ - $(top_srcdir)/st/Included.am $(top_srcdir)/util/Included.am \ - README build-aux/ar-lib build-aux/compile \ - build-aux/config.guess build-aux/config.sub build-aux/depcomp \ - build-aux/install-sh build-aux/ltmain.sh build-aux/missing -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(PACKAGE)-$(VERSION) -top_distdir = $(distdir) -am__remove_distdir = \ - if test -d "$(distdir)"; then \ - find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ - && rm -rf "$(distdir)" \ - || { sleep 5 && rm -rf "$(distdir)"; }; \ - else :; fi -am__post_remove_distdir = $(am__remove_distdir) -DIST_ARCHIVES = $(distdir).tar.gz -GZIP_ENV = --best -DIST_TARGETS = dist-gzip -distuninstallcheck_listfiles = find . -type f -print -am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ - | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' -distcleancheck_listfiles = find . -type f -print -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXCPP = @CXXCPP@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DOXYGEN = @DOXYGEN@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINDEX = @MAKEINDEX@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PDFLATEX = @PDFLATEX@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -ACLOCAL_AMFLAGS = -I m4 -include_HEADERS = cudd/cudd.h mtr/mtr.h $(am__append_1) \ - $(am__append_2) -check_SCRIPTS = cudd/test_cudd.test st/test_st.test mtr/test_mtr.test \ - dddmp/test_dddmp.test cplusplus/test_obj.test \ - nanotrav/test_ntrv.test -dist_check_DATA = cudd/r7x8.1.mat cudd/r7x8.1.out cudd/extra.out \ - mtr/test.groups mtr/test.out cplusplus/test.out \ - cplusplus/multi.out nanotrav/adj49.blif nanotrav/adj49.out \ - nanotrav/C17.blif nanotrav/C17.out nanotrav/C880.blif \ - nanotrav/C880.out nanotrav/closest.blif nanotrav/closest.out \ - nanotrav/ham01.blif nanotrav/ham01.out nanotrav/mult32a.blif \ - nanotrav/mult32a.out nanotrav/rcn25.blif nanotrav/rcn25.out \ - nanotrav/s27.blif nanotrav/s27.out nanotrav/s27b.blif \ - nanotrav/s27b.out nanotrav/s27c.blif nanotrav/s27c.out \ - nanotrav/s382.blif nanotrav/s382.out nanotrav/s641.blif \ - nanotrav/s641.out nanotrav/miniFirst.blif \ - nanotrav/miniSecond.blif nanotrav/miniFirst.out -EXTRA_DIST = README RELEASE.NOTES LICENSE groups.dox \ - cudd/test_cudd.test.in st/test_st.test.in mtr/test_mtr.test.in \ - dddmp/README.dddmp dddmp/README.testdddmp dddmp/RELEASE_NOTES \ - dddmp/doc dddmp/test_dddmp.test.in dddmp/exp/test1.sh.in \ - dddmp/exp/test2.sh.in dddmp/exp/test3.sh.in \ - dddmp/exp/test4.sh.in dddmp/exp/test5.sh.in \ - dddmp/exp/test6.sh.in dddmp/exp/test7.sh.in dddmp/exp/0.add \ - dddmp/exp/0.bdd dddmp/exp/0or1.bdd dddmp/exp/1.add \ - dddmp/exp/1.bdd dddmp/exp/2and3.bdd dddmp/exp/2.bdd \ - dddmp/exp/3.bdd dddmp/exp/4.bdd dddmp/exp/4.bdd.bis1 \ - dddmp/exp/4.bdd.bis2 dddmp/exp/4.bdd.bis3 dddmp/exp/4.bdd.bis4 \ - dddmp/exp/4bis.bdd dddmp/exp/4.cnf dddmp/exp/4.cnf.bis \ - dddmp/exp/4.max1 dddmp/exp/4.max2 dddmp/exp/4xor5.bdd \ - dddmp/exp/5.bdd dddmp/exp/composeids.txt dddmp/exp/one.bdd \ - dddmp/exp/s27deltaDddmp1.bdd dddmp/exp/s27deltaDddmp1.bdd.bis \ - dddmp/exp/s27deltaDddmp2.bdd dddmp/exp/s27RP1.bdd \ - dddmp/exp/varauxids.ord dddmp/exp/varnames.ord \ - dddmp/exp/zero.bdd cplusplus/test_obj.test.in nanotrav/README \ - nanotrav/nanotrav.1 nanotrav/test_ntrv.test.in doc/phase.pdf -TESTS = $(am__append_3) - -#endif -CLEANFILES = cudd/r7x8.1.tst cudd/extra.tst mtr/test.tst \ - dddmp/exp/test1.sh dddmp/exp/test2.sh dddmp/exp/test3.sh \ - dddmp/exp/test4.sh dddmp/exp/test5.sh dddmp/exp/test6.sh \ - dddmp/exp/test7.sh cplusplus/test.tst cplusplus/multi.tst \ - nanotrav/adj49.tst nanotrav/C17.tst nanotrav/C880.tst \ - nanotrav/closest.tst nanotrav/ham01.tst nanotrav/mult32a.tst \ - nanotrav/rcn25.tst nanotrav/s27.tst nanotrav/s27b.tst \ - nanotrav/s27c.tst nanotrav/s382.tst nanotrav/s641.tst \ - nanotrav/miniFirst.tst $(am__append_8) $(check_SCRIPTS) -noinst_LTLIBRARIES = $(am__append_5) $(am__append_7) -TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ - $(top_srcdir)/build-aux/tap-driver.sh - -do_subst = sed \ - -e 's,[@]EXEEXT[@],$(EXEEXT),g' \ - -e 's,[@]srcdir[@],$(srcdir),g' - -lib_LTLIBRARIES = cudd/libcudd.la -cudd_libcudd_la_SOURCES = cudd/cudd.h cudd/cuddInt.h cudd/cuddAddAbs.c \ - cudd/cuddAddApply.c cudd/cuddAddFind.c cudd/cuddAddInv.c \ - cudd/cuddAddIte.c cudd/cuddAddNeg.c cudd/cuddAddWalsh.c \ - cudd/cuddAndAbs.c cudd/cuddAnneal.c cudd/cuddApa.c \ - cudd/cuddAPI.c cudd/cuddApprox.c cudd/cuddBddAbs.c \ - cudd/cuddBddCorr.c cudd/cuddBddIte.c cudd/cuddBridge.c \ - cudd/cuddCache.c cudd/cuddCheck.c cudd/cuddClip.c \ - cudd/cuddCof.c cudd/cuddCompose.c cudd/cuddDecomp.c \ - cudd/cuddEssent.c cudd/cuddExact.c cudd/cuddExport.c \ - cudd/cuddGenCof.c cudd/cuddGenetic.c cudd/cuddGroup.c \ - cudd/cuddHarwell.c cudd/cuddInit.c cudd/cuddInteract.c \ - cudd/cuddLCache.c cudd/cuddLevelQ.c cudd/cuddLinear.c \ - cudd/cuddLiteral.c cudd/cuddMatMult.c cudd/cuddPriority.c \ - cudd/cuddRead.c cudd/cuddRef.c cudd/cuddReorder.c \ - cudd/cuddSat.c cudd/cuddSign.c cudd/cuddSolve.c \ - cudd/cuddSplit.c cudd/cuddSubsetHB.c cudd/cuddSubsetSP.c \ - cudd/cuddSymmetry.c cudd/cuddTable.c cudd/cuddUtil.c \ - cudd/cuddWindow.c cudd/cuddZddCount.c cudd/cuddZddFuncs.c \ - cudd/cuddZddGroup.c cudd/cuddZddIsop.c cudd/cuddZddLin.c \ - cudd/cuddZddMisc.c cudd/cuddZddPort.c cudd/cuddZddReord.c \ - cudd/cuddZddSetop.c cudd/cuddZddSymm.c cudd/cuddZddUtil.c \ - util/util.h util/cstringstream.h util/cpu_stats.c \ - util/cpu_time.c util/cstringstream.c util/datalimit.c \ - util/pathsearch.c util/pipefork.c util/prtime.c \ - util/safe_mem.c util/strsav.c util/texpand.c util/ucbqsort.c \ - st/st.h st/st.c epd/epd.c epd/epdInt.h epd/epd.h mtr/mtr.h \ - mtr/mtrInt.h mtr/mtrBasic.c mtr/mtrGroup.c $(am__append_4) \ - $(am__append_6) -cudd_libcudd_la_CPPFLAGS = -I$(top_srcdir)/cudd -I$(top_srcdir)/st \ - -I$(top_srcdir)/epd -I$(top_srcdir)/mtr -I$(top_srcdir)/util - -@OBJ_TRUE@cudd_libcudd_la_LIBTOOLFLAGS = --tag=CXX -cudd_libcudd_la_LDFLAGS = -release @PACKAGE_VERSION@ -version-info 0:0:0 \ - -no-undefined - -cudd_testcudd_SOURCES = cudd/testcudd.c -cudd_testcudd_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -cudd_testcudd_LDADD = cudd/libcudd.la -cudd_testextra_SOURCES = cudd/testextra.c -cudd_testextra_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -cudd_testextra_LDADD = cudd/libcudd.la -@CROSS_COMPILING_TRUE@@MINGW64_TRUE@cudd_libcudd_la_LIBADD = -lws2_32 -lpsapi -st_testst_SOURCES = st/testst.c -st_testst_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -st_testst_LDADD = cudd/libcudd.la -mtr_testmtr_SOURCES = mtr/testmtr.c -mtr_testmtr_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -mtr_testmtr_LDADD = cudd/libcudd.la -dddmp_sources = dddmp/dddmp.h dddmp/dddmpInt.h \ - dddmp/dddmpBinary.c dddmp/dddmpConvert.c dddmp/dddmpDbg.c \ - dddmp/dddmpLoad.c dddmp/dddmpLoadCnf.c dddmp/dddmpNodeAdd.c \ - dddmp/dddmpNodeBdd.c dddmp/dddmpNodeCnf.c dddmp/dddmpStoreAdd.c \ - dddmp/dddmpStoreBdd.c dddmp/dddmpStoreCnf.c dddmp/dddmpStoreMisc.c \ - dddmp/dddmpUtil.c - -@DDDMP_FALSE@dddmp_libdddmp_la_SOURCES = $(dddmp_sources) -@DDDMP_FALSE@dddmp_libdddmp_la_CPPFLAGS = -I$(top_srcdir)/util -I$(top_srcdir)/mtr \ -@DDDMP_FALSE@ -I$(top_srcdir)/epd -I$(top_srcdir)/cudd -I$(top_srcdir)/st - -dddmp_testdddmp_SOURCES = dddmp/testdddmp.c -@DDDMP_FALSE@dddmp_testdddmp_CPPFLAGS = $(dddmp_libdddmp_la_CPPFLAGS) -@DDDMP_TRUE@dddmp_testdddmp_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -@DDDMP_FALSE@dddmp_testdddmp_LDADD = dddmp/libdddmp.la cudd/libcudd.la -@DDDMP_TRUE@dddmp_testdddmp_LDADD = cudd/libcudd.la -cplusplus_sources = cplusplus/cuddObj.hh cplusplus/cuddObj.cc -@OBJ_FALSE@cplusplus_libobj_la_SOURCES = $(cplusplus_sources) -@OBJ_FALSE@cplusplus_libobj_la_CPPFLAGS = -I$(top_srcdir)/cudd -I$(top_srcdir)/mtr \ -@OBJ_FALSE@ -I$(top_srcdir)/epd -I$(top_srcdir)/st - -cplusplus_testobj_SOURCES = cplusplus/testobj.cc -@OBJ_FALSE@cplusplus_testobj_CPPFLAGS = $(cplusplus_libobj_la_CPPFLAGS) -@OBJ_TRUE@cplusplus_testobj_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -@OBJ_FALSE@cplusplus_testobj_LDADD = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testobj_LDADD = cudd/libcudd.la -cplusplus_testmulti_SOURCES = cplusplus/testmulti.cc -@OBJ_FALSE@cplusplus_testmulti_CPPFLAGS = $(cplusplus_libobj_la_CPPFLAGS) -@OBJ_TRUE@cplusplus_testmulti_CPPFLAGS = $(cudd_libcudd_la_CPPFLAGS) -@OBJ_FALSE@cplusplus_testmulti_LDADD = cplusplus/libobj.la \ -@OBJ_FALSE@ cudd/libcudd.la -@OBJ_TRUE@cplusplus_testmulti_LDADD = cudd/libcudd.la -@HAVE_PTHREADS_TRUE@cplusplus_testmulti_LDFLAGS = -pthread -nanotrav_nanotrav_SOURCES = nanotrav/bnet.h nanotrav/ntr.h \ - nanotrav/bnet.c nanotrav/chkMterm.c nanotrav/main.c nanotrav/ntrBddTest.c \ - nanotrav/ntr.c nanotrav/ntrHeap.c nanotrav/ntrMflow.c nanotrav/ntrShort.c \ - nanotrav/ntrZddTest.c - -nanotrav_nanotrav_CPPFLAGS = -I$(top_srcdir)/cudd -I$(top_srcdir)/mtr \ - -I$(top_srcdir)/epd -I$(top_srcdir)/st -I$(top_srcdir)/dddmp \ - -I$(top_srcdir)/util - -@DDDMP_FALSE@nanotrav_nanotrav_LDADD = dddmp/libdddmp.la \ -@DDDMP_FALSE@ cudd/libcudd.la -@DDDMP_TRUE@nanotrav_nanotrav_LDADD = cudd/libcudd.la -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .cc .lo .log .o .obj .test .test$(EXEEXT) .trs -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/cudd/Included.am $(top_srcdir)/util/Included.am $(top_srcdir)/st/Included.am $(top_srcdir)/epd/Included.am $(top_srcdir)/mtr/Included.am $(top_srcdir)/dddmp/Included.am $(top_srcdir)/cplusplus/Included.am $(top_srcdir)/nanotrav/Included.am $(top_srcdir)/doc/Included.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; -$(top_srcdir)/cudd/Included.am $(top_srcdir)/util/Included.am $(top_srcdir)/st/Included.am $(top_srcdir)/epd/Included.am $(top_srcdir)/mtr/Included.am $(top_srcdir)/dddmp/Included.am $(top_srcdir)/cplusplus/Included.am $(top_srcdir)/nanotrav/Included.am $(top_srcdir)/doc/Included.am $(am__empty): - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -@HAVE_DOXYGEN_TRUE@Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in -@HAVE_DOXYGEN_TRUE@ cd $(top_builddir) && $(SHELL) ./config.status $@ -@HAVE_PDFLATEX_TRUE@doc/cudd.tex: $(top_builddir)/config.status $(top_srcdir)/doc/cudd.tex.in -@HAVE_PDFLATEX_TRUE@ cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test1.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test1.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test2.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test2.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test3.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test3.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test4.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test4.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test5.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test5.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test6.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test6.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ -dddmp/exp/test7.sh: $(top_builddir)/config.status $(top_srcdir)/dddmp/exp/test7.sh.in - cd $(top_builddir) && $(SHELL) ./config.status $@ - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } -cplusplus/$(am__dirstamp): - @$(MKDIR_P) cplusplus - @: > cplusplus/$(am__dirstamp) -cplusplus/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) cplusplus/$(DEPDIR) - @: > cplusplus/$(DEPDIR)/$(am__dirstamp) -cplusplus/cplusplus_libobj_la-cuddObj.lo: cplusplus/$(am__dirstamp) \ - cplusplus/$(DEPDIR)/$(am__dirstamp) - -cplusplus/libobj.la: $(cplusplus_libobj_la_OBJECTS) $(cplusplus_libobj_la_DEPENDENCIES) $(EXTRA_cplusplus_libobj_la_DEPENDENCIES) cplusplus/$(am__dirstamp) - $(AM_V_CXXLD)$(CXXLINK) $(am_cplusplus_libobj_la_rpath) $(cplusplus_libobj_la_OBJECTS) $(cplusplus_libobj_la_LIBADD) $(LIBS) -cudd/$(am__dirstamp): - @$(MKDIR_P) cudd - @: > cudd/$(am__dirstamp) -cudd/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) cudd/$(DEPDIR) - @: > cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddAbs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddApply.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddFind.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddInv.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddIte.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddNeg.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAddWalsh.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAndAbs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAnneal.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddApa.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddAPI.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddApprox.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBddAbs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBddCorr.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBddIte.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddBridge.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCache.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCheck.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddClip.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCof.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddCompose.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddDecomp.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddEssent.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddExact.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddExport.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddGenCof.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddGenetic.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddGroup.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddHarwell.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddInit.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddInteract.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLCache.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLevelQ.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLinear.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddLiteral.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddMatMult.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddPriority.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddRead.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddRef.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddReorder.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSat.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSign.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSolve.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSplit.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSubsetHB.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSubsetSP.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddSymmetry.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddTable.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddUtil.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddWindow.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddCount.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddFuncs.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddGroup.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddIsop.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddLin.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddMisc.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddPort.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddReord.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddSetop.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddSymm.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -cudd/cudd_libcudd_la-cuddZddUtil.lo: cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) -util/$(am__dirstamp): - @$(MKDIR_P) util - @: > util/$(am__dirstamp) -util/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) util/$(DEPDIR) - @: > util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-cpu_stats.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-cpu_time.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-cstringstream.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-datalimit.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-pathsearch.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-pipefork.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-prtime.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-safe_mem.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-strsav.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-texpand.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -util/cudd_libcudd_la-ucbqsort.lo: util/$(am__dirstamp) \ - util/$(DEPDIR)/$(am__dirstamp) -st/$(am__dirstamp): - @$(MKDIR_P) st - @: > st/$(am__dirstamp) -st/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) st/$(DEPDIR) - @: > st/$(DEPDIR)/$(am__dirstamp) -st/cudd_libcudd_la-st.lo: st/$(am__dirstamp) \ - st/$(DEPDIR)/$(am__dirstamp) -epd/$(am__dirstamp): - @$(MKDIR_P) epd - @: > epd/$(am__dirstamp) -epd/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) epd/$(DEPDIR) - @: > epd/$(DEPDIR)/$(am__dirstamp) -epd/cudd_libcudd_la-epd.lo: epd/$(am__dirstamp) \ - epd/$(DEPDIR)/$(am__dirstamp) -mtr/$(am__dirstamp): - @$(MKDIR_P) mtr - @: > mtr/$(am__dirstamp) -mtr/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) mtr/$(DEPDIR) - @: > mtr/$(DEPDIR)/$(am__dirstamp) -mtr/cudd_libcudd_la-mtrBasic.lo: mtr/$(am__dirstamp) \ - mtr/$(DEPDIR)/$(am__dirstamp) -mtr/cudd_libcudd_la-mtrGroup.lo: mtr/$(am__dirstamp) \ - mtr/$(DEPDIR)/$(am__dirstamp) -dddmp/$(am__dirstamp): - @$(MKDIR_P) dddmp - @: > dddmp/$(am__dirstamp) -dddmp/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) dddmp/$(DEPDIR) - @: > dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpBinary.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpConvert.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpDbg.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpLoad.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpLoadCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpNodeAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpNodeBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpNodeCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpStoreMisc.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/cudd_libcudd_la-dddmpUtil.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -cplusplus/cudd_libcudd_la-cuddObj.lo: cplusplus/$(am__dirstamp) \ - cplusplus/$(DEPDIR)/$(am__dirstamp) - -cudd/libcudd.la: $(cudd_libcudd_la_OBJECTS) $(cudd_libcudd_la_DEPENDENCIES) $(EXTRA_cudd_libcudd_la_DEPENDENCIES) cudd/$(am__dirstamp) - $(AM_V_CXXLD)$(cudd_libcudd_la_LINK) -rpath $(libdir) $(cudd_libcudd_la_OBJECTS) $(cudd_libcudd_la_LIBADD) $(LIBS) -dddmp/dddmp_libdddmp_la-dddmpBinary.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpConvert.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpDbg.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpLoad.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) -dddmp/dddmp_libdddmp_la-dddmpUtil.lo: dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) - -dddmp/libdddmp.la: $(dddmp_libdddmp_la_OBJECTS) $(dddmp_libdddmp_la_DEPENDENCIES) $(EXTRA_dddmp_libdddmp_la_DEPENDENCIES) dddmp/$(am__dirstamp) - $(AM_V_CCLD)$(LINK) $(am_dddmp_libdddmp_la_rpath) $(dddmp_libdddmp_la_OBJECTS) $(dddmp_libdddmp_la_LIBADD) $(LIBS) - -clean-checkPROGRAMS: - @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -cplusplus/cplusplus_testmulti-testmulti.$(OBJEXT): \ - cplusplus/$(am__dirstamp) cplusplus/$(DEPDIR)/$(am__dirstamp) - -cplusplus/testmulti$(EXEEXT): $(cplusplus_testmulti_OBJECTS) $(cplusplus_testmulti_DEPENDENCIES) $(EXTRA_cplusplus_testmulti_DEPENDENCIES) cplusplus/$(am__dirstamp) - @rm -f cplusplus/testmulti$(EXEEXT) - $(AM_V_CXXLD)$(cplusplus_testmulti_LINK) $(cplusplus_testmulti_OBJECTS) $(cplusplus_testmulti_LDADD) $(LIBS) -cplusplus/cplusplus_testobj-testobj.$(OBJEXT): \ - cplusplus/$(am__dirstamp) cplusplus/$(DEPDIR)/$(am__dirstamp) - -cplusplus/testobj$(EXEEXT): $(cplusplus_testobj_OBJECTS) $(cplusplus_testobj_DEPENDENCIES) $(EXTRA_cplusplus_testobj_DEPENDENCIES) cplusplus/$(am__dirstamp) - @rm -f cplusplus/testobj$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(cplusplus_testobj_OBJECTS) $(cplusplus_testobj_LDADD) $(LIBS) -cudd/cudd_testcudd-testcudd.$(OBJEXT): cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) - -cudd/testcudd$(EXEEXT): $(cudd_testcudd_OBJECTS) $(cudd_testcudd_DEPENDENCIES) $(EXTRA_cudd_testcudd_DEPENDENCIES) cudd/$(am__dirstamp) - @rm -f cudd/testcudd$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(cudd_testcudd_OBJECTS) $(cudd_testcudd_LDADD) $(LIBS) -cudd/cudd_testextra-testextra.$(OBJEXT): cudd/$(am__dirstamp) \ - cudd/$(DEPDIR)/$(am__dirstamp) - -cudd/testextra$(EXEEXT): $(cudd_testextra_OBJECTS) $(cudd_testextra_DEPENDENCIES) $(EXTRA_cudd_testextra_DEPENDENCIES) cudd/$(am__dirstamp) - @rm -f cudd/testextra$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(cudd_testextra_OBJECTS) $(cudd_testextra_LDADD) $(LIBS) -dddmp/dddmp_testdddmp-testdddmp.$(OBJEXT): dddmp/$(am__dirstamp) \ - dddmp/$(DEPDIR)/$(am__dirstamp) - -dddmp/testdddmp$(EXEEXT): $(dddmp_testdddmp_OBJECTS) $(dddmp_testdddmp_DEPENDENCIES) $(EXTRA_dddmp_testdddmp_DEPENDENCIES) dddmp/$(am__dirstamp) - @rm -f dddmp/testdddmp$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(dddmp_testdddmp_OBJECTS) $(dddmp_testdddmp_LDADD) $(LIBS) -mtr/mtr_testmtr-testmtr.$(OBJEXT): mtr/$(am__dirstamp) \ - mtr/$(DEPDIR)/$(am__dirstamp) - -mtr/testmtr$(EXEEXT): $(mtr_testmtr_OBJECTS) $(mtr_testmtr_DEPENDENCIES) $(EXTRA_mtr_testmtr_DEPENDENCIES) mtr/$(am__dirstamp) - @rm -f mtr/testmtr$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(mtr_testmtr_OBJECTS) $(mtr_testmtr_LDADD) $(LIBS) -nanotrav/$(am__dirstamp): - @$(MKDIR_P) nanotrav - @: > nanotrav/$(am__dirstamp) -nanotrav/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) nanotrav/$(DEPDIR) - @: > nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-bnet.$(OBJEXT): nanotrav/$(am__dirstamp) \ - nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-chkMterm.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-main.$(OBJEXT): nanotrav/$(am__dirstamp) \ - nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrBddTest.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntr.$(OBJEXT): nanotrav/$(am__dirstamp) \ - nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrHeap.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrMflow.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrShort.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) -nanotrav/nanotrav_nanotrav-ntrZddTest.$(OBJEXT): \ - nanotrav/$(am__dirstamp) nanotrav/$(DEPDIR)/$(am__dirstamp) - -nanotrav/nanotrav$(EXEEXT): $(nanotrav_nanotrav_OBJECTS) $(nanotrav_nanotrav_DEPENDENCIES) $(EXTRA_nanotrav_nanotrav_DEPENDENCIES) nanotrav/$(am__dirstamp) - @rm -f nanotrav/nanotrav$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(nanotrav_nanotrav_OBJECTS) $(nanotrav_nanotrav_LDADD) $(LIBS) -st/st_testst-testst.$(OBJEXT): st/$(am__dirstamp) \ - st/$(DEPDIR)/$(am__dirstamp) - -st/testst$(EXEEXT): $(st_testst_OBJECTS) $(st_testst_DEPENDENCIES) $(EXTRA_st_testst_DEPENDENCIES) st/$(am__dirstamp) - @rm -f st/testst$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(st_testst_OBJECTS) $(st_testst_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -rm -f cplusplus/*.$(OBJEXT) - -rm -f cplusplus/*.lo - -rm -f cudd/*.$(OBJEXT) - -rm -f cudd/*.lo - -rm -f dddmp/*.$(OBJEXT) - -rm -f dddmp/*.lo - -rm -f epd/*.$(OBJEXT) - -rm -f epd/*.lo - -rm -f mtr/*.$(OBJEXT) - -rm -f mtr/*.lo - -rm -f nanotrav/*.$(OBJEXT) - -rm -f st/*.$(OBJEXT) - -rm -f st/*.lo - -rm -f util/*.$(OBJEXT) - -rm -f util/*.lo - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_testcudd-testcudd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@cudd/$(DEPDIR)/cudd_testextra-testextra.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@epd/$(DEPDIR)/cudd_libcudd_la-epd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@mtr/$(DEPDIR)/mtr_testmtr-testmtr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@st/$(DEPDIR)/cudd_libcudd_la-st.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@st/$(DEPDIR)/st_testst-testst.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-datalimit.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-pipefork.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-prtime.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-strsav.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-texpand.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -cudd/cudd_libcudd_la-cuddAddAbs.lo: cudd/cuddAddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddAbs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Tpo -c -o cudd/cudd_libcudd_la-cuddAddAbs.lo `test -f 'cudd/cuddAddAbs.c' || echo '$(srcdir)/'`cudd/cuddAddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddAbs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddAbs.c' object='cudd/cudd_libcudd_la-cuddAddAbs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddAbs.lo `test -f 'cudd/cuddAddAbs.c' || echo '$(srcdir)/'`cudd/cuddAddAbs.c - -cudd/cudd_libcudd_la-cuddAddApply.lo: cudd/cuddAddApply.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddApply.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Tpo -c -o cudd/cudd_libcudd_la-cuddAddApply.lo `test -f 'cudd/cuddAddApply.c' || echo '$(srcdir)/'`cudd/cuddAddApply.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddApply.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddApply.c' object='cudd/cudd_libcudd_la-cuddAddApply.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddApply.lo `test -f 'cudd/cuddAddApply.c' || echo '$(srcdir)/'`cudd/cuddAddApply.c - -cudd/cudd_libcudd_la-cuddAddFind.lo: cudd/cuddAddFind.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddFind.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Tpo -c -o cudd/cudd_libcudd_la-cuddAddFind.lo `test -f 'cudd/cuddAddFind.c' || echo '$(srcdir)/'`cudd/cuddAddFind.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddFind.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddFind.c' object='cudd/cudd_libcudd_la-cuddAddFind.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddFind.lo `test -f 'cudd/cuddAddFind.c' || echo '$(srcdir)/'`cudd/cuddAddFind.c - -cudd/cudd_libcudd_la-cuddAddInv.lo: cudd/cuddAddInv.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddInv.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Tpo -c -o cudd/cudd_libcudd_la-cuddAddInv.lo `test -f 'cudd/cuddAddInv.c' || echo '$(srcdir)/'`cudd/cuddAddInv.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddInv.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddInv.c' object='cudd/cudd_libcudd_la-cuddAddInv.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddInv.lo `test -f 'cudd/cuddAddInv.c' || echo '$(srcdir)/'`cudd/cuddAddInv.c - -cudd/cudd_libcudd_la-cuddAddIte.lo: cudd/cuddAddIte.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddIte.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Tpo -c -o cudd/cudd_libcudd_la-cuddAddIte.lo `test -f 'cudd/cuddAddIte.c' || echo '$(srcdir)/'`cudd/cuddAddIte.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddIte.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddIte.c' object='cudd/cudd_libcudd_la-cuddAddIte.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddIte.lo `test -f 'cudd/cuddAddIte.c' || echo '$(srcdir)/'`cudd/cuddAddIte.c - -cudd/cudd_libcudd_la-cuddAddNeg.lo: cudd/cuddAddNeg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddNeg.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Tpo -c -o cudd/cudd_libcudd_la-cuddAddNeg.lo `test -f 'cudd/cuddAddNeg.c' || echo '$(srcdir)/'`cudd/cuddAddNeg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddNeg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddNeg.c' object='cudd/cudd_libcudd_la-cuddAddNeg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddNeg.lo `test -f 'cudd/cuddAddNeg.c' || echo '$(srcdir)/'`cudd/cuddAddNeg.c - -cudd/cudd_libcudd_la-cuddAddWalsh.lo: cudd/cuddAddWalsh.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAddWalsh.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Tpo -c -o cudd/cudd_libcudd_la-cuddAddWalsh.lo `test -f 'cudd/cuddAddWalsh.c' || echo '$(srcdir)/'`cudd/cuddAddWalsh.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAddWalsh.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAddWalsh.c' object='cudd/cudd_libcudd_la-cuddAddWalsh.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAddWalsh.lo `test -f 'cudd/cuddAddWalsh.c' || echo '$(srcdir)/'`cudd/cuddAddWalsh.c - -cudd/cudd_libcudd_la-cuddAndAbs.lo: cudd/cuddAndAbs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAndAbs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Tpo -c -o cudd/cudd_libcudd_la-cuddAndAbs.lo `test -f 'cudd/cuddAndAbs.c' || echo '$(srcdir)/'`cudd/cuddAndAbs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAndAbs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAndAbs.c' object='cudd/cudd_libcudd_la-cuddAndAbs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAndAbs.lo `test -f 'cudd/cuddAndAbs.c' || echo '$(srcdir)/'`cudd/cuddAndAbs.c - -cudd/cudd_libcudd_la-cuddAnneal.lo: cudd/cuddAnneal.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAnneal.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Tpo -c -o cudd/cudd_libcudd_la-cuddAnneal.lo `test -f 'cudd/cuddAnneal.c' || echo '$(srcdir)/'`cudd/cuddAnneal.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAnneal.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAnneal.c' object='cudd/cudd_libcudd_la-cuddAnneal.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAnneal.lo `test -f 'cudd/cuddAnneal.c' || echo '$(srcdir)/'`cudd/cuddAnneal.c - -cudd/cudd_libcudd_la-cuddApa.lo: cudd/cuddApa.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddApa.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Tpo -c -o cudd/cudd_libcudd_la-cuddApa.lo `test -f 'cudd/cuddApa.c' || echo '$(srcdir)/'`cudd/cuddApa.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddApa.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddApa.c' object='cudd/cudd_libcudd_la-cuddApa.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddApa.lo `test -f 'cudd/cuddApa.c' || echo '$(srcdir)/'`cudd/cuddApa.c - -cudd/cudd_libcudd_la-cuddAPI.lo: cudd/cuddAPI.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddAPI.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Tpo -c -o cudd/cudd_libcudd_la-cuddAPI.lo `test -f 'cudd/cuddAPI.c' || echo '$(srcdir)/'`cudd/cuddAPI.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddAPI.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddAPI.c' object='cudd/cudd_libcudd_la-cuddAPI.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddAPI.lo `test -f 'cudd/cuddAPI.c' || echo '$(srcdir)/'`cudd/cuddAPI.c - -cudd/cudd_libcudd_la-cuddApprox.lo: cudd/cuddApprox.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddApprox.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Tpo -c -o cudd/cudd_libcudd_la-cuddApprox.lo `test -f 'cudd/cuddApprox.c' || echo '$(srcdir)/'`cudd/cuddApprox.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddApprox.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddApprox.c' object='cudd/cudd_libcudd_la-cuddApprox.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddApprox.lo `test -f 'cudd/cuddApprox.c' || echo '$(srcdir)/'`cudd/cuddApprox.c - -cudd/cudd_libcudd_la-cuddBddAbs.lo: cudd/cuddBddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBddAbs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Tpo -c -o cudd/cudd_libcudd_la-cuddBddAbs.lo `test -f 'cudd/cuddBddAbs.c' || echo '$(srcdir)/'`cudd/cuddBddAbs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddAbs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBddAbs.c' object='cudd/cudd_libcudd_la-cuddBddAbs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBddAbs.lo `test -f 'cudd/cuddBddAbs.c' || echo '$(srcdir)/'`cudd/cuddBddAbs.c - -cudd/cudd_libcudd_la-cuddBddCorr.lo: cudd/cuddBddCorr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBddCorr.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Tpo -c -o cudd/cudd_libcudd_la-cuddBddCorr.lo `test -f 'cudd/cuddBddCorr.c' || echo '$(srcdir)/'`cudd/cuddBddCorr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddCorr.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBddCorr.c' object='cudd/cudd_libcudd_la-cuddBddCorr.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBddCorr.lo `test -f 'cudd/cuddBddCorr.c' || echo '$(srcdir)/'`cudd/cuddBddCorr.c - -cudd/cudd_libcudd_la-cuddBddIte.lo: cudd/cuddBddIte.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBddIte.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Tpo -c -o cudd/cudd_libcudd_la-cuddBddIte.lo `test -f 'cudd/cuddBddIte.c' || echo '$(srcdir)/'`cudd/cuddBddIte.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBddIte.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBddIte.c' object='cudd/cudd_libcudd_la-cuddBddIte.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBddIte.lo `test -f 'cudd/cuddBddIte.c' || echo '$(srcdir)/'`cudd/cuddBddIte.c - -cudd/cudd_libcudd_la-cuddBridge.lo: cudd/cuddBridge.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddBridge.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Tpo -c -o cudd/cudd_libcudd_la-cuddBridge.lo `test -f 'cudd/cuddBridge.c' || echo '$(srcdir)/'`cudd/cuddBridge.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddBridge.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddBridge.c' object='cudd/cudd_libcudd_la-cuddBridge.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddBridge.lo `test -f 'cudd/cuddBridge.c' || echo '$(srcdir)/'`cudd/cuddBridge.c - -cudd/cudd_libcudd_la-cuddCache.lo: cudd/cuddCache.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCache.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Tpo -c -o cudd/cudd_libcudd_la-cuddCache.lo `test -f 'cudd/cuddCache.c' || echo '$(srcdir)/'`cudd/cuddCache.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCache.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCache.c' object='cudd/cudd_libcudd_la-cuddCache.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCache.lo `test -f 'cudd/cuddCache.c' || echo '$(srcdir)/'`cudd/cuddCache.c - -cudd/cudd_libcudd_la-cuddCheck.lo: cudd/cuddCheck.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCheck.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Tpo -c -o cudd/cudd_libcudd_la-cuddCheck.lo `test -f 'cudd/cuddCheck.c' || echo '$(srcdir)/'`cudd/cuddCheck.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCheck.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCheck.c' object='cudd/cudd_libcudd_la-cuddCheck.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCheck.lo `test -f 'cudd/cuddCheck.c' || echo '$(srcdir)/'`cudd/cuddCheck.c - -cudd/cudd_libcudd_la-cuddClip.lo: cudd/cuddClip.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddClip.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Tpo -c -o cudd/cudd_libcudd_la-cuddClip.lo `test -f 'cudd/cuddClip.c' || echo '$(srcdir)/'`cudd/cuddClip.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddClip.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddClip.c' object='cudd/cudd_libcudd_la-cuddClip.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddClip.lo `test -f 'cudd/cuddClip.c' || echo '$(srcdir)/'`cudd/cuddClip.c - -cudd/cudd_libcudd_la-cuddCof.lo: cudd/cuddCof.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCof.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Tpo -c -o cudd/cudd_libcudd_la-cuddCof.lo `test -f 'cudd/cuddCof.c' || echo '$(srcdir)/'`cudd/cuddCof.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCof.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCof.c' object='cudd/cudd_libcudd_la-cuddCof.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCof.lo `test -f 'cudd/cuddCof.c' || echo '$(srcdir)/'`cudd/cuddCof.c - -cudd/cudd_libcudd_la-cuddCompose.lo: cudd/cuddCompose.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddCompose.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Tpo -c -o cudd/cudd_libcudd_la-cuddCompose.lo `test -f 'cudd/cuddCompose.c' || echo '$(srcdir)/'`cudd/cuddCompose.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddCompose.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddCompose.c' object='cudd/cudd_libcudd_la-cuddCompose.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddCompose.lo `test -f 'cudd/cuddCompose.c' || echo '$(srcdir)/'`cudd/cuddCompose.c - -cudd/cudd_libcudd_la-cuddDecomp.lo: cudd/cuddDecomp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddDecomp.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Tpo -c -o cudd/cudd_libcudd_la-cuddDecomp.lo `test -f 'cudd/cuddDecomp.c' || echo '$(srcdir)/'`cudd/cuddDecomp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddDecomp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddDecomp.c' object='cudd/cudd_libcudd_la-cuddDecomp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddDecomp.lo `test -f 'cudd/cuddDecomp.c' || echo '$(srcdir)/'`cudd/cuddDecomp.c - -cudd/cudd_libcudd_la-cuddEssent.lo: cudd/cuddEssent.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddEssent.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Tpo -c -o cudd/cudd_libcudd_la-cuddEssent.lo `test -f 'cudd/cuddEssent.c' || echo '$(srcdir)/'`cudd/cuddEssent.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddEssent.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddEssent.c' object='cudd/cudd_libcudd_la-cuddEssent.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddEssent.lo `test -f 'cudd/cuddEssent.c' || echo '$(srcdir)/'`cudd/cuddEssent.c - -cudd/cudd_libcudd_la-cuddExact.lo: cudd/cuddExact.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddExact.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Tpo -c -o cudd/cudd_libcudd_la-cuddExact.lo `test -f 'cudd/cuddExact.c' || echo '$(srcdir)/'`cudd/cuddExact.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddExact.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddExact.c' object='cudd/cudd_libcudd_la-cuddExact.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddExact.lo `test -f 'cudd/cuddExact.c' || echo '$(srcdir)/'`cudd/cuddExact.c - -cudd/cudd_libcudd_la-cuddExport.lo: cudd/cuddExport.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddExport.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Tpo -c -o cudd/cudd_libcudd_la-cuddExport.lo `test -f 'cudd/cuddExport.c' || echo '$(srcdir)/'`cudd/cuddExport.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddExport.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddExport.c' object='cudd/cudd_libcudd_la-cuddExport.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddExport.lo `test -f 'cudd/cuddExport.c' || echo '$(srcdir)/'`cudd/cuddExport.c - -cudd/cudd_libcudd_la-cuddGenCof.lo: cudd/cuddGenCof.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddGenCof.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Tpo -c -o cudd/cudd_libcudd_la-cuddGenCof.lo `test -f 'cudd/cuddGenCof.c' || echo '$(srcdir)/'`cudd/cuddGenCof.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenCof.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddGenCof.c' object='cudd/cudd_libcudd_la-cuddGenCof.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddGenCof.lo `test -f 'cudd/cuddGenCof.c' || echo '$(srcdir)/'`cudd/cuddGenCof.c - -cudd/cudd_libcudd_la-cuddGenetic.lo: cudd/cuddGenetic.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddGenetic.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Tpo -c -o cudd/cudd_libcudd_la-cuddGenetic.lo `test -f 'cudd/cuddGenetic.c' || echo '$(srcdir)/'`cudd/cuddGenetic.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddGenetic.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddGenetic.c' object='cudd/cudd_libcudd_la-cuddGenetic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddGenetic.lo `test -f 'cudd/cuddGenetic.c' || echo '$(srcdir)/'`cudd/cuddGenetic.c - -cudd/cudd_libcudd_la-cuddGroup.lo: cudd/cuddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddGroup.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Tpo -c -o cudd/cudd_libcudd_la-cuddGroup.lo `test -f 'cudd/cuddGroup.c' || echo '$(srcdir)/'`cudd/cuddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddGroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddGroup.c' object='cudd/cudd_libcudd_la-cuddGroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddGroup.lo `test -f 'cudd/cuddGroup.c' || echo '$(srcdir)/'`cudd/cuddGroup.c - -cudd/cudd_libcudd_la-cuddHarwell.lo: cudd/cuddHarwell.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddHarwell.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Tpo -c -o cudd/cudd_libcudd_la-cuddHarwell.lo `test -f 'cudd/cuddHarwell.c' || echo '$(srcdir)/'`cudd/cuddHarwell.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddHarwell.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddHarwell.c' object='cudd/cudd_libcudd_la-cuddHarwell.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddHarwell.lo `test -f 'cudd/cuddHarwell.c' || echo '$(srcdir)/'`cudd/cuddHarwell.c - -cudd/cudd_libcudd_la-cuddInit.lo: cudd/cuddInit.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddInit.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Tpo -c -o cudd/cudd_libcudd_la-cuddInit.lo `test -f 'cudd/cuddInit.c' || echo '$(srcdir)/'`cudd/cuddInit.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddInit.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddInit.c' object='cudd/cudd_libcudd_la-cuddInit.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddInit.lo `test -f 'cudd/cuddInit.c' || echo '$(srcdir)/'`cudd/cuddInit.c - -cudd/cudd_libcudd_la-cuddInteract.lo: cudd/cuddInteract.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddInteract.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Tpo -c -o cudd/cudd_libcudd_la-cuddInteract.lo `test -f 'cudd/cuddInteract.c' || echo '$(srcdir)/'`cudd/cuddInteract.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddInteract.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddInteract.c' object='cudd/cudd_libcudd_la-cuddInteract.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddInteract.lo `test -f 'cudd/cuddInteract.c' || echo '$(srcdir)/'`cudd/cuddInteract.c - -cudd/cudd_libcudd_la-cuddLCache.lo: cudd/cuddLCache.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLCache.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Tpo -c -o cudd/cudd_libcudd_la-cuddLCache.lo `test -f 'cudd/cuddLCache.c' || echo '$(srcdir)/'`cudd/cuddLCache.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLCache.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLCache.c' object='cudd/cudd_libcudd_la-cuddLCache.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLCache.lo `test -f 'cudd/cuddLCache.c' || echo '$(srcdir)/'`cudd/cuddLCache.c - -cudd/cudd_libcudd_la-cuddLevelQ.lo: cudd/cuddLevelQ.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLevelQ.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Tpo -c -o cudd/cudd_libcudd_la-cuddLevelQ.lo `test -f 'cudd/cuddLevelQ.c' || echo '$(srcdir)/'`cudd/cuddLevelQ.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLevelQ.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLevelQ.c' object='cudd/cudd_libcudd_la-cuddLevelQ.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLevelQ.lo `test -f 'cudd/cuddLevelQ.c' || echo '$(srcdir)/'`cudd/cuddLevelQ.c - -cudd/cudd_libcudd_la-cuddLinear.lo: cudd/cuddLinear.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLinear.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Tpo -c -o cudd/cudd_libcudd_la-cuddLinear.lo `test -f 'cudd/cuddLinear.c' || echo '$(srcdir)/'`cudd/cuddLinear.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLinear.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLinear.c' object='cudd/cudd_libcudd_la-cuddLinear.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLinear.lo `test -f 'cudd/cuddLinear.c' || echo '$(srcdir)/'`cudd/cuddLinear.c - -cudd/cudd_libcudd_la-cuddLiteral.lo: cudd/cuddLiteral.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddLiteral.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Tpo -c -o cudd/cudd_libcudd_la-cuddLiteral.lo `test -f 'cudd/cuddLiteral.c' || echo '$(srcdir)/'`cudd/cuddLiteral.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddLiteral.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddLiteral.c' object='cudd/cudd_libcudd_la-cuddLiteral.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddLiteral.lo `test -f 'cudd/cuddLiteral.c' || echo '$(srcdir)/'`cudd/cuddLiteral.c - -cudd/cudd_libcudd_la-cuddMatMult.lo: cudd/cuddMatMult.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddMatMult.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Tpo -c -o cudd/cudd_libcudd_la-cuddMatMult.lo `test -f 'cudd/cuddMatMult.c' || echo '$(srcdir)/'`cudd/cuddMatMult.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddMatMult.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddMatMult.c' object='cudd/cudd_libcudd_la-cuddMatMult.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddMatMult.lo `test -f 'cudd/cuddMatMult.c' || echo '$(srcdir)/'`cudd/cuddMatMult.c - -cudd/cudd_libcudd_la-cuddPriority.lo: cudd/cuddPriority.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddPriority.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Tpo -c -o cudd/cudd_libcudd_la-cuddPriority.lo `test -f 'cudd/cuddPriority.c' || echo '$(srcdir)/'`cudd/cuddPriority.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddPriority.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddPriority.c' object='cudd/cudd_libcudd_la-cuddPriority.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddPriority.lo `test -f 'cudd/cuddPriority.c' || echo '$(srcdir)/'`cudd/cuddPriority.c - -cudd/cudd_libcudd_la-cuddRead.lo: cudd/cuddRead.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddRead.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Tpo -c -o cudd/cudd_libcudd_la-cuddRead.lo `test -f 'cudd/cuddRead.c' || echo '$(srcdir)/'`cudd/cuddRead.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddRead.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddRead.c' object='cudd/cudd_libcudd_la-cuddRead.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddRead.lo `test -f 'cudd/cuddRead.c' || echo '$(srcdir)/'`cudd/cuddRead.c - -cudd/cudd_libcudd_la-cuddRef.lo: cudd/cuddRef.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddRef.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Tpo -c -o cudd/cudd_libcudd_la-cuddRef.lo `test -f 'cudd/cuddRef.c' || echo '$(srcdir)/'`cudd/cuddRef.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddRef.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddRef.c' object='cudd/cudd_libcudd_la-cuddRef.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddRef.lo `test -f 'cudd/cuddRef.c' || echo '$(srcdir)/'`cudd/cuddRef.c - -cudd/cudd_libcudd_la-cuddReorder.lo: cudd/cuddReorder.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddReorder.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Tpo -c -o cudd/cudd_libcudd_la-cuddReorder.lo `test -f 'cudd/cuddReorder.c' || echo '$(srcdir)/'`cudd/cuddReorder.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddReorder.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddReorder.c' object='cudd/cudd_libcudd_la-cuddReorder.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddReorder.lo `test -f 'cudd/cuddReorder.c' || echo '$(srcdir)/'`cudd/cuddReorder.c - -cudd/cudd_libcudd_la-cuddSat.lo: cudd/cuddSat.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSat.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Tpo -c -o cudd/cudd_libcudd_la-cuddSat.lo `test -f 'cudd/cuddSat.c' || echo '$(srcdir)/'`cudd/cuddSat.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSat.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSat.c' object='cudd/cudd_libcudd_la-cuddSat.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSat.lo `test -f 'cudd/cuddSat.c' || echo '$(srcdir)/'`cudd/cuddSat.c - -cudd/cudd_libcudd_la-cuddSign.lo: cudd/cuddSign.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSign.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Tpo -c -o cudd/cudd_libcudd_la-cuddSign.lo `test -f 'cudd/cuddSign.c' || echo '$(srcdir)/'`cudd/cuddSign.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSign.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSign.c' object='cudd/cudd_libcudd_la-cuddSign.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSign.lo `test -f 'cudd/cuddSign.c' || echo '$(srcdir)/'`cudd/cuddSign.c - -cudd/cudd_libcudd_la-cuddSolve.lo: cudd/cuddSolve.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSolve.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Tpo -c -o cudd/cudd_libcudd_la-cuddSolve.lo `test -f 'cudd/cuddSolve.c' || echo '$(srcdir)/'`cudd/cuddSolve.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSolve.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSolve.c' object='cudd/cudd_libcudd_la-cuddSolve.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSolve.lo `test -f 'cudd/cuddSolve.c' || echo '$(srcdir)/'`cudd/cuddSolve.c - -cudd/cudd_libcudd_la-cuddSplit.lo: cudd/cuddSplit.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSplit.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Tpo -c -o cudd/cudd_libcudd_la-cuddSplit.lo `test -f 'cudd/cuddSplit.c' || echo '$(srcdir)/'`cudd/cuddSplit.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSplit.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSplit.c' object='cudd/cudd_libcudd_la-cuddSplit.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSplit.lo `test -f 'cudd/cuddSplit.c' || echo '$(srcdir)/'`cudd/cuddSplit.c - -cudd/cudd_libcudd_la-cuddSubsetHB.lo: cudd/cuddSubsetHB.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSubsetHB.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Tpo -c -o cudd/cudd_libcudd_la-cuddSubsetHB.lo `test -f 'cudd/cuddSubsetHB.c' || echo '$(srcdir)/'`cudd/cuddSubsetHB.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetHB.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSubsetHB.c' object='cudd/cudd_libcudd_la-cuddSubsetHB.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSubsetHB.lo `test -f 'cudd/cuddSubsetHB.c' || echo '$(srcdir)/'`cudd/cuddSubsetHB.c - -cudd/cudd_libcudd_la-cuddSubsetSP.lo: cudd/cuddSubsetSP.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSubsetSP.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Tpo -c -o cudd/cudd_libcudd_la-cuddSubsetSP.lo `test -f 'cudd/cuddSubsetSP.c' || echo '$(srcdir)/'`cudd/cuddSubsetSP.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSubsetSP.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSubsetSP.c' object='cudd/cudd_libcudd_la-cuddSubsetSP.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSubsetSP.lo `test -f 'cudd/cuddSubsetSP.c' || echo '$(srcdir)/'`cudd/cuddSubsetSP.c - -cudd/cudd_libcudd_la-cuddSymmetry.lo: cudd/cuddSymmetry.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddSymmetry.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Tpo -c -o cudd/cudd_libcudd_la-cuddSymmetry.lo `test -f 'cudd/cuddSymmetry.c' || echo '$(srcdir)/'`cudd/cuddSymmetry.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddSymmetry.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddSymmetry.c' object='cudd/cudd_libcudd_la-cuddSymmetry.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddSymmetry.lo `test -f 'cudd/cuddSymmetry.c' || echo '$(srcdir)/'`cudd/cuddSymmetry.c - -cudd/cudd_libcudd_la-cuddTable.lo: cudd/cuddTable.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddTable.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Tpo -c -o cudd/cudd_libcudd_la-cuddTable.lo `test -f 'cudd/cuddTable.c' || echo '$(srcdir)/'`cudd/cuddTable.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddTable.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddTable.c' object='cudd/cudd_libcudd_la-cuddTable.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddTable.lo `test -f 'cudd/cuddTable.c' || echo '$(srcdir)/'`cudd/cuddTable.c - -cudd/cudd_libcudd_la-cuddUtil.lo: cudd/cuddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddUtil.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Tpo -c -o cudd/cudd_libcudd_la-cuddUtil.lo `test -f 'cudd/cuddUtil.c' || echo '$(srcdir)/'`cudd/cuddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddUtil.c' object='cudd/cudd_libcudd_la-cuddUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddUtil.lo `test -f 'cudd/cuddUtil.c' || echo '$(srcdir)/'`cudd/cuddUtil.c - -cudd/cudd_libcudd_la-cuddWindow.lo: cudd/cuddWindow.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddWindow.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Tpo -c -o cudd/cudd_libcudd_la-cuddWindow.lo `test -f 'cudd/cuddWindow.c' || echo '$(srcdir)/'`cudd/cuddWindow.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddWindow.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddWindow.c' object='cudd/cudd_libcudd_la-cuddWindow.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddWindow.lo `test -f 'cudd/cuddWindow.c' || echo '$(srcdir)/'`cudd/cuddWindow.c - -cudd/cudd_libcudd_la-cuddZddCount.lo: cudd/cuddZddCount.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddCount.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Tpo -c -o cudd/cudd_libcudd_la-cuddZddCount.lo `test -f 'cudd/cuddZddCount.c' || echo '$(srcdir)/'`cudd/cuddZddCount.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddCount.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddCount.c' object='cudd/cudd_libcudd_la-cuddZddCount.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddCount.lo `test -f 'cudd/cuddZddCount.c' || echo '$(srcdir)/'`cudd/cuddZddCount.c - -cudd/cudd_libcudd_la-cuddZddFuncs.lo: cudd/cuddZddFuncs.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddFuncs.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Tpo -c -o cudd/cudd_libcudd_la-cuddZddFuncs.lo `test -f 'cudd/cuddZddFuncs.c' || echo '$(srcdir)/'`cudd/cuddZddFuncs.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddFuncs.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddFuncs.c' object='cudd/cudd_libcudd_la-cuddZddFuncs.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddFuncs.lo `test -f 'cudd/cuddZddFuncs.c' || echo '$(srcdir)/'`cudd/cuddZddFuncs.c - -cudd/cudd_libcudd_la-cuddZddGroup.lo: cudd/cuddZddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddGroup.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Tpo -c -o cudd/cudd_libcudd_la-cuddZddGroup.lo `test -f 'cudd/cuddZddGroup.c' || echo '$(srcdir)/'`cudd/cuddZddGroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddGroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddGroup.c' object='cudd/cudd_libcudd_la-cuddZddGroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddGroup.lo `test -f 'cudd/cuddZddGroup.c' || echo '$(srcdir)/'`cudd/cuddZddGroup.c - -cudd/cudd_libcudd_la-cuddZddIsop.lo: cudd/cuddZddIsop.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddIsop.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Tpo -c -o cudd/cudd_libcudd_la-cuddZddIsop.lo `test -f 'cudd/cuddZddIsop.c' || echo '$(srcdir)/'`cudd/cuddZddIsop.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddIsop.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddIsop.c' object='cudd/cudd_libcudd_la-cuddZddIsop.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddIsop.lo `test -f 'cudd/cuddZddIsop.c' || echo '$(srcdir)/'`cudd/cuddZddIsop.c - -cudd/cudd_libcudd_la-cuddZddLin.lo: cudd/cuddZddLin.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddLin.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Tpo -c -o cudd/cudd_libcudd_la-cuddZddLin.lo `test -f 'cudd/cuddZddLin.c' || echo '$(srcdir)/'`cudd/cuddZddLin.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddLin.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddLin.c' object='cudd/cudd_libcudd_la-cuddZddLin.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddLin.lo `test -f 'cudd/cuddZddLin.c' || echo '$(srcdir)/'`cudd/cuddZddLin.c - -cudd/cudd_libcudd_la-cuddZddMisc.lo: cudd/cuddZddMisc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddMisc.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Tpo -c -o cudd/cudd_libcudd_la-cuddZddMisc.lo `test -f 'cudd/cuddZddMisc.c' || echo '$(srcdir)/'`cudd/cuddZddMisc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddMisc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddMisc.c' object='cudd/cudd_libcudd_la-cuddZddMisc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddMisc.lo `test -f 'cudd/cuddZddMisc.c' || echo '$(srcdir)/'`cudd/cuddZddMisc.c - -cudd/cudd_libcudd_la-cuddZddPort.lo: cudd/cuddZddPort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddPort.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Tpo -c -o cudd/cudd_libcudd_la-cuddZddPort.lo `test -f 'cudd/cuddZddPort.c' || echo '$(srcdir)/'`cudd/cuddZddPort.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddPort.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddPort.c' object='cudd/cudd_libcudd_la-cuddZddPort.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddPort.lo `test -f 'cudd/cuddZddPort.c' || echo '$(srcdir)/'`cudd/cuddZddPort.c - -cudd/cudd_libcudd_la-cuddZddReord.lo: cudd/cuddZddReord.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddReord.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Tpo -c -o cudd/cudd_libcudd_la-cuddZddReord.lo `test -f 'cudd/cuddZddReord.c' || echo '$(srcdir)/'`cudd/cuddZddReord.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddReord.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddReord.c' object='cudd/cudd_libcudd_la-cuddZddReord.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddReord.lo `test -f 'cudd/cuddZddReord.c' || echo '$(srcdir)/'`cudd/cuddZddReord.c - -cudd/cudd_libcudd_la-cuddZddSetop.lo: cudd/cuddZddSetop.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddSetop.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Tpo -c -o cudd/cudd_libcudd_la-cuddZddSetop.lo `test -f 'cudd/cuddZddSetop.c' || echo '$(srcdir)/'`cudd/cuddZddSetop.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSetop.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddSetop.c' object='cudd/cudd_libcudd_la-cuddZddSetop.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddSetop.lo `test -f 'cudd/cuddZddSetop.c' || echo '$(srcdir)/'`cudd/cuddZddSetop.c - -cudd/cudd_libcudd_la-cuddZddSymm.lo: cudd/cuddZddSymm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddSymm.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Tpo -c -o cudd/cudd_libcudd_la-cuddZddSymm.lo `test -f 'cudd/cuddZddSymm.c' || echo '$(srcdir)/'`cudd/cuddZddSymm.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddSymm.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddSymm.c' object='cudd/cudd_libcudd_la-cuddZddSymm.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddSymm.lo `test -f 'cudd/cuddZddSymm.c' || echo '$(srcdir)/'`cudd/cuddZddSymm.c - -cudd/cudd_libcudd_la-cuddZddUtil.lo: cudd/cuddZddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_libcudd_la-cuddZddUtil.lo -MD -MP -MF cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Tpo -c -o cudd/cudd_libcudd_la-cuddZddUtil.lo `test -f 'cudd/cuddZddUtil.c' || echo '$(srcdir)/'`cudd/cuddZddUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Tpo cudd/$(DEPDIR)/cudd_libcudd_la-cuddZddUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/cuddZddUtil.c' object='cudd/cudd_libcudd_la-cuddZddUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_libcudd_la-cuddZddUtil.lo `test -f 'cudd/cuddZddUtil.c' || echo '$(srcdir)/'`cudd/cuddZddUtil.c - -util/cudd_libcudd_la-cpu_stats.lo: util/cpu_stats.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-cpu_stats.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Tpo -c -o util/cudd_libcudd_la-cpu_stats.lo `test -f 'util/cpu_stats.c' || echo '$(srcdir)/'`util/cpu_stats.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Tpo util/$(DEPDIR)/cudd_libcudd_la-cpu_stats.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/cpu_stats.c' object='util/cudd_libcudd_la-cpu_stats.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-cpu_stats.lo `test -f 'util/cpu_stats.c' || echo '$(srcdir)/'`util/cpu_stats.c - -util/cudd_libcudd_la-cpu_time.lo: util/cpu_time.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-cpu_time.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Tpo -c -o util/cudd_libcudd_la-cpu_time.lo `test -f 'util/cpu_time.c' || echo '$(srcdir)/'`util/cpu_time.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Tpo util/$(DEPDIR)/cudd_libcudd_la-cpu_time.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/cpu_time.c' object='util/cudd_libcudd_la-cpu_time.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-cpu_time.lo `test -f 'util/cpu_time.c' || echo '$(srcdir)/'`util/cpu_time.c - -util/cudd_libcudd_la-cstringstream.lo: util/cstringstream.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-cstringstream.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Tpo -c -o util/cudd_libcudd_la-cstringstream.lo `test -f 'util/cstringstream.c' || echo '$(srcdir)/'`util/cstringstream.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Tpo util/$(DEPDIR)/cudd_libcudd_la-cstringstream.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/cstringstream.c' object='util/cudd_libcudd_la-cstringstream.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-cstringstream.lo `test -f 'util/cstringstream.c' || echo '$(srcdir)/'`util/cstringstream.c - -util/cudd_libcudd_la-datalimit.lo: util/datalimit.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-datalimit.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-datalimit.Tpo -c -o util/cudd_libcudd_la-datalimit.lo `test -f 'util/datalimit.c' || echo '$(srcdir)/'`util/datalimit.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-datalimit.Tpo util/$(DEPDIR)/cudd_libcudd_la-datalimit.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/datalimit.c' object='util/cudd_libcudd_la-datalimit.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-datalimit.lo `test -f 'util/datalimit.c' || echo '$(srcdir)/'`util/datalimit.c - -util/cudd_libcudd_la-pathsearch.lo: util/pathsearch.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-pathsearch.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Tpo -c -o util/cudd_libcudd_la-pathsearch.lo `test -f 'util/pathsearch.c' || echo '$(srcdir)/'`util/pathsearch.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Tpo util/$(DEPDIR)/cudd_libcudd_la-pathsearch.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/pathsearch.c' object='util/cudd_libcudd_la-pathsearch.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-pathsearch.lo `test -f 'util/pathsearch.c' || echo '$(srcdir)/'`util/pathsearch.c - -util/cudd_libcudd_la-pipefork.lo: util/pipefork.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-pipefork.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-pipefork.Tpo -c -o util/cudd_libcudd_la-pipefork.lo `test -f 'util/pipefork.c' || echo '$(srcdir)/'`util/pipefork.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-pipefork.Tpo util/$(DEPDIR)/cudd_libcudd_la-pipefork.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/pipefork.c' object='util/cudd_libcudd_la-pipefork.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-pipefork.lo `test -f 'util/pipefork.c' || echo '$(srcdir)/'`util/pipefork.c - -util/cudd_libcudd_la-prtime.lo: util/prtime.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-prtime.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-prtime.Tpo -c -o util/cudd_libcudd_la-prtime.lo `test -f 'util/prtime.c' || echo '$(srcdir)/'`util/prtime.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-prtime.Tpo util/$(DEPDIR)/cudd_libcudd_la-prtime.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/prtime.c' object='util/cudd_libcudd_la-prtime.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-prtime.lo `test -f 'util/prtime.c' || echo '$(srcdir)/'`util/prtime.c - -util/cudd_libcudd_la-safe_mem.lo: util/safe_mem.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-safe_mem.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Tpo -c -o util/cudd_libcudd_la-safe_mem.lo `test -f 'util/safe_mem.c' || echo '$(srcdir)/'`util/safe_mem.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Tpo util/$(DEPDIR)/cudd_libcudd_la-safe_mem.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/safe_mem.c' object='util/cudd_libcudd_la-safe_mem.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-safe_mem.lo `test -f 'util/safe_mem.c' || echo '$(srcdir)/'`util/safe_mem.c - -util/cudd_libcudd_la-strsav.lo: util/strsav.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-strsav.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-strsav.Tpo -c -o util/cudd_libcudd_la-strsav.lo `test -f 'util/strsav.c' || echo '$(srcdir)/'`util/strsav.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-strsav.Tpo util/$(DEPDIR)/cudd_libcudd_la-strsav.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/strsav.c' object='util/cudd_libcudd_la-strsav.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-strsav.lo `test -f 'util/strsav.c' || echo '$(srcdir)/'`util/strsav.c - -util/cudd_libcudd_la-texpand.lo: util/texpand.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-texpand.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-texpand.Tpo -c -o util/cudd_libcudd_la-texpand.lo `test -f 'util/texpand.c' || echo '$(srcdir)/'`util/texpand.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-texpand.Tpo util/$(DEPDIR)/cudd_libcudd_la-texpand.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/texpand.c' object='util/cudd_libcudd_la-texpand.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-texpand.lo `test -f 'util/texpand.c' || echo '$(srcdir)/'`util/texpand.c - -util/cudd_libcudd_la-ucbqsort.lo: util/ucbqsort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT util/cudd_libcudd_la-ucbqsort.lo -MD -MP -MF util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Tpo -c -o util/cudd_libcudd_la-ucbqsort.lo `test -f 'util/ucbqsort.c' || echo '$(srcdir)/'`util/ucbqsort.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Tpo util/$(DEPDIR)/cudd_libcudd_la-ucbqsort.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util/ucbqsort.c' object='util/cudd_libcudd_la-ucbqsort.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o util/cudd_libcudd_la-ucbqsort.lo `test -f 'util/ucbqsort.c' || echo '$(srcdir)/'`util/ucbqsort.c - -st/cudd_libcudd_la-st.lo: st/st.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT st/cudd_libcudd_la-st.lo -MD -MP -MF st/$(DEPDIR)/cudd_libcudd_la-st.Tpo -c -o st/cudd_libcudd_la-st.lo `test -f 'st/st.c' || echo '$(srcdir)/'`st/st.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) st/$(DEPDIR)/cudd_libcudd_la-st.Tpo st/$(DEPDIR)/cudd_libcudd_la-st.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st/st.c' object='st/cudd_libcudd_la-st.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o st/cudd_libcudd_la-st.lo `test -f 'st/st.c' || echo '$(srcdir)/'`st/st.c - -epd/cudd_libcudd_la-epd.lo: epd/epd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT epd/cudd_libcudd_la-epd.lo -MD -MP -MF epd/$(DEPDIR)/cudd_libcudd_la-epd.Tpo -c -o epd/cudd_libcudd_la-epd.lo `test -f 'epd/epd.c' || echo '$(srcdir)/'`epd/epd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) epd/$(DEPDIR)/cudd_libcudd_la-epd.Tpo epd/$(DEPDIR)/cudd_libcudd_la-epd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epd/epd.c' object='epd/cudd_libcudd_la-epd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o epd/cudd_libcudd_la-epd.lo `test -f 'epd/epd.c' || echo '$(srcdir)/'`epd/epd.c - -mtr/cudd_libcudd_la-mtrBasic.lo: mtr/mtrBasic.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/cudd_libcudd_la-mtrBasic.lo -MD -MP -MF mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Tpo -c -o mtr/cudd_libcudd_la-mtrBasic.lo `test -f 'mtr/mtrBasic.c' || echo '$(srcdir)/'`mtr/mtrBasic.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Tpo mtr/$(DEPDIR)/cudd_libcudd_la-mtrBasic.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/mtrBasic.c' object='mtr/cudd_libcudd_la-mtrBasic.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/cudd_libcudd_la-mtrBasic.lo `test -f 'mtr/mtrBasic.c' || echo '$(srcdir)/'`mtr/mtrBasic.c - -mtr/cudd_libcudd_la-mtrGroup.lo: mtr/mtrGroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/cudd_libcudd_la-mtrGroup.lo -MD -MP -MF mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Tpo -c -o mtr/cudd_libcudd_la-mtrGroup.lo `test -f 'mtr/mtrGroup.c' || echo '$(srcdir)/'`mtr/mtrGroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Tpo mtr/$(DEPDIR)/cudd_libcudd_la-mtrGroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/mtrGroup.c' object='mtr/cudd_libcudd_la-mtrGroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/cudd_libcudd_la-mtrGroup.lo `test -f 'mtr/mtrGroup.c' || echo '$(srcdir)/'`mtr/mtrGroup.c - -dddmp/cudd_libcudd_la-dddmpBinary.lo: dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpBinary.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Tpo -c -o dddmp/cudd_libcudd_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpBinary.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpBinary.c' object='dddmp/cudd_libcudd_la-dddmpBinary.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c - -dddmp/cudd_libcudd_la-dddmpConvert.lo: dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpConvert.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Tpo -c -o dddmp/cudd_libcudd_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpConvert.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpConvert.c' object='dddmp/cudd_libcudd_la-dddmpConvert.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c - -dddmp/cudd_libcudd_la-dddmpDbg.lo: dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpDbg.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Tpo -c -o dddmp/cudd_libcudd_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpDbg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpDbg.c' object='dddmp/cudd_libcudd_la-dddmpDbg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c - -dddmp/cudd_libcudd_la-dddmpLoad.lo: dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpLoad.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Tpo -c -o dddmp/cudd_libcudd_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoad.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoad.c' object='dddmp/cudd_libcudd_la-dddmpLoad.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c - -dddmp/cudd_libcudd_la-dddmpLoadCnf.lo: dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpLoadCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Tpo -c -o dddmp/cudd_libcudd_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpLoadCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoadCnf.c' object='dddmp/cudd_libcudd_la-dddmpLoadCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c - -dddmp/cudd_libcudd_la-dddmpNodeAdd.lo: dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpNodeAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeAdd.c' object='dddmp/cudd_libcudd_la-dddmpNodeAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c - -dddmp/cudd_libcudd_la-dddmpNodeBdd.lo: dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpNodeBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeBdd.c' object='dddmp/cudd_libcudd_la-dddmpNodeBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c - -dddmp/cudd_libcudd_la-dddmpNodeCnf.lo: dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpNodeCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Tpo -c -o dddmp/cudd_libcudd_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpNodeCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeCnf.c' object='dddmp/cudd_libcudd_la-dddmpNodeCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c - -dddmp/cudd_libcudd_la-dddmpStoreAdd.lo: dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreAdd.c' object='dddmp/cudd_libcudd_la-dddmpStoreAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c - -dddmp/cudd_libcudd_la-dddmpStoreBdd.lo: dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreBdd.c' object='dddmp/cudd_libcudd_la-dddmpStoreBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c - -dddmp/cudd_libcudd_la-dddmpStoreCnf.lo: dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreCnf.c' object='dddmp/cudd_libcudd_la-dddmpStoreCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c - -dddmp/cudd_libcudd_la-dddmpStoreMisc.lo: dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpStoreMisc.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Tpo -c -o dddmp/cudd_libcudd_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpStoreMisc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreMisc.c' object='dddmp/cudd_libcudd_la-dddmpStoreMisc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c - -dddmp/cudd_libcudd_la-dddmpUtil.lo: dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/cudd_libcudd_la-dddmpUtil.lo -MD -MP -MF dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Tpo -c -o dddmp/cudd_libcudd_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Tpo dddmp/$(DEPDIR)/cudd_libcudd_la-dddmpUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpUtil.c' object='dddmp/cudd_libcudd_la-dddmpUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/cudd_libcudd_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c - -dddmp/dddmp_libdddmp_la-dddmpBinary.lo: dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpBinary.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpBinary.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpBinary.c' object='dddmp/dddmp_libdddmp_la-dddmpBinary.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpBinary.lo `test -f 'dddmp/dddmpBinary.c' || echo '$(srcdir)/'`dddmp/dddmpBinary.c - -dddmp/dddmp_libdddmp_la-dddmpConvert.lo: dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpConvert.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpConvert.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpConvert.c' object='dddmp/dddmp_libdddmp_la-dddmpConvert.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpConvert.lo `test -f 'dddmp/dddmpConvert.c' || echo '$(srcdir)/'`dddmp/dddmpConvert.c - -dddmp/dddmp_libdddmp_la-dddmpDbg.lo: dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpDbg.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpDbg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpDbg.c' object='dddmp/dddmp_libdddmp_la-dddmpDbg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpDbg.lo `test -f 'dddmp/dddmpDbg.c' || echo '$(srcdir)/'`dddmp/dddmpDbg.c - -dddmp/dddmp_libdddmp_la-dddmpLoad.lo: dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpLoad.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoad.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoad.c' object='dddmp/dddmp_libdddmp_la-dddmpLoad.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpLoad.lo `test -f 'dddmp/dddmpLoad.c' || echo '$(srcdir)/'`dddmp/dddmpLoad.c - -dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo: dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpLoadCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpLoadCnf.c' object='dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpLoadCnf.lo `test -f 'dddmp/dddmpLoadCnf.c' || echo '$(srcdir)/'`dddmp/dddmpLoadCnf.c - -dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo: dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeAdd.c' object='dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpNodeAdd.lo `test -f 'dddmp/dddmpNodeAdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeAdd.c - -dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo: dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeBdd.c' object='dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpNodeBdd.lo `test -f 'dddmp/dddmpNodeBdd.c' || echo '$(srcdir)/'`dddmp/dddmpNodeBdd.c - -dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo: dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpNodeCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpNodeCnf.c' object='dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpNodeCnf.lo `test -f 'dddmp/dddmpNodeCnf.c' || echo '$(srcdir)/'`dddmp/dddmpNodeCnf.c - -dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo: dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreAdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreAdd.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreAdd.lo `test -f 'dddmp/dddmpStoreAdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreAdd.c - -dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo: dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreBdd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreBdd.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreBdd.lo `test -f 'dddmp/dddmpStoreBdd.c' || echo '$(srcdir)/'`dddmp/dddmpStoreBdd.c - -dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo: dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreCnf.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreCnf.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreCnf.lo `test -f 'dddmp/dddmpStoreCnf.c' || echo '$(srcdir)/'`dddmp/dddmpStoreCnf.c - -dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo: dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpStoreMisc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpStoreMisc.c' object='dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpStoreMisc.lo `test -f 'dddmp/dddmpStoreMisc.c' || echo '$(srcdir)/'`dddmp/dddmpStoreMisc.c - -dddmp/dddmp_libdddmp_la-dddmpUtil.lo: dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_libdddmp_la-dddmpUtil.lo -MD -MP -MF dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Tpo -c -o dddmp/dddmp_libdddmp_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Tpo dddmp/$(DEPDIR)/dddmp_libdddmp_la-dddmpUtil.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/dddmpUtil.c' object='dddmp/dddmp_libdddmp_la-dddmpUtil.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_libdddmp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_libdddmp_la-dddmpUtil.lo `test -f 'dddmp/dddmpUtil.c' || echo '$(srcdir)/'`dddmp/dddmpUtil.c - -cudd/cudd_testcudd-testcudd.o: cudd/testcudd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testcudd-testcudd.o -MD -MP -MF cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo -c -o cudd/cudd_testcudd-testcudd.o `test -f 'cudd/testcudd.c' || echo '$(srcdir)/'`cudd/testcudd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo cudd/$(DEPDIR)/cudd_testcudd-testcudd.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testcudd.c' object='cudd/cudd_testcudd-testcudd.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testcudd-testcudd.o `test -f 'cudd/testcudd.c' || echo '$(srcdir)/'`cudd/testcudd.c - -cudd/cudd_testcudd-testcudd.obj: cudd/testcudd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testcudd-testcudd.obj -MD -MP -MF cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo -c -o cudd/cudd_testcudd-testcudd.obj `if test -f 'cudd/testcudd.c'; then $(CYGPATH_W) 'cudd/testcudd.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testcudd.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testcudd-testcudd.Tpo cudd/$(DEPDIR)/cudd_testcudd-testcudd.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testcudd.c' object='cudd/cudd_testcudd-testcudd.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testcudd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testcudd-testcudd.obj `if test -f 'cudd/testcudd.c'; then $(CYGPATH_W) 'cudd/testcudd.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testcudd.c'; fi` - -cudd/cudd_testextra-testextra.o: cudd/testextra.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testextra-testextra.o -MD -MP -MF cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo -c -o cudd/cudd_testextra-testextra.o `test -f 'cudd/testextra.c' || echo '$(srcdir)/'`cudd/testextra.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo cudd/$(DEPDIR)/cudd_testextra-testextra.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testextra.c' object='cudd/cudd_testextra-testextra.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testextra-testextra.o `test -f 'cudd/testextra.c' || echo '$(srcdir)/'`cudd/testextra.c - -cudd/cudd_testextra-testextra.obj: cudd/testextra.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cudd/cudd_testextra-testextra.obj -MD -MP -MF cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo -c -o cudd/cudd_testextra-testextra.obj `if test -f 'cudd/testextra.c'; then $(CYGPATH_W) 'cudd/testextra.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testextra.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) cudd/$(DEPDIR)/cudd_testextra-testextra.Tpo cudd/$(DEPDIR)/cudd_testextra-testextra.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cudd/testextra.c' object='cudd/cudd_testextra-testextra.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_testextra_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cudd/cudd_testextra-testextra.obj `if test -f 'cudd/testextra.c'; then $(CYGPATH_W) 'cudd/testextra.c'; else $(CYGPATH_W) '$(srcdir)/cudd/testextra.c'; fi` - -dddmp/dddmp_testdddmp-testdddmp.o: dddmp/testdddmp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_testdddmp-testdddmp.o -MD -MP -MF dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo -c -o dddmp/dddmp_testdddmp-testdddmp.o `test -f 'dddmp/testdddmp.c' || echo '$(srcdir)/'`dddmp/testdddmp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/testdddmp.c' object='dddmp/dddmp_testdddmp-testdddmp.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_testdddmp-testdddmp.o `test -f 'dddmp/testdddmp.c' || echo '$(srcdir)/'`dddmp/testdddmp.c - -dddmp/dddmp_testdddmp-testdddmp.obj: dddmp/testdddmp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dddmp/dddmp_testdddmp-testdddmp.obj -MD -MP -MF dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo -c -o dddmp/dddmp_testdddmp-testdddmp.obj `if test -f 'dddmp/testdddmp.c'; then $(CYGPATH_W) 'dddmp/testdddmp.c'; else $(CYGPATH_W) '$(srcdir)/dddmp/testdddmp.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Tpo dddmp/$(DEPDIR)/dddmp_testdddmp-testdddmp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dddmp/testdddmp.c' object='dddmp/dddmp_testdddmp-testdddmp.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dddmp_testdddmp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dddmp/dddmp_testdddmp-testdddmp.obj `if test -f 'dddmp/testdddmp.c'; then $(CYGPATH_W) 'dddmp/testdddmp.c'; else $(CYGPATH_W) '$(srcdir)/dddmp/testdddmp.c'; fi` - -mtr/mtr_testmtr-testmtr.o: mtr/testmtr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/mtr_testmtr-testmtr.o -MD -MP -MF mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo -c -o mtr/mtr_testmtr-testmtr.o `test -f 'mtr/testmtr.c' || echo '$(srcdir)/'`mtr/testmtr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo mtr/$(DEPDIR)/mtr_testmtr-testmtr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/testmtr.c' object='mtr/mtr_testmtr-testmtr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/mtr_testmtr-testmtr.o `test -f 'mtr/testmtr.c' || echo '$(srcdir)/'`mtr/testmtr.c - -mtr/mtr_testmtr-testmtr.obj: mtr/testmtr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mtr/mtr_testmtr-testmtr.obj -MD -MP -MF mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo -c -o mtr/mtr_testmtr-testmtr.obj `if test -f 'mtr/testmtr.c'; then $(CYGPATH_W) 'mtr/testmtr.c'; else $(CYGPATH_W) '$(srcdir)/mtr/testmtr.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) mtr/$(DEPDIR)/mtr_testmtr-testmtr.Tpo mtr/$(DEPDIR)/mtr_testmtr-testmtr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtr/testmtr.c' object='mtr/mtr_testmtr-testmtr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mtr_testmtr_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mtr/mtr_testmtr-testmtr.obj `if test -f 'mtr/testmtr.c'; then $(CYGPATH_W) 'mtr/testmtr.c'; else $(CYGPATH_W) '$(srcdir)/mtr/testmtr.c'; fi` - -nanotrav/nanotrav_nanotrav-bnet.o: nanotrav/bnet.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-bnet.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo -c -o nanotrav/nanotrav_nanotrav-bnet.o `test -f 'nanotrav/bnet.c' || echo '$(srcdir)/'`nanotrav/bnet.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/bnet.c' object='nanotrav/nanotrav_nanotrav-bnet.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-bnet.o `test -f 'nanotrav/bnet.c' || echo '$(srcdir)/'`nanotrav/bnet.c - -nanotrav/nanotrav_nanotrav-bnet.obj: nanotrav/bnet.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-bnet.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo -c -o nanotrav/nanotrav_nanotrav-bnet.obj `if test -f 'nanotrav/bnet.c'; then $(CYGPATH_W) 'nanotrav/bnet.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/bnet.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-bnet.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/bnet.c' object='nanotrav/nanotrav_nanotrav-bnet.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-bnet.obj `if test -f 'nanotrav/bnet.c'; then $(CYGPATH_W) 'nanotrav/bnet.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/bnet.c'; fi` - -nanotrav/nanotrav_nanotrav-chkMterm.o: nanotrav/chkMterm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-chkMterm.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo -c -o nanotrav/nanotrav_nanotrav-chkMterm.o `test -f 'nanotrav/chkMterm.c' || echo '$(srcdir)/'`nanotrav/chkMterm.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/chkMterm.c' object='nanotrav/nanotrav_nanotrav-chkMterm.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-chkMterm.o `test -f 'nanotrav/chkMterm.c' || echo '$(srcdir)/'`nanotrav/chkMterm.c - -nanotrav/nanotrav_nanotrav-chkMterm.obj: nanotrav/chkMterm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-chkMterm.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo -c -o nanotrav/nanotrav_nanotrav-chkMterm.obj `if test -f 'nanotrav/chkMterm.c'; then $(CYGPATH_W) 'nanotrav/chkMterm.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/chkMterm.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-chkMterm.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/chkMterm.c' object='nanotrav/nanotrav_nanotrav-chkMterm.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-chkMterm.obj `if test -f 'nanotrav/chkMterm.c'; then $(CYGPATH_W) 'nanotrav/chkMterm.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/chkMterm.c'; fi` - -nanotrav/nanotrav_nanotrav-main.o: nanotrav/main.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-main.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo -c -o nanotrav/nanotrav_nanotrav-main.o `test -f 'nanotrav/main.c' || echo '$(srcdir)/'`nanotrav/main.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/main.c' object='nanotrav/nanotrav_nanotrav-main.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-main.o `test -f 'nanotrav/main.c' || echo '$(srcdir)/'`nanotrav/main.c - -nanotrav/nanotrav_nanotrav-main.obj: nanotrav/main.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-main.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo -c -o nanotrav/nanotrav_nanotrav-main.obj `if test -f 'nanotrav/main.c'; then $(CYGPATH_W) 'nanotrav/main.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/main.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/main.c' object='nanotrav/nanotrav_nanotrav-main.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-main.obj `if test -f 'nanotrav/main.c'; then $(CYGPATH_W) 'nanotrav/main.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/main.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrBddTest.o: nanotrav/ntrBddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrBddTest.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.o `test -f 'nanotrav/ntrBddTest.c' || echo '$(srcdir)/'`nanotrav/ntrBddTest.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrBddTest.c' object='nanotrav/nanotrav_nanotrav-ntrBddTest.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.o `test -f 'nanotrav/ntrBddTest.c' || echo '$(srcdir)/'`nanotrav/ntrBddTest.c - -nanotrav/nanotrav_nanotrav-ntrBddTest.obj: nanotrav/ntrBddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrBddTest.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.obj `if test -f 'nanotrav/ntrBddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrBddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrBddTest.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrBddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrBddTest.c' object='nanotrav/nanotrav_nanotrav-ntrBddTest.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrBddTest.obj `if test -f 'nanotrav/ntrBddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrBddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrBddTest.c'; fi` - -nanotrav/nanotrav_nanotrav-ntr.o: nanotrav/ntr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntr.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo -c -o nanotrav/nanotrav_nanotrav-ntr.o `test -f 'nanotrav/ntr.c' || echo '$(srcdir)/'`nanotrav/ntr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntr.c' object='nanotrav/nanotrav_nanotrav-ntr.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntr.o `test -f 'nanotrav/ntr.c' || echo '$(srcdir)/'`nanotrav/ntr.c - -nanotrav/nanotrav_nanotrav-ntr.obj: nanotrav/ntr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntr.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo -c -o nanotrav/nanotrav_nanotrav-ntr.obj `if test -f 'nanotrav/ntr.c'; then $(CYGPATH_W) 'nanotrav/ntr.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntr.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntr.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntr.c' object='nanotrav/nanotrav_nanotrav-ntr.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntr.obj `if test -f 'nanotrav/ntr.c'; then $(CYGPATH_W) 'nanotrav/ntr.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntr.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrHeap.o: nanotrav/ntrHeap.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrHeap.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrHeap.o `test -f 'nanotrav/ntrHeap.c' || echo '$(srcdir)/'`nanotrav/ntrHeap.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrHeap.c' object='nanotrav/nanotrav_nanotrav-ntrHeap.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrHeap.o `test -f 'nanotrav/ntrHeap.c' || echo '$(srcdir)/'`nanotrav/ntrHeap.c - -nanotrav/nanotrav_nanotrav-ntrHeap.obj: nanotrav/ntrHeap.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrHeap.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrHeap.obj `if test -f 'nanotrav/ntrHeap.c'; then $(CYGPATH_W) 'nanotrav/ntrHeap.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrHeap.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrHeap.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrHeap.c' object='nanotrav/nanotrav_nanotrav-ntrHeap.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrHeap.obj `if test -f 'nanotrav/ntrHeap.c'; then $(CYGPATH_W) 'nanotrav/ntrHeap.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrHeap.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrMflow.o: nanotrav/ntrMflow.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrMflow.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrMflow.o `test -f 'nanotrav/ntrMflow.c' || echo '$(srcdir)/'`nanotrav/ntrMflow.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrMflow.c' object='nanotrav/nanotrav_nanotrav-ntrMflow.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrMflow.o `test -f 'nanotrav/ntrMflow.c' || echo '$(srcdir)/'`nanotrav/ntrMflow.c - -nanotrav/nanotrav_nanotrav-ntrMflow.obj: nanotrav/ntrMflow.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrMflow.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrMflow.obj `if test -f 'nanotrav/ntrMflow.c'; then $(CYGPATH_W) 'nanotrav/ntrMflow.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrMflow.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrMflow.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrMflow.c' object='nanotrav/nanotrav_nanotrav-ntrMflow.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrMflow.obj `if test -f 'nanotrav/ntrMflow.c'; then $(CYGPATH_W) 'nanotrav/ntrMflow.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrMflow.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrShort.o: nanotrav/ntrShort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrShort.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrShort.o `test -f 'nanotrav/ntrShort.c' || echo '$(srcdir)/'`nanotrav/ntrShort.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrShort.c' object='nanotrav/nanotrav_nanotrav-ntrShort.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrShort.o `test -f 'nanotrav/ntrShort.c' || echo '$(srcdir)/'`nanotrav/ntrShort.c - -nanotrav/nanotrav_nanotrav-ntrShort.obj: nanotrav/ntrShort.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrShort.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrShort.obj `if test -f 'nanotrav/ntrShort.c'; then $(CYGPATH_W) 'nanotrav/ntrShort.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrShort.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrShort.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrShort.c' object='nanotrav/nanotrav_nanotrav-ntrShort.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrShort.obj `if test -f 'nanotrav/ntrShort.c'; then $(CYGPATH_W) 'nanotrav/ntrShort.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrShort.c'; fi` - -nanotrav/nanotrav_nanotrav-ntrZddTest.o: nanotrav/ntrZddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrZddTest.o -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.o `test -f 'nanotrav/ntrZddTest.c' || echo '$(srcdir)/'`nanotrav/ntrZddTest.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrZddTest.c' object='nanotrav/nanotrav_nanotrav-ntrZddTest.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.o `test -f 'nanotrav/ntrZddTest.c' || echo '$(srcdir)/'`nanotrav/ntrZddTest.c - -nanotrav/nanotrav_nanotrav-ntrZddTest.obj: nanotrav/ntrZddTest.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nanotrav/nanotrav_nanotrav-ntrZddTest.obj -MD -MP -MF nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.obj `if test -f 'nanotrav/ntrZddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrZddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrZddTest.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Tpo nanotrav/$(DEPDIR)/nanotrav_nanotrav-ntrZddTest.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nanotrav/ntrZddTest.c' object='nanotrav/nanotrav_nanotrav-ntrZddTest.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(nanotrav_nanotrav_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nanotrav/nanotrav_nanotrav-ntrZddTest.obj `if test -f 'nanotrav/ntrZddTest.c'; then $(CYGPATH_W) 'nanotrav/ntrZddTest.c'; else $(CYGPATH_W) '$(srcdir)/nanotrav/ntrZddTest.c'; fi` - -st/st_testst-testst.o: st/testst.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT st/st_testst-testst.o -MD -MP -MF st/$(DEPDIR)/st_testst-testst.Tpo -c -o st/st_testst-testst.o `test -f 'st/testst.c' || echo '$(srcdir)/'`st/testst.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) st/$(DEPDIR)/st_testst-testst.Tpo st/$(DEPDIR)/st_testst-testst.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st/testst.c' object='st/st_testst-testst.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o st/st_testst-testst.o `test -f 'st/testst.c' || echo '$(srcdir)/'`st/testst.c - -st/st_testst-testst.obj: st/testst.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT st/st_testst-testst.obj -MD -MP -MF st/$(DEPDIR)/st_testst-testst.Tpo -c -o st/st_testst-testst.obj `if test -f 'st/testst.c'; then $(CYGPATH_W) 'st/testst.c'; else $(CYGPATH_W) '$(srcdir)/st/testst.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) st/$(DEPDIR)/st_testst-testst.Tpo st/$(DEPDIR)/st_testst-testst.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st/testst.c' object='st/st_testst-testst.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(st_testst_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o st/st_testst-testst.obj `if test -f 'st/testst.c'; then $(CYGPATH_W) 'st/testst.c'; else $(CYGPATH_W) '$(srcdir)/st/testst.c'; fi` - -.cc.o: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< - -.cc.obj: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.cc.lo: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< - -cplusplus/cplusplus_libobj_la-cuddObj.lo: cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_libobj_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_libobj_la-cuddObj.lo -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Tpo -c -o cplusplus/cplusplus_libobj_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Tpo cplusplus/$(DEPDIR)/cplusplus_libobj_la-cuddObj.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/cuddObj.cc' object='cplusplus/cplusplus_libobj_la-cuddObj.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_libobj_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_libobj_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc - -cplusplus/cudd_libcudd_la-cuddObj.lo: cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cudd_libcudd_la-cuddObj.lo -MD -MP -MF cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Tpo -c -o cplusplus/cudd_libcudd_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Tpo cplusplus/$(DEPDIR)/cudd_libcudd_la-cuddObj.Plo -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/cuddObj.cc' object='cplusplus/cudd_libcudd_la-cuddObj.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(cudd_libcudd_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cudd_libcudd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cudd_libcudd_la-cuddObj.lo `test -f 'cplusplus/cuddObj.cc' || echo '$(srcdir)/'`cplusplus/cuddObj.cc - -cplusplus/cplusplus_testmulti-testmulti.o: cplusplus/testmulti.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testmulti-testmulti.o -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo -c -o cplusplus/cplusplus_testmulti-testmulti.o `test -f 'cplusplus/testmulti.cc' || echo '$(srcdir)/'`cplusplus/testmulti.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testmulti.cc' object='cplusplus/cplusplus_testmulti-testmulti.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testmulti-testmulti.o `test -f 'cplusplus/testmulti.cc' || echo '$(srcdir)/'`cplusplus/testmulti.cc - -cplusplus/cplusplus_testmulti-testmulti.obj: cplusplus/testmulti.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testmulti-testmulti.obj -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo -c -o cplusplus/cplusplus_testmulti-testmulti.obj `if test -f 'cplusplus/testmulti.cc'; then $(CYGPATH_W) 'cplusplus/testmulti.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testmulti.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Tpo cplusplus/$(DEPDIR)/cplusplus_testmulti-testmulti.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testmulti.cc' object='cplusplus/cplusplus_testmulti-testmulti.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testmulti_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testmulti-testmulti.obj `if test -f 'cplusplus/testmulti.cc'; then $(CYGPATH_W) 'cplusplus/testmulti.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testmulti.cc'; fi` - -cplusplus/cplusplus_testobj-testobj.o: cplusplus/testobj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testobj-testobj.o -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo -c -o cplusplus/cplusplus_testobj-testobj.o `test -f 'cplusplus/testobj.cc' || echo '$(srcdir)/'`cplusplus/testobj.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testobj.cc' object='cplusplus/cplusplus_testobj-testobj.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testobj-testobj.o `test -f 'cplusplus/testobj.cc' || echo '$(srcdir)/'`cplusplus/testobj.cc - -cplusplus/cplusplus_testobj-testobj.obj: cplusplus/testobj.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cplusplus/cplusplus_testobj-testobj.obj -MD -MP -MF cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo -c -o cplusplus/cplusplus_testobj-testobj.obj `if test -f 'cplusplus/testobj.cc'; then $(CYGPATH_W) 'cplusplus/testobj.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testobj.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Tpo cplusplus/$(DEPDIR)/cplusplus_testobj-testobj.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cplusplus/testobj.cc' object='cplusplus/cplusplus_testobj-testobj.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cplusplus_testobj_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cplusplus/cplusplus_testobj-testobj.obj `if test -f 'cplusplus/testobj.cc'; then $(CYGPATH_W) 'cplusplus/testobj.cc'; else $(CYGPATH_W) '$(srcdir)/cplusplus/testobj.cc'; fi` - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -rm -rf cplusplus/.libs cplusplus/_libs - -rm -rf cudd/.libs cudd/_libs - -rm -rf dddmp/.libs dddmp/_libs - -rm -rf epd/.libs epd/_libs - -rm -rf mtr/.libs mtr/_libs - -rm -rf nanotrav/.libs nanotrav/_libs - -rm -rf st/.libs st/_libs - -rm -rf util/.libs util/_libs - -distclean-libtool: - -rm -f libtool config.lt -install-includeHEADERS: $(include_HEADERS) - @$(NORMAL_INSTALL) - @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ - $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ - done - -uninstall-includeHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscope: cscope.files - test ! -s cscope.files \ - || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) -clean-cscope: - -rm -f cscope.files -cscope.files: clean-cscope cscopelist -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -rm -f cscope.out cscope.in.out cscope.po.out cscope.files - -# Recover from deleted '.trs' file; this should ensure that -# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create -# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells -# to avoid problems with "make -n". -.log.trs: - rm -f $< $@ - $(MAKE) $(AM_MAKEFLAGS) $< - -# Leading 'am--fnord' is there to ensure the list of targets does not -# expand to empty, as could happen e.g. with make check TESTS=''. -am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) -am--force-recheck: - @: - -$(TEST_SUITE_LOG): $(TEST_LOGS) - @$(am__set_TESTS_bases); \ - am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ - redo_bases=`for i in $$bases; do \ - am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ - done`; \ - if test -n "$$redo_bases"; then \ - redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ - redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ - if $(am__make_dryrun); then :; else \ - rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ - fi; \ - fi; \ - if test -n "$$am__remaking_logs"; then \ - echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ - "recursion detected" >&2; \ - elif test -n "$$redo_logs"; then \ - am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ - fi; \ - if $(am__make_dryrun); then :; else \ - st=0; \ - errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ - for i in $$redo_bases; do \ - test -f $$i.trs && test -r $$i.trs \ - || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ - test -f $$i.log && test -r $$i.log \ - || { echo "$$errmsg $$i.log" >&2; st=1; }; \ - done; \ - test $$st -eq 0 || exit 1; \ - fi - @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ - ws='[ ]'; \ - results=`for b in $$bases; do echo $$b.trs; done`; \ - test -n "$$results" || results=/dev/null; \ - all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ - pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ - fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ - skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ - xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ - xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ - error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ - if test `expr $$fail + $$xpass + $$error` -eq 0; then \ - success=true; \ - else \ - success=false; \ - fi; \ - br='==================='; br=$$br$$br$$br$$br; \ - result_count () \ - { \ - if test x"$$1" = x"--maybe-color"; then \ - maybe_colorize=yes; \ - elif test x"$$1" = x"--no-color"; then \ - maybe_colorize=no; \ - else \ - echo "$@: invalid 'result_count' usage" >&2; exit 4; \ - fi; \ - shift; \ - desc=$$1 count=$$2; \ - if test $$maybe_colorize = yes && test $$count -gt 0; then \ - color_start=$$3 color_end=$$std; \ - else \ - color_start= color_end=; \ - fi; \ - echo "$${color_start}# $$desc $$count$${color_end}"; \ - }; \ - create_testsuite_report () \ - { \ - result_count $$1 "TOTAL:" $$all "$$brg"; \ - result_count $$1 "PASS: " $$pass "$$grn"; \ - result_count $$1 "SKIP: " $$skip "$$blu"; \ - result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ - result_count $$1 "FAIL: " $$fail "$$red"; \ - result_count $$1 "XPASS:" $$xpass "$$red"; \ - result_count $$1 "ERROR:" $$error "$$mgn"; \ - }; \ - { \ - echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ - $(am__rst_title); \ - create_testsuite_report --no-color; \ - echo; \ - echo ".. contents:: :depth: 2"; \ - echo; \ - for b in $$bases; do echo $$b; done \ - | $(am__create_global_log); \ - } >$(TEST_SUITE_LOG).tmp || exit 1; \ - mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ - if $$success; then \ - col="$$grn"; \ - else \ - col="$$red"; \ - test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ - fi; \ - echo "$${col}$$br$${std}"; \ - echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ - echo "$${col}$$br$${std}"; \ - create_testsuite_report --maybe-color; \ - echo "$$col$$br$$std"; \ - if $$success; then :; else \ - echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ - if test -n "$(PACKAGE_BUGREPORT)"; then \ - echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ - fi; \ - echo "$$col$$br$$std"; \ - fi; \ - $$success || exit 1 - -check-TESTS: - @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list - @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - @set +e; $(am__set_TESTS_bases); \ - log_list=`for i in $$bases; do echo $$i.log; done`; \ - trs_list=`for i in $$bases; do echo $$i.trs; done`; \ - log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ - $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ - exit $$?; -recheck: all $(check_PROGRAMS) $(check_SCRIPTS) $(dist_check_DATA) - @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - @set +e; $(am__set_TESTS_bases); \ - bases=`for i in $$bases; do echo $$i; done \ - | $(am__list_recheck_tests)` || exit 1; \ - log_list=`for i in $$bases; do echo $$i.log; done`; \ - log_list=`echo $$log_list`; \ - $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ - am__force_recheck=am--force-recheck \ - TEST_LOGS="$$log_list"; \ - exit $$? -.test.log: - @p='$<'; \ - $(am__set_b); \ - $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) -@am__EXEEXT_TRUE@.test$(EXEEXT).log: -@am__EXEEXT_TRUE@ @p='$<'; \ -@am__EXEEXT_TRUE@ $(am__set_b); \ -@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ -@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ -@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ -@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) - -distdir: $(DISTFILES) - $(am__remove_distdir) - test -d "$(distdir)" || mkdir "$(distdir)" - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$(top_distdir)" distdir="$(distdir)" \ - dist-hook - -test -n "$(am__skip_mode_fix)" \ - || find "$(distdir)" -type d ! -perm -755 \ - -exec chmod u+rwx,go+rx {} \; -o \ - ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ - ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ - || chmod -R a+r "$(distdir)" -dist-gzip: distdir - tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz - $(am__post_remove_distdir) - -dist-bzip2: distdir - tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 - $(am__post_remove_distdir) - -dist-lzip: distdir - tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz - $(am__post_remove_distdir) - -dist-xz: distdir - tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz - $(am__post_remove_distdir) - -dist-tarZ: distdir - @echo WARNING: "Support for distribution archives compressed with" \ - "legacy program 'compress' is deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z - $(am__post_remove_distdir) - -dist-shar: distdir - @echo WARNING: "Support for shar distribution archives is" \ - "deprecated." >&2 - @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz - $(am__post_remove_distdir) - -dist-zip: distdir - -rm -f $(distdir).zip - zip -rq $(distdir).zip $(distdir) - $(am__post_remove_distdir) - -dist dist-all: - $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' - $(am__post_remove_distdir) - -# This target untars the dist file and tries a VPATH configuration. Then -# it guarantees that the distribution is self-contained by making another -# tarfile. -distcheck: dist - case '$(DIST_ARCHIVES)' in \ - *.tar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ - *.tar.bz2*) \ - bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ - *.tar.lz*) \ - lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ - *.tar.xz*) \ - xz -dc $(distdir).tar.xz | $(am__untar) ;;\ - *.tar.Z*) \ - uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ - *.shar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ - *.zip*) \ - unzip $(distdir).zip ;;\ - esac - chmod -R a-w $(distdir) - chmod u+w $(distdir) - mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst - chmod a-w $(distdir) - test -d $(distdir)/_build || exit 0; \ - dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ - && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ - && am__cwd=`pwd` \ - && $(am__cd) $(distdir)/_build/sub \ - && ../../configure \ - $(AM_DISTCHECK_CONFIGURE_FLAGS) \ - $(DISTCHECK_CONFIGURE_FLAGS) \ - --srcdir=../.. --prefix="$$dc_install_base" \ - && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ - && $(MAKE) $(AM_MAKEFLAGS) check \ - && $(MAKE) $(AM_MAKEFLAGS) install \ - && $(MAKE) $(AM_MAKEFLAGS) installcheck \ - && $(MAKE) $(AM_MAKEFLAGS) uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ - distuninstallcheck \ - && chmod -R a-w "$$dc_install_base" \ - && ({ \ - (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ - && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ - distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ - } || { rm -rf "$$dc_destdir"; exit 1; }) \ - && rm -rf "$$dc_destdir" \ - && $(MAKE) $(AM_MAKEFLAGS) dist \ - && rm -rf $(DIST_ARCHIVES) \ - && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ - && cd "$$am__cwd" \ - || exit 1 - $(am__post_remove_distdir) - @(echo "$(distdir) archives ready for distribution: "; \ - list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ - sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' -distuninstallcheck: - @test -n '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: trying to run $@ with an empty' \ - '$$(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - $(am__cd) '$(distuninstallcheck_dir)' || { \ - echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ - exit 1; \ - }; \ - test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left after uninstall:" ; \ - if test -n "$(DESTDIR)"; then \ - echo " (check DESTDIR support)"; \ - fi ; \ - $(distuninstallcheck_listfiles) ; \ - exit 1; } >&2 -distcleancheck: distclean - @if test '$(srcdir)' = . ; then \ - echo "ERROR: distcleancheck can only run from a VPATH build" ; \ - exit 1 ; \ - fi - @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ - || { echo "ERROR: files left in build directory after distclean:" ; \ - $(distcleancheck_listfiles) ; \ - exit 1; } >&2 -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(check_SCRIPTS) \ - $(dist_check_DATA) - $(MAKE) $(AM_MAKEFLAGS) check-TESTS -check: check-am -all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) - -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) - -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -rm -f cplusplus/$(DEPDIR)/$(am__dirstamp) - -rm -f cplusplus/$(am__dirstamp) - -rm -f cudd/$(DEPDIR)/$(am__dirstamp) - -rm -f cudd/$(am__dirstamp) - -rm -f dddmp/$(DEPDIR)/$(am__dirstamp) - -rm -f dddmp/$(am__dirstamp) - -rm -f epd/$(DEPDIR)/$(am__dirstamp) - -rm -f epd/$(am__dirstamp) - -rm -f mtr/$(DEPDIR)/$(am__dirstamp) - -rm -f mtr/$(am__dirstamp) - -rm -f nanotrav/$(DEPDIR)/$(am__dirstamp) - -rm -f nanotrav/$(am__dirstamp) - -rm -f st/$(DEPDIR)/$(am__dirstamp) - -rm -f st/$(am__dirstamp) - -rm -f util/$(DEPDIR)/$(am__dirstamp) - -rm -f util/$(am__dirstamp) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ - clean-libtool clean-noinstLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf cplusplus/$(DEPDIR) cudd/$(DEPDIR) dddmp/$(DEPDIR) epd/$(DEPDIR) mtr/$(DEPDIR) nanotrav/$(DEPDIR) st/$(DEPDIR) util/$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-includeHEADERS - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf cplusplus/$(DEPDIR) cudd/$(DEPDIR) dddmp/$(DEPDIR) epd/$(DEPDIR) mtr/$(DEPDIR) nanotrav/$(DEPDIR) st/$(DEPDIR) util/$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES - -.MAKE: all check-am install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-TESTS \ - check-am clean clean-checkPROGRAMS clean-cscope clean-generic \ - clean-libLTLIBRARIES clean-libtool clean-noinstLTLIBRARIES \ - cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ - dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \ - dist-zip distcheck distclean distclean-compile \ - distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-includeHEADERS install-info install-info-am \ - install-libLTLIBRARIES install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - recheck tags tags-am uninstall uninstall-am \ - uninstall-includeHEADERS uninstall-libLTLIBRARIES - -.PRECIOUS: Makefile - - -cudd/test_cudd.test: cudd/test_cudd.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -st/test_st.test: st/test_st.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -mtr/test_mtr.test: mtr/test_mtr.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -dddmp/test_dddmp.test: dddmp/test_dddmp.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -cplusplus/test_obj.test: cplusplus/test_obj.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -nanotrav/test_ntrv.test: nanotrav/test_ntrv.test.in Makefile - $(do_subst) $< > $@ - chmod +x $@ - -@HAVE_PDFLATEX_TRUE@doc/cudd.pdf: doc/cudd.tex $(top_srcdir)/doc/phase.pdf -@HAVE_PDFLATEX_TRUE@ @if $(AM_V_P); then dest='2>&1'; else dest='> /dev/null 2>&1'; fi; \ -@HAVE_PDFLATEX_TRUE@ cd doc && eval "$(PDFLATEX) cudd $${dest}" && \ -@HAVE_PDFLATEX_TRUE@ eval "$(MAKEINDEX) cudd $${dest}" && \ -@HAVE_PDFLATEX_TRUE@ eval "$(PDFLATEX) cudd $${dest}" && \ -@HAVE_PDFLATEX_TRUE@ eval "$(PDFLATEX) cudd $${dest}" - -@HAVE_PDFLATEX_FALSE@doc/cudd.pdf: - -dist-hook: - rm -rf `find $(distdir) -name .svn` - -.PHONY : - -all: html/index.html doc/cudd.pdf - -#if HAVE_DOXYGEN -# -#html/index.html: Doxyfile $(lib_LTLIBRARIES) -# @if $(AM_V_P); then dest='2>&1'; else dest='> /dev/null 2>&1'; fi; \ -# eval "$(DOXYGEN) $< $${dest}" -# -#clean-local: -# rm -rf html doxygen_sqlite3.db -# -#else - -html/index.html: - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/resources/3rdparty/cudd-3.0.0/aclocal.m4 b/resources/3rdparty/cudd-3.0.0/aclocal.m4 deleted file mode 100644 index 0de6688a7..000000000 --- a/resources/3rdparty/cudd-3.0.0/aclocal.m4 +++ /dev/null @@ -1,1256 +0,0 @@ -# generated automatically by aclocal 1.15 -*- Autoconf -*- - -# Copyright (C) 1996-2014 Free Software Foundation, Inc. - -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. -You have another version of autoconf. It may work, but is not guaranteed to. -If you have problems, you may need to regenerate the build system entirely. -To do so, use the procedure documented by the package, typically 'autoreconf'.])]) - -# Copyright (C) 2002-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.15' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.15], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.15])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) - -# Copyright (C) 2011-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_AR([ACT-IF-FAIL]) -# ------------------------- -# Try to determine the archiver interface, and trigger the ar-lib wrapper -# if it is needed. If the detection of archiver interface fails, run -# ACT-IF-FAIL (default is to abort configure with a proper error message). -AC_DEFUN([AM_PROG_AR], -[AC_BEFORE([$0], [LT_INIT])dnl -AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl -AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([ar-lib])dnl -AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) -: ${AR=ar} - -AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], - [AC_LANG_PUSH([C]) - am_cv_ar_interface=ar - AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], - [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' - AC_TRY_EVAL([am_ar_try]) - if test "$ac_status" -eq 0; then - am_cv_ar_interface=ar - else - am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' - AC_TRY_EVAL([am_ar_try]) - if test "$ac_status" -eq 0; then - am_cv_ar_interface=lib - else - am_cv_ar_interface=unknown - fi - fi - rm -f conftest.lib libconftest.a - ]) - AC_LANG_POP([C])]) - -case $am_cv_ar_interface in -ar) - ;; -lib) - # Microsoft lib, so override with the ar-lib wrapper script. - # FIXME: It is wrong to rewrite AR. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__AR in this case, - # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something - # similar. - AR="$am_aux_dir/ar-lib $AR" - ;; -unknown) - m4_default([$1], - [AC_MSG_ERROR([could not determine $AR interface])]) - ;; -esac -AC_SUBST([AR])dnl -]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to -# '$srcdir', '$srcdir/..', or '$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is '.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` -]) - -# AM_COND_IF -*- Autoconf -*- - -# Copyright (C) 2008-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_COND_IF -# _AM_COND_ELSE -# _AM_COND_ENDIF -# -------------- -# These macros are only used for tracing. -m4_define([_AM_COND_IF]) -m4_define([_AM_COND_ELSE]) -m4_define([_AM_COND_ENDIF]) - -# AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) -# --------------------------------------- -# If the shell condition COND is true, execute IF-TRUE, otherwise execute -# IF-FALSE. Allow automake to learn about conditional instantiating macros -# (the AC_CONFIG_FOOS). -AC_DEFUN([AM_COND_IF], -[m4_ifndef([_AM_COND_VALUE_$1], - [m4_fatal([$0: no such condition "$1"])])dnl -_AM_COND_IF([$1])dnl -if test -z "$$1_TRUE"; then : - m4_n([$2])[]dnl -m4_ifval([$3], -[_AM_COND_ELSE([$1])dnl -else - $3 -])dnl -_AM_COND_ENDIF([$1])dnl -fi[]dnl -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ([2.52])dnl - m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Copyright (C) 1999-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - - -# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be -# written in clear, in which case automake, when reading aclocal.m4, -# will think it sees a *use*, and therefore will trigger all it's -# C support machinery. Also note that it means that autoscan, seeing -# CC etc. in the Makefile, will ask for an AC_PROG_CC use... - - -# _AM_DEPENDENCIES(NAME) -# ---------------------- -# See how the compiler implements dependency checking. -# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". -# We try a few techniques and use that to set a single cache variable. -# -# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was -# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular -# dependency, and given that the user is not expected to run this macro, -# just rely on AC_PROG_CC. -AC_DEFUN([_AM_DEPENDENCIES], -[AC_REQUIRE([AM_SET_DEPDIR])dnl -AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl -AC_REQUIRE([AM_MAKE_INCLUDE])dnl -AC_REQUIRE([AM_DEP_TRACK])dnl - -m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], - [$1], [CXX], [depcc="$CXX" am_compiler_list=], - [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], - [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], - [$1], [UPC], [depcc="$UPC" am_compiler_list=], - [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], - [depcc="$$1" am_compiler_list=]) - -AC_CACHE_CHECK([dependency style of $depcc], - [am_cv_$1_dependencies_compiler_type], -[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_$1_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` - fi - am__universal=false - m4_case([$1], [CC], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac], - [CXX], - [case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac]) - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_$1_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_$1_dependencies_compiler_type=none -fi -]) -AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) -AM_CONDITIONAL([am__fastdep$1], [ - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) -]) - - -# AM_SET_DEPDIR -# ------------- -# Choose a directory name for dependency files. -# This macro is AC_REQUIREd in _AM_DEPENDENCIES. -AC_DEFUN([AM_SET_DEPDIR], -[AC_REQUIRE([AM_SET_LEADING_DOT])dnl -AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl -]) - - -# AM_DEP_TRACK -# ------------ -AC_DEFUN([AM_DEP_TRACK], -[AC_ARG_ENABLE([dependency-tracking], [dnl -AS_HELP_STRING( - [--enable-dependency-tracking], - [do not reject slow dependency extractors]) -AS_HELP_STRING( - [--disable-dependency-tracking], - [speeds up one-time build])]) -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi -AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) -AC_SUBST([AMDEPBACKSLASH])dnl -_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl -AC_SUBST([am__nodep])dnl -_AM_SUBST_NOTMAKE([am__nodep])dnl -]) - -# Generate code to set up dependency tracking. -*- Autoconf -*- - -# Copyright (C) 1999-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - - -# _AM_OUTPUT_DEPENDENCY_COMMANDS -# ------------------------------ -AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[{ - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac - shift - for mf - do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done - done -} -])# _AM_OUTPUT_DEPENDENCY_COMMANDS - - -# AM_OUTPUT_DEPENDENCY_COMMANDS -# ----------------------------- -# This macro should only be invoked once -- use via AC_REQUIRE. -# -# This code is only required when automatic dependency tracking -# is enabled. FIXME. This creates each '.P' file that we will -# need in order to bootstrap the dependency handling code. -AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], -[AC_CONFIG_COMMANDS([depfiles], - [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], - [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) -]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. -m4_define([AC_PROG_CC], -m4_defn([AC_PROG_CC]) -[_AM_PROG_CC_C_O -]) - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.65])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[AC_DIAGNOSE([obsolete], - [$0: two- and three-arguments forms are deprecated.]) -m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if( - m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), - [ok:ok],, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) - AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) -AM_MISSING_PROG([AUTOCONF], [autoconf]) -AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) -AM_MISSING_PROG([AUTOHEADER], [autoheader]) -AM_MISSING_PROG([MAKEINFO], [makeinfo]) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -AC_SUBST([mkdir_p], ['$(MKDIR_P)']) -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES([CC])], - [m4_define([AC_PROG_CC], - m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES([CXX])], - [m4_define([AC_PROG_CXX], - m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES([OBJC])], - [m4_define([AC_PROG_OBJC], - m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], - [_AM_DEPENDENCIES([OBJCXX])], - [m4_define([AC_PROG_OBJCXX], - m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl -]) -AC_REQUIRE([AM_SILENT_RULES])dnl -dnl The testsuite driver may need to know about EXEEXT, so add the -dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This -dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl - -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) - fi -fi -dnl The trailing newline in this macro's definition is deliberate, for -dnl backward compatibility and to allow trailing 'dnl'-style comments -dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. -]) - -dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not -dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further -dnl mangled by Autoconf and run in a shell conditional statement. -m4_define([_AC_COMPILER_EXEEXT], -m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST([install_sh])]) - -# Copyright (C) 2003-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# Check whether the underlying file-system supports filenames -# with a leading dot. For instance MS-DOS doesn't. -AC_DEFUN([AM_SET_LEADING_DOT], -[rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null -AC_SUBST([am__leading_dot])]) - -# Check to see how 'make' treats includes. -*- Autoconf -*- - -# Copyright (C) 2001-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MAKE_INCLUDE() -# ----------------- -# Check to see how make treats includes. -AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo this is the am__doit target -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -AC_MSG_CHECKING([for style of include used by $am_make]) -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi -AC_SUBST([am__include]) -AC_SUBST([am__quote]) -AC_MSG_RESULT([$_am_result]) -rm -f confinc confmf -]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it is modern enough. -# If it is, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - AC_MSG_WARN(['missing' script is too old or missing]) -fi -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# -------------------- -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) - -# _AM_SET_OPTIONS(OPTIONS) -# ------------------------ -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Copyright (C) 1999-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_CC_C_O -# --------------- -# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC -# to automatically call this. -AC_DEFUN([_AM_PROG_CC_C_O], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([compile])dnl -AC_LANG_PUSH([C])dnl -AC_CACHE_CHECK( - [whether $CC understands -c and -o together], - [am_cv_prog_cc_c_o], - [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i]) -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -AC_LANG_POP([C])]) - -# For backward compatibility. -AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) - -# Copyright (C) 2001-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_RUN_LOG(COMMAND) -# ------------------- -# Run COMMAND, save the exit status in ac_status, and log it. -# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) -AC_DEFUN([AM_RUN_LOG], -[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD - ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD - (exit $ac_status); }]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken - alias in your environment]) - fi - if test "$[2]" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -AC_MSG_RESULT([yes]) -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & - am_sleep_pid=$! -fi -AC_CONFIG_COMMANDS_PRE( - [AC_MSG_CHECKING([that generated files are newer than configure]) - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - AC_MSG_RESULT([done])]) -rm -f conftest.file -]) - -# Copyright (C) 2009-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_SILENT_RULES([DEFAULT]) -# -------------------------- -# Enable less verbose build rules; with the default set to DEFAULT -# ("yes" being less verbose, "no" or empty being verbose). -AC_DEFUN([AM_SILENT_RULES], -[AC_ARG_ENABLE([silent-rules], [dnl -AS_HELP_STRING( - [--enable-silent-rules], - [less verbose build output (undo: "make V=1")]) -AS_HELP_STRING( - [--disable-silent-rules], - [verbose build output (undo: "make V=0")])dnl -]) -case $enable_silent_rules in @%:@ ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; -esac -dnl -dnl A few 'make' implementations (e.g., NonStop OS and NextStep) -dnl do not support nested variable expansions. -dnl See automake bug#9928 and bug#10237. -am_make=${MAKE-make} -AC_CACHE_CHECK([whether $am_make supports nested variables], - [am_cv_make_support_nested_variables], - [if AS_ECHO([['TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi]) -if test $am_cv_make_support_nested_variables = yes; then - dnl Using '$V' instead of '$(V)' breaks IRIX make. - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -AC_SUBST([AM_V])dnl -AM_SUBST_NOTMAKE([AM_V])dnl -AC_SUBST([AM_DEFAULT_V])dnl -AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl -AC_SUBST([AM_DEFAULT_VERBOSITY])dnl -AM_BACKSLASH='\' -AC_SUBST([AM_BACKSLASH])dnl -_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl -]) - -# Copyright (C) 2001-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor 'install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in "make install-strip", and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# -------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004-2014 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of 'v7', 'ustar', or 'pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -# -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AC_SUBST([AMTAR], ['$${TAR-tar}']) - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' - -m4_if([$1], [v7], - [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], - - [m4_case([$1], - [ustar], - [# The POSIX 1988 'ustar' format is defined with fixed-size fields. - # There is notably a 21 bits limit for the UID and the GID. In fact, - # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 - # and bug#13588). - am_max_uid=2097151 # 2^21 - 1 - am_max_gid=$am_max_uid - # The $UID and $GID variables are not portable, so we need to resort - # to the POSIX-mandated id(1) utility. Errors in the 'id' calls - # below are definitely unexpected, so allow the users to see them - # (that is, avoid stderr redirection). - am_uid=`id -u || echo unknown` - am_gid=`id -g || echo unknown` - AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) - if test $am_uid -le $am_max_uid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi - AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) - if test $am_gid -le $am_max_gid; then - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - _am_tools=none - fi], - - [pax], - [], - - [m4_fatal([Unknown tar format])]) - - AC_MSG_CHECKING([how to create a $1 tar archive]) - - # Go ahead even if we have the value already cached. We do so because we - # need to set the values for the 'am__tar' and 'am__untar' variables. - _am_tools=${am_cv_prog_tar_$1-$_am_tools} - - for _am_tool in $_am_tools; do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works. - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi - done - rm -rf conftest.dir - - AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) - AC_MSG_RESULT([$am_cv_prog_tar_$1])]) - -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - -m4_include([m4/libtool.m4]) -m4_include([m4/ltoptions.m4]) -m4_include([m4/ltsugar.m4]) -m4_include([m4/ltversion.m4]) -m4_include([m4/lt~obsolete.m4]) -m4_include([m4/modern_cxx.m4]) -m4_include([m4/w32.m4]) diff --git a/resources/3rdparty/cudd-3.0.0/configure b/resources/3rdparty/cudd-3.0.0/configure deleted file mode 100755 index ef3832be0..000000000 --- a/resources/3rdparty/cudd-3.0.0/configure +++ /dev/null @@ -1,19902 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for cudd 3.0.0. -# -# Report bugs to . -# -# -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. -# -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org and Fabio@Colorado.EDU -$0: about your system, including any error possibly output -$0: before this message. Then install a modern shell, or -$0: manually run the script under such a shell if you do -$0: have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - -SHELL=${CONFIG_SHELL-/bin/sh} - - -test -n "$DJDIR" || exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='cudd' -PACKAGE_TARNAME='cudd' -PACKAGE_VERSION='3.0.0' -PACKAGE_STRING='cudd 3.0.0' -PACKAGE_BUGREPORT='Fabio@Colorado.EDU' -PACKAGE_URL='' - -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_unique_file="st/st.c" -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -LIBOBJS -MINGW64_FALSE -MINGW64_TRUE -HAVE_PTHREADS_FALSE -HAVE_PTHREADS_TRUE -HAVE_PDFLATEX_FALSE -HAVE_PDFLATEX_TRUE -MAKEINDEX -PDFLATEX -HAVE_DOXYGEN_FALSE -HAVE_DOXYGEN_TRUE -DOXYGEN -CROSS_COMPILING_FALSE -CROSS_COMPILING_TRUE -CXXCPP -CPP -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -MANIFEST_TOOL -RANLIB -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -EGREP -GREP -SED -LIBTOOL -OBJDUMP -DLLTOOL -AS -ac_ct_AR -AR -am__fastdepCXX_FALSE -am__fastdepCXX_TRUE -CXXDEPMODE -ac_ct_CXX -CXXFLAGS -CXX -am__fastdepCC_FALSE -am__fastdepCC_TRUE -CCDEPMODE -am__nodep -AMDEPBACKSLASH -AMDEP_FALSE -AMDEP_TRUE -am__quote -am__include -DEPDIR -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -OBJ_FALSE -OBJ_TRUE -DDDMP_FALSE -DDDMP_TRUE -AM_BACKSLASH -AM_DEFAULT_VERBOSITY -AM_DEFAULT_V -AM_V -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -runstatedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_silent_rules -enable_dddmp -enable_obj -with_system_qsort -enable_dependency_tracking -enable_shared -enable_static -with_pic -enable_fast_install -with_gnu_ld -with_sysroot -enable_libtool_lock -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CXX -CXXFLAGS -CCC -CPP -CXXCPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures cudd 3.0.0 to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/cudd] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of cudd 3.0.0:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-silent-rules less verbose build output (undo: "make V=1") - --disable-silent-rules verbose build output (undo: "make V=0") - --enable-dddmp include libdddmp in libcudd - --enable-obj include libobj in libcudd - --enable-dependency-tracking - do not reject slow dependency extractors - --disable-dependency-tracking - speeds up one-time build - --enable-shared[=PKGS] build shared libraries [default=no] - --enable-static[=PKGS] build static libraries [default=yes] - --enable-fast-install[=PKGS] - optimize for fast installation [default=yes] - --disable-libtool-lock avoid locking (might break parallel builds) - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-system-qsort use system qsort instead of portable one - --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use - both] - --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-sysroot=DIR Search for dependent libraries within DIR - (or the compiler's sysroot if not specified). - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CXX C++ compiler command - CXXFLAGS C++ compiler flags - CPP C preprocessor - CXXCPP C++ preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to . -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -cudd configure 3.0.0 -generated by GNU Autoconf 2.69 - -Copyright (C) 2012 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_cxx_try_compile LINENO -# ---------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_compile - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_func - -# ac_fn_cxx_try_cpp LINENO -# ------------------------ -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { - test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_cpp - -# ac_fn_cxx_try_link LINENO -# ------------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_cxx_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_cxx_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_cxx_try_link - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval \${$3+:} false; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.i conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## --------------------------------- ## -## Report this to Fabio@Colorado.EDU ## -## --------------------------------- ##" - ) | sed "s/^/$as_me: WARNING: /" >&2 - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_type - -# ac_fn_c_find_uintX_t LINENO BITS VAR -# ------------------------------------ -# Finds an unsigned integer type with width BITS, setting cache variable VAR -# accordingly. -ac_fn_c_find_uintX_t () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 -$as_echo_n "checking for uint$2_t... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - # Order is important - never check a type that is potentially smaller - # than half of the expected target width. - for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ - 'unsigned long long int' 'unsigned short int' 'unsigned char'; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ -static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - case $ac_type in #( - uint$2_t) : - eval "$3=yes" ;; #( - *) : - eval "$3=\$ac_type" ;; -esac -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if eval test \"x\$"$3"\" = x"no"; then : - -else - break -fi - done -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_find_uintX_t - -# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES -# -------------------------------------------- -# Tries to find the compile-time value of EXPR in a program that includes -# INCLUDES, setting VAR accordingly. Returns whether the value could be -# computed -ac_fn_c_compute_int () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=0 ac_mid=0 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid; break -else - as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=-1 ac_mid=-1 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=$ac_mid; break -else - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - ac_lo= ac_hi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0; -return test_array [0]; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid -else - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in #(( -?*) eval "$3=\$ac_lo"; ac_retval=0 ;; -'') ac_retval=1 ;; -esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - return 1; - if (($2) < 0) - { - long int i = longval (); - if (i != ($2)) - return 1; - fprintf (f, "%ld", i); - } - else - { - unsigned long int i = ulongval (); - if (i != ($2)) - return 1; - fprintf (f, "%lu", i); - } - /* Do not output a trailing newline, as this causes \r\n confusion - on some platforms. */ - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - echo >>conftest.val; read $3 config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by cudd $as_me 3.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - $as_echo "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - $as_echo "## ----------------- ## -## Output variables. ## -## ----------------- ##" - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - $as_echo "## ----------- ## -## confdefs.h. ## -## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special files - # actually), so we avoid doing that. DJGPP emulates it as a regular file. - if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -ac_aux_dir= -for ac_dir in build-aux "$srcdir"/build-aux; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi -done -if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - - -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` -test "x$ac_build_alias" = x && - as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - -am__api_version='1.15' - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -$as_echo_n "checking whether build environment is sane... " >&6; } -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; -esac - -# Do 'set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - am_has_slept=no - for am_try in 1 2; do - echo "timestamp, slept: $am_has_slept" > conftest.file - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - if test "$*" != "X $srcdir/configure conftest.file" \ - && test "$*" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - as_fn_error $? "ls -t appears to fail. Make sure there is not a broken - alias in your environment" "$LINENO" 5 - fi - if test "$2" = conftest.file || test $am_try -eq 2; then - break - fi - # Just in case. - sleep 1 - am_has_slept=yes - done - test "$2" = conftest.file - ) -then - # Ok. - : -else - as_fn_error $? "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -# If we didn't sleep, we still need to ensure time stamps of config.status and -# generated files are strictly newer. -am_sleep_pid= -if grep 'slept: no' conftest.file >/dev/null 2>&1; then - ( sleep 1 ) & - am_sleep_pid=$! -fi - -rm -f conftest.file - -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was `s,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` - -# Expand $ac_aux_dir to an absolute path. -am_aux_dir=`cd "$ac_aux_dir" && pwd` - -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --is-lightweight"; then - am_missing_run="$MISSING " -else - am_missing_run= - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using 'strip' when the user -# run "make install-strip". However 'strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the 'STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 -$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if ${ac_cv_path_mkdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - -fi - - test -d ./--version && rmdir ./--version - if test "${ac_cv_path_mkdir+set}" = set; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - MKDIR_P="$ac_install_sh -d" - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AWK+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - SET_MAKE= -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -# Check whether --enable-silent-rules was given. -if test "${enable_silent_rules+set}" = set; then : - enableval=$enable_silent_rules; -fi - -case $enable_silent_rules in # ((( - yes) AM_DEFAULT_VERBOSITY=0;; - no) AM_DEFAULT_VERBOSITY=1;; - *) AM_DEFAULT_VERBOSITY=1;; -esac -am_make=${MAKE-make} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -$as_echo_n "checking whether $am_make supports nested variables... " >&6; } -if ${am_cv_make_support_nested_variables+:} false; then : - $as_echo_n "(cached) " >&6 -else - if $as_echo 'TRUE=$(BAR$(V)) -BAR0=false -BAR1=true -V=1 -am__doit: - @$(TRUE) -.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then - am_cv_make_support_nested_variables=yes -else - am_cv_make_support_nested_variables=no -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -$as_echo "$am_cv_make_support_nested_variables" >&6; } -if test $am_cv_make_support_nested_variables = yes; then - AM_V='$(V)' - AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' -else - AM_V=$AM_DEFAULT_VERBOSITY - AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY -fi -AM_BACKSLASH='\' - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='cudd' - VERSION='3.0.0' - - -cat >>confdefs.h <<_ACEOF -#define PACKAGE "$PACKAGE" -_ACEOF - - -cat >>confdefs.h <<_ACEOF -#define VERSION "$VERSION" -_ACEOF - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# For better backward compatibility. To be removed once Automake 1.9.x -# dies out for good. For more background, see: -# -# -mkdir_p='$(MKDIR_P)' - -# We need awk for the "check" target (and possibly the TAP driver). The -# system "awk" is bad on some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - - -# We'll loop over all known methods to create a tar archive until one works. -_am_tools='gnutar pax cpio none' - -am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' - - - - - - -# POSIX will say in a future version that running "rm -f" with no argument -# is OK; and we want to be able to make that assumption in our Makefile -# recipes. So use an aggressive probe to check that the usage we want is -# actually supported "in the wild" to an acceptable degree. -# See automake bug#10828. -# To make any issue more visible, cause the running configure to be aborted -# by default if the 'rm' program in use doesn't match our expectations; the -# user can still override this though. -if rm -f && rm -fr && rm -rf; then : OK; else - cat >&2 <<'END' -Oops! - -Your 'rm' program seems unable to run without file operands specified -on the command line, even when the '-f' option is present. This is contrary -to the behaviour of most rm programs out there, and not conforming with -the upcoming POSIX standard: - -Please tell bug-automake@gnu.org about your system, including the value -of your $PATH and any error possibly output before this message. This -can help us improve future automake versions. - -END - if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then - echo 'Configuration will proceed anyway, since you have set the' >&2 - echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 - echo >&2 - else - cat >&2 <<'END' -Aborting the configuration process, to ensure you take notice of the issue. - -You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . - -If you want to complete the configuration process using your problematic -'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM -to "yes", and re-run configure. - -END - as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 - fi -fi - - - -# Check whether --enable-dddmp was given. -if test "${enable_dddmp+set}" = set; then : - enableval=$enable_dddmp; -fi - - if test x$enable_dddmp = xyes; then - DDDMP_TRUE= - DDDMP_FALSE='#' -else - DDDMP_TRUE='#' - DDDMP_FALSE= -fi - - -# Check whether --enable-obj was given. -if test "${enable_obj+set}" = set; then : - enableval=$enable_obj; -fi - - if test x$enable_obj = xyes; then - OBJ_TRUE= - OBJ_FALSE='#' -else - OBJ_TRUE='#' - OBJ_FALSE= -fi - - - -# Check whether --with-system-qsort was given. -if test "${with_system_qsort+set}" = set; then : - withval=$with_system_qsort; -else - with_system_qsort=no -fi - -if test x$with_system_qsort != xno ; then - -$as_echo "#define USE_SYSTEM_QSORT 1" >>confdefs.h - -fi - -# Set our own default (instead of "-g -O2") unless CFLAGS is already defined. -: ${CFLAGS="-Wall -Wextra -g -O3"} -: ${CXXFLAGS="-Wall -Wextra -std=c++0x -g -O3"} - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -if test -z "$ac_file"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -$as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -ac_exeext=$ac_cv_exeext - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -FILE *f = fopen ("conftest.out", "w"); - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -ac_clean_files="$ac_clean_files conftest.out" -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -if test "$cross_compiling" != yes; then - { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if { ac_try='./conftest$ac_cv_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out -ac_clean_files=$ac_clean_files_save -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -struct stat; -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 -$as_echo_n "checking whether $CC understands -c and -o together... " >&6; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF - # Make sure it works both with $CC and with simple cc. - # Following AC_PROG_CC_C_O, we do the test twice because some - # compilers refuse to overwrite an existing .o file with -o, - # though they will create one. - am_cv_prog_cc_c_o=yes - for am_i in 1 2; do - if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 - ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } \ - && test -f conftest2.$ac_objext; then - : OK - else - am_cv_prog_cc_c_o=no - break - fi - done - rm -f core conftest* - unset am_i -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } -if test "$am_cv_prog_cc_c_o" != yes; then - # Losing compiler, so override with the script. - # FIXME: It is wrong to rewrite CC. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__CC in this case, - # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" - CC="$am_aux_dir/compile $CC" -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -DEPDIR="${am__leading_dot}deps" - -ac_config_commands="$ac_config_commands depfiles" - - -am_make=${MAKE-make} -cat > confinc << 'END' -am__doit: - @echo this is the am__doit target -.PHONY: am__doit -END -# If we don't find an include directive, just comment out the code. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 -$as_echo_n "checking for style of include used by $am_make... " >&6; } -am__include="#" -am__quote= -_am_result=none -# First try GNU make style include. -echo "include confinc" > confmf -# Ignore all kinds of additional output from 'make'. -case `$am_make -s -f confmf 2> /dev/null` in #( -*the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU - ;; -esac -# Now try BSD make style include. -if test "$am__include" = "#"; then - echo '.include "confinc"' > confmf - case `$am_make -s -f confmf 2> /dev/null` in #( - *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD - ;; - esac -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 -$as_echo "$_am_result" >&6; } -rm -f confinc confmf - -# Check whether --enable-dependency-tracking was given. -if test "${enable_dependency_tracking+set}" = set; then : - enableval=$enable_dependency_tracking; -fi - -if test "x$enable_dependency_tracking" != xno; then - am_depcomp="$ac_aux_dir/depcomp" - AMDEPBACKSLASH='\' - am__nodep='_no' -fi - if test "x$enable_dependency_tracking" != xno; then - AMDEP_TRUE= - AMDEP_FALSE='#' -else - AMDEP_TRUE='#' - AMDEP_FALSE= -fi - - - -depcc="$CC" am_compiler_list= - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CC_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CC_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CC_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CC_dependencies_compiler_type=none -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } -CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then - am__fastdepCC_TRUE= - am__fastdepCC_FALSE='#' -else - am__fastdepCC_TRUE='#' - am__fastdepCC_FALSE= -fi - - - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -if test -z "$CXX"; then - if test -n "$CCC"; then - CXX=$CCC - else - if test -n "$ac_tool_prefix"; then - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CXX"; then - ac_cv_prog_CXX="$CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CXX=$ac_cv_prog_CXX -if test -n "$CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -$as_echo "$CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CXX" && break - done -fi -if test -z "$CXX"; then - ac_ct_CXX=$CXX - for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CXX"; then - ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CXX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CXX=$ac_cv_prog_ac_ct_CXX -if test -n "$ac_ct_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -$as_echo "$ac_ct_CXX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CXX" && break -done - - if test "x$ac_ct_CXX" = x; then - CXX="g++" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CXX=$ac_ct_CXX - fi -fi - - fi -fi -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 -$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } -if ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GXX=yes -else - GXX= -fi -ac_test_CXXFLAGS=${CXXFLAGS+set} -ac_save_CXXFLAGS=$CXXFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 -$as_echo_n "checking whether $CXX accepts -g... " >&6; } -if ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_cxx_werror_flag=$ac_cxx_werror_flag - ac_cxx_werror_flag=yes - ac_cv_prog_cxx_g=no - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -else - CXXFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - -else - ac_cxx_werror_flag=$ac_save_cxx_werror_flag - CXXFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_prog_cxx_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -$as_echo "$ac_cv_prog_cxx_g" >&6; } -if test "$ac_test_CXXFLAGS" = set; then - CXXFLAGS=$ac_save_CXXFLAGS -elif test $ac_cv_prog_cxx_g = yes; then - if test "$GXX" = yes; then - CXXFLAGS="-g -O2" - else - CXXFLAGS="-g" - fi -else - if test "$GXX" = yes; then - CXXFLAGS="-O2" - else - CXXFLAGS= - fi -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -depcc="$CXX" am_compiler_list= - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 -$as_echo_n "checking dependency style of $depcc... " >&6; } -if ${am_cv_CXX_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then - # We make a subdir and do the tests there. Otherwise we can end up - # making bogus files that we don't know about and never remove. For - # instance it was reported that on HP-UX the gcc test will end up - # making a dummy file named 'D' -- because '-MD' means "put the output - # in D". - rm -rf conftest.dir - mkdir conftest.dir - # Copy depcomp to subdir because otherwise we won't find it if we're - # using a relative directory. - cp "$am_depcomp" conftest.dir - cd conftest.dir - # We will build objects and dependencies in a subdirectory because - # it helps to detect inapplicable dependency modes. For instance - # both Tru64's cc and ICC support -MD to output dependencies as a - # side effect of compilation, but ICC will put the dependencies in - # the current directory while Tru64 will put them in the object - # directory. - mkdir sub - - am_cv_CXX_dependencies_compiler_type=none - if test "$am_compiler_list" = ""; then - am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` - fi - am__universal=false - case " $depcc " in #( - *\ -arch\ *\ -arch\ *) am__universal=true ;; - esac - - for depmode in $am_compiler_list; do - # Setup a source with many dependencies, because some compilers - # like to wrap large dependency lists on column 80 (with \), and - # we should not choose a depcomp mode which is confused by this. - # - # We need to recreate these files for each test, as the compiler may - # overwrite some of them when testing with obscure command lines. - # This happens at least with the AIX C compiler. - : > sub/conftest.c - for i in 1 2 3 4 5 6; do - echo '#include "conftst'$i'.h"' >> sub/conftest.c - # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with - # Solaris 10 /bin/sh. - echo '/* dummy */' > sub/conftst$i.h - done - echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf - - # We check with '-c' and '-o' for the sake of the "dashmstdout" - # mode. It turns out that the SunPro C++ compiler does not properly - # handle '-M -o', and we need to detect this. Also, some Intel - # versions had trouble with output in subdirs. - am__obj=sub/conftest.${OBJEXT-o} - am__minus_obj="-o $am__obj" - case $depmode in - gcc) - # This depmode causes a compiler race in universal mode. - test "$am__universal" = false || continue - ;; - nosideeffect) - # After this tag, mechanisms are not by side-effect, so they'll - # only be used when explicitly requested. - if test "x$enable_dependency_tracking" = xyes; then - continue - else - break - fi - ;; - msvc7 | msvc7msys | msvisualcpp | msvcmsys) - # This compiler won't grok '-c -o', but also, the minuso test has - # not run yet. These depmodes are late enough in the game, and - # so weak that their functioning should not be impacted. - am__obj=conftest.${OBJEXT-o} - am__minus_obj= - ;; - none) break ;; - esac - if depmode=$depmode \ - source=sub/conftest.c object=$am__obj \ - depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ - $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ - >/dev/null 2>conftest.err && - grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && - grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && - grep $am__obj sub/conftest.Po > /dev/null 2>&1 && - ${MAKE-make} -s -f confmf > /dev/null 2>&1; then - # icc doesn't choke on unknown options, it will just issue warnings - # or remarks (even with -Werror). So we grep stderr for any message - # that says an option was ignored or not supported. - # When given -MP, icc 7.0 and 7.1 complain thusly: - # icc: Command line warning: ignoring option '-M'; no argument required - # The diagnosis changed in icc 8.0: - # icc: Command line remark: option '-MP' not supported - if (grep 'ignoring option' conftest.err || - grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else - am_cv_CXX_dependencies_compiler_type=$depmode - break - fi - fi - done - - cd .. - rm -rf conftest.dir -else - am_cv_CXX_dependencies_compiler_type=none -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 -$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } -CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type - - if - test "x$enable_dependency_tracking" != xno \ - && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then - am__fastdepCXX_TRUE= - am__fastdepCXX_FALSE='#' -else - am__fastdepCXX_TRUE='#' - am__fastdepCXX_FALSE= -fi - - - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar lib "link -lib" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar lib "link -lib" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 -$as_echo_n "checking the archiver ($AR) interface... " >&6; } -if ${am_cv_ar_interface+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - am_cv_ar_interface=ar - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int some_variable = 0; -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 - (eval $am_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -eq 0; then - am_cv_ar_interface=ar - else - am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 - (eval $am_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -eq 0; then - am_cv_ar_interface=lib - else - am_cv_ar_interface=unknown - fi - fi - rm -f conftest.lib libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 -$as_echo "$am_cv_ar_interface" >&6; } - -case $am_cv_ar_interface in -ar) - ;; -lib) - # Microsoft lib, so override with the ar-lib wrapper script. - # FIXME: It is wrong to rewrite AR. - # But if we don't then we get into trouble of one sort or another. - # A longer-term fix would be to have automake use am__AR in this case, - # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something - # similar. - AR="$am_aux_dir/ar-lib $AR" - ;; -unknown) - as_fn_error $? "could not determine $AR interface" "$LINENO" 5 - ;; -esac - - -case `pwd` in - *\ * | *\ *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.4.2' -macro_revision='1.3337' - - - - - - - - - - - - - -ltmain="$ac_aux_dir/ltmain.sh" - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -$as_echo_n "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case "$ECHO" in - printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -$as_echo "printf" >&6; } ;; - print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -$as_echo "print -r" >&6; } ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -$as_echo "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if ${ac_cv_path_SED+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_SED" || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if ${ac_cv_path_GREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if ${ac_cv_path_EGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -$as_echo_n "checking for fgrep... " >&6; } -if ${ac_cv_path_FGREP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in fgrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_FGREP" || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -$as_echo "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -$as_echo_n "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if ${lt_cv_path_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if ${lt_cv_prog_gnu_ld+:} false; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -$as_echo "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if ${lt_cv_path_NM+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM="$NM" -else - lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/$lt_tmp_nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS="$lt_save_ifs" - done - : ${lt_cv_path_NM=no} -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -$as_echo "$lt_cv_path_NM" >&6; } -if test "$lt_cv_path_NM" != "no"; then - NM="$lt_cv_path_NM" -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DUMPBIN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -$as_echo "$DUMPBIN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -$as_echo "$ac_ct_DUMPBIN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test "$DUMPBIN" != ":"; then - NM="$DUMPBIN" - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -$as_echo_n "checking the name lister ($NM) interface... " >&6; } -if ${lt_cv_nm_interface+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -$as_echo "$lt_cv_nm_interface" >&6; } - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -$as_echo_n "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -$as_echo "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -$as_echo_n "checking the maximum length of command line arguments... " >&6; } -if ${lt_cv_sys_max_cmd_len+:} false; then : - $as_echo_n "(cached) " >&6 -else - i=0 - teststring="ABCD" - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - os2*) - # The test takes a long time on OS/2. - lt_cv_sys_max_cmd_len=8192 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len" && \ - test undefined != "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8 ; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - -fi - -if test -n $lt_cv_sys_max_cmd_len ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -$as_echo "$lt_cv_sys_max_cmd_len" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 -$as_echo "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 -$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } -# Try some XSI features -xsi_shell=no -( _lt_dummy="a/b/c" - test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ - = c,a/b,b/c, \ - && eval 'test $(( 1 + 1 )) -eq 2 \ - && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ - && xsi_shell=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 -$as_echo "$xsi_shell" >&6; } - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 -$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } -lt_shell_append=no -( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ - >/dev/null 2>&1 \ - && lt_shell_append=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 -$as_echo "$lt_shell_append" >&6; } - - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 -$as_echo_n "checking how to convert $build file names to $host format... " >&6; } -if ${lt_cv_to_host_file_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 - ;; - esac - ;; - *-*-cygwin* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin - ;; - *-*-cygwin* ) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; - * ) # otherwise, assume *nix - lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin - ;; - esac - ;; - * ) # unhandled hosts (and "normal" native builds) - lt_cv_to_host_file_cmd=func_convert_file_noop - ;; -esac - -fi - -to_host_file_cmd=$lt_cv_to_host_file_cmd -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 -$as_echo "$lt_cv_to_host_file_cmd" >&6; } - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 -$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } -if ${lt_cv_to_tool_file_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - #assume ordinary cross tools, or native build. -lt_cv_to_tool_file_cmd=func_convert_file_noop -case $host in - *-*-mingw* ) - case $build in - *-*-mingw* ) # actually msys - lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 - ;; - esac - ;; -esac - -fi - -to_tool_file_cmd=$lt_cv_to_tool_file_cmd -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 -$as_echo "$lt_cv_to_tool_file_cmd" >&6; } - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -$as_echo_n "checking for $LD option to reload object files... " >&6; } -if ${lt_cv_ld_reload_flag+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_reload_flag='-r' -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -$as_echo "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - if test "$GCC" != yes; then - reload_cmds=false - fi - ;; - darwin*) - if test "$GCC" = yes; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -$as_echo "$OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -$as_echo "$ac_ct_OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -$as_echo_n "checking how to recognize dependent libraries... " >&6; } -if ${lt_cv_deplibs_check_method+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# `unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. -# 'file_magic [[regex]]' -- check by looking for files in library path -# which responds to the $file_magic_cmd with a given extended regex. -# If you have `file' or equivalent on your system and you're not sure -# whether `pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='/usr/bin/file -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. - if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - # Keep this pattern in sync with the one in func_win32_libid. - lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -$as_echo "$lt_cv_deplibs_check_method" >&6; } - -file_magic_glob= -want_nocaseglob=no -if test "$build" = "$host"; then - case $host_os in - mingw* | pw32*) - if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then - want_nocaseglob=yes - else - file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` - fi - ;; - esac -fi - -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -$as_echo "$DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -$as_echo "$ac_ct_DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 -$as_echo_n "checking how to associate runtime and link libraries... " >&6; } -if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_sharedlib_from_linklib_cmd='unknown' - -case $host_os in -cygwin* | mingw* | pw32* | cegcc*) - # two different shell functions defined in ltmain.sh - # decide which to use based on capabilities of $DLLTOOL - case `$DLLTOOL --help 2>&1` in - *--identify-strict*) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib - ;; - *) - lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback - ;; - esac - ;; -*) - # fallback: assume linklib IS sharedlib - lt_cv_sharedlib_from_linklib_cmd="$ECHO" - ;; -esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 -$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } -sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd -test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO - - - - - - - -if test -n "$ac_tool_prefix"; then - for ac_prog in ar - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AR="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AR" && break - done -fi -if test -z "$AR"; then - ac_ct_AR=$AR - for ac_prog in ar -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AR+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AR="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_AR" && break -done - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -fi - -: ${AR=ar} -: ${AR_FLAGS=cru} - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 -$as_echo_n "checking for archiver @FILE support... " >&6; } -if ${lt_cv_ar_at_file+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ar_at_file=no - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - echo conftest.$ac_objext > conftest.lst - lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -eq 0; then - # Ensure the archiver fails upon bogus file names. - rm -f conftest.$ac_objext libconftest.a - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 - (eval $lt_ar_try) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - if test "$ac_status" -ne 0; then - lt_cv_ar_at_file=@ - fi - fi - rm -f conftest.* libconftest.a - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 -$as_echo "$lt_cv_ar_at_file" >&6; } - -if test "x$lt_cv_ar_at_file" = xno; then - archiver_list_spec= -else - archiver_list_spec=$lt_cv_ar_at_file -fi - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } -if ${lt_cv_sys_global_symbol_pipe+:} false; then : - $as_echo_n "(cached) " >&6 -else - -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test "$host_cpu" = ia64; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function - # and D for any global variable. - # Also find C++ and __fastcall symbols from MSVC++, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ -" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ -" s[1]~/^[@?]/{print s[1], s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 - (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ -#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) -/* DATA imports from DLLs on WIN32 con't be const, because runtime - relocations are performed -- see ld's documentation on pseudo-relocs. */ -# define LT_DLSYM_CONST -#elif defined(__osf__) -/* This system does not cope well with relocations in const data. */ -# define LT_DLSYM_CONST -#else -# define LT_DLSYM_CONST const -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -LT_DLSYM_CONST struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_globsym_save_LIBS=$LIBS - lt_globsym_save_CFLAGS=$CFLAGS - LIBS="conftstm.$ac_objext" - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext}; then - pipe_works=yes - fi - LIBS=$lt_globsym_save_LIBS - CFLAGS=$lt_globsym_save_CFLAGS - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -$as_echo "failed" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -$as_echo "ok" >&6; } -fi - -# Response file support. -if test "$lt_cv_nm_interface" = "MS dumpbin"; then - nm_file_list_spec='@' -elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then - nm_file_list_spec='@' -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 -$as_echo_n "checking for sysroot... " >&6; } - -# Check whether --with-sysroot was given. -if test "${with_sysroot+set}" = set; then : - withval=$with_sysroot; -else - with_sysroot=no -fi - - -lt_sysroot= -case ${with_sysroot} in #( - yes) - if test "$GCC" = yes; then - lt_sysroot=`$CC --print-sysroot 2>/dev/null` - fi - ;; #( - /*) - lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` - ;; #( - no|'') - ;; #( - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 -$as_echo "${with_sysroot}" >&6; } - as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 - ;; -esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 -$as_echo "${lt_sysroot:-no}" >&6; } - - - - - -# Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then : - enableval=$enable_libtool_lock; -fi - -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out which ABI we are using. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*) - case `/usr/bin/file conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -belf" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -$as_echo_n "checking whether the C compiler needs -belf... " >&6; } -if ${lt_cv_cc_needs_belf+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_cc_needs_belf=yes -else - lt_cv_cc_needs_belf=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -$as_echo "$lt_cv_cc_needs_belf" >&6; } - if test x"$lt_cv_cc_needs_belf" != x"yes"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" - fi - ;; -*-*solaris*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) - case $host in - i?86-*-solaris*) - LD="${LD-ld} -m elf_x86_64" - ;; - sparc*-*-solaris*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - # GNU ld 2.21 introduced _sol2 emulations. Use them if available. - if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then - LD="${LD-ld}_sol2" - fi - ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks="$enable_libtool_lock" - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. -set dummy ${ac_tool_prefix}mt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$MANIFEST_TOOL"; then - ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL -if test -n "$MANIFEST_TOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 -$as_echo "$MANIFEST_TOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_MANIFEST_TOOL"; then - ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL - # Extract the first word of "mt", so it can be a program name with args. -set dummy mt; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_MANIFEST_TOOL"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL -if test -n "$ac_ct_MANIFEST_TOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 -$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_MANIFEST_TOOL" = x; then - MANIFEST_TOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL - fi -else - MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" -fi - -test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 -$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } -if ${lt_cv_path_mainfest_tool+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_path_mainfest_tool=no - echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 - $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out - cat conftest.err >&5 - if $GREP 'Manifest Tool' conftest.out > /dev/null; then - lt_cv_path_mainfest_tool=yes - fi - rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 -$as_echo "$lt_cv_path_mainfest_tool" >&6; } -if test "x$lt_cv_path_mainfest_tool" != xyes; then - MANIFEST_TOOL=: -fi - - - - - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DSYMUTIL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -$as_echo "$DSYMUTIL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -$as_echo "$ac_ct_DSYMUTIL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_NMEDIT+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -$as_echo "$NMEDIT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -$as_echo "$ac_ct_NMEDIT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_LIPO+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -$as_echo "$LIPO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_LIPO+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_LIPO="lipo" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -$as_echo "$ac_ct_LIPO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -$as_echo "$OTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL="otool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -$as_echo "$ac_ct_OTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OTOOL64+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -$as_echo "$OTOOL64" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -$as_echo "$ac_ct_OTOOL64" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -$as_echo_n "checking for -single_module linker flag... " >&6; } -if ${lt_cv_apple_cc_single_mod+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_apple_cc_single_mod=no - if test -z "${LT_MULTI_MODULE}"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - # If there is a non-empty error log, and "single_module" - # appears in it, assume the flag caused a linker warning - if test -s conftest.err && $GREP single_module conftest.err; then - cat conftest.err >&5 - # Otherwise, if the output was created with a 0 exit code from - # the compiler, it worked. - elif test -f libconftest.dylib && test $_lt_result -eq 0; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -$as_echo "$lt_cv_apple_cc_single_mod" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } -if ${lt_cv_ld_exported_symbols_list+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_ld_exported_symbols_list=yes -else - lt_cv_ld_exported_symbols_list=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -$as_echo_n "checking for -force_load linker flag... " >&6; } -if ${lt_cv_ld_force_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR cru libconftest.a conftest.o" >&5 - $AR cru libconftest.a conftest.o 2>&5 - echo "$RANLIB libconftest.a" >&5 - $RANLIB libconftest.a 2>&5 - cat > conftest.c << _LT_EOF -int main() { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -s conftest.err && $GREP force_load conftest.err; then - cat conftest.err >&5 - elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -$as_echo "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; - darwin*) # darwin 5.x on - # if running on 10.5 or later, the deployment target defaults - # to the OS version, if on x86, and 10.4, the deployment - # target defaults to 10.4. Don't you love it? - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*86*-darwin8*|10.0,*-darwin[91]*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - 10.[012]*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; - 10.*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - esac - ;; - esac - if test "$lt_cv_apple_cc_single_mod" = "yes"; then - _lt_dar_single_mod='$single_module' - fi - if test "$lt_cv_ld_exported_symbols_list" = "yes"; then - _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if ${ac_cv_prog_CPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if ${ac_cv_header_stdc+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - -for ac_header in dlfcn.h -do : - ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_DLFCN_H 1 -_ACEOF - -fi - -done - - - - -func_stripname_cnf () -{ - case ${2} in - .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; - *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; - esac -} # func_stripname_cnf - - - - - -# Set options -enable_win32_dll=yes - -case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. -set dummy ${ac_tool_prefix}as; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_AS+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AS"; then - ac_cv_prog_AS="$AS" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_AS="${ac_tool_prefix}as" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AS=$ac_cv_prog_AS -if test -n "$AS"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 -$as_echo "$AS" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AS"; then - ac_ct_AS=$AS - # Extract the first word of "as", so it can be a program name with args. -set dummy as; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_AS+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AS"; then - ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_AS="as" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AS=$ac_cv_prog_ac_ct_AS -if test -n "$ac_ct_AS"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 -$as_echo "$ac_ct_AS" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_AS" = x; then - AS="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AS=$ac_ct_AS - fi -else - AS="$ac_cv_prog_AS" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DLLTOOL=$ac_cv_prog_DLLTOOL -if test -n "$DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 -$as_echo "$DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DLLTOOL"; then - ac_ct_DLLTOOL=$DLLTOOL - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DLLTOOL"; then - ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_DLLTOOL="dlltool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL -if test -n "$ac_ct_DLLTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 -$as_echo "$ac_ct_DLLTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DLLTOOL" = x; then - DLLTOOL="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DLLTOOL=$ac_ct_DLLTOOL - fi -else - DLLTOOL="$ac_cv_prog_DLLTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -$as_echo "$OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -$as_echo "$ac_ct_OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - - ;; -esac - -test -z "$AS" && AS=as - - - - - -test -z "$DLLTOOL" && DLLTOOL=dlltool - - - - - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - -# Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_shared=no -fi - - - - - - - - - - - enable_dlopen=no - - - - - # Check whether --enable-static was given. -if test "${enable_static+set}" = set; then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_static=yes -fi - - - - - - - - - - -# Check whether --with-pic was given. -if test "${with_pic+set}" = set; then : - withval=$with_pic; lt_p=${PACKAGE-default} - case $withval in - yes|no) pic_mode=$withval ;; - *) - pic_mode=default - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for lt_pkg in $withval; do - IFS="$lt_save_ifs" - if test "X$lt_pkg" = "X$lt_p"; then - pic_mode=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - pic_mode=default -fi - - -test -z "$pic_mode" && pic_mode=default - - - - - - - - # Check whether --enable-fast-install was given. -if test "${enable_fast_install+set}" = set; then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_fast_install=yes -fi - - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ltmain" - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -$as_echo_n "checking for objdir... " >&6; } -if ${lt_cv_objdir+:} false; then : - $as_echo_n "(cached) " >&6 -else - rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -$as_echo "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -cat >>confdefs.h <<_ACEOF -#define LT_OBJDIR "$lt_cv_objdir/" -_ACEOF - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a - -with_gnu_ld="$lt_cv_prog_gnu_ld" - -old_CC="$CC" -old_CFLAGS="$CFLAGS" - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } -if ${lt_cv_path_MAGIC_CMD+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/${ac_tool_prefix}file; then - lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -$as_echo "$MAGIC_CMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -$as_echo_n "checking for file... " >&6; } -if ${lt_cv_path_MAGIC_CMD+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/file; then - lt_cv_path_MAGIC_CMD="$ac_dir/file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -$as_echo "$MAGIC_CMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC="$CC" -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test "$GCC" = yes; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - - - if test "$GCC" = yes; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - if test -n "$lt_prog_compiler_pic"; then - lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" - fi - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - # old Intel for x86_64 which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - nagfor*) - # NAG Fortran compiler - lt_prog_compiler_wl='-Wl,-Wl,,' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ F* | *Sun*Fortran*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Qoption ld ' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - *Intel*\ [CF]*Compiler*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - *Portland\ Group*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" - ;; -esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } -if ${lt_cv_prog_compiler_pic+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic=$lt_prog_compiler_pic -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 -$as_echo "$lt_cv_prog_compiler_pic" >&6; } -lt_prog_compiler_pic=$lt_cv_prog_compiler_pic - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if ${lt_cv_prog_compiler_pic_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } - -if test x"$lt_cv_prog_compiler_pic_works" = xyes; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if ${lt_cv_prog_compiler_static_works+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_static_works=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -$as_echo "$lt_cv_prog_compiler_static_works" >&6; } - -if test x"$lt_cv_prog_compiler_static_works" = xyes; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -$as_echo "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -$as_echo "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -$as_echo_n "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -$as_echo "$hard_links" >&6; } - if test "$hard_links" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - linux* | k*bsd*-gnu | gnu*) - link_all_deplibs=no - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test "$with_gnu_ld" = yes; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test "$lt_use_gnu_ld_interface" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='${wl}--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - link_all_deplibs=yes - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test "$host_os" = linux-dietlibc; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test "$tmp_diet" = no - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test "$ld_shlibs" = no; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - # Also, AIX nm treats weak defined symbols like other global - # defined symbols, whereas GNU nm marks them as "W". - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='${wl}-f,' - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - link_all_deplibs=no - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - export_dynamic_flag_spec='${wl}-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath_+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath_+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath_"; then - lt_cv_aix_libpath_="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath_ -fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' ${wl}-bernotok' - allow_undefined_flag=' ${wl}-berok' - if test "$with_gnu_ld" = yes; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - case $cc_basename in - cl*) - # Native MSVC - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - always_export_symbols=yes - file_list_spec='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; - else - sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, )='true' - enable_shared_with_static_runtimes=yes - exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - # Don't use ranlib - old_postinstall_cmds='chmod 644 $oldlib' - postlink_cmds='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile="$lt_outputfile.exe" - lt_tool_outputfile="$lt_tool_outputfile.exe" - ;; - esac~ - if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # Assume MSVC wrapper - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - enable_shared_with_static_runtimes=yes - ;; - esac - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test "$lt_cv_ld_force_load" = "yes"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag="$_lt_dar_allow_undefined" - case $cc_basename in - ifort*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" - archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" - module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly*) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test "$GCC" = yes; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -$as_echo_n "checking if $CC understands -b... " >&6; } -if ${lt_cv_prog_compiler__b+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler__b=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -$as_echo "$lt_cv_prog_compiler__b" >&6; } - -if test x"$lt_cv_prog_compiler__b" = xyes; then - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - # This should be the same for all languages, so no per-tag cache variable. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 -$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } -if ${lt_cv_irix_exported_symbol+:} false; then : - $as_echo_n "(cached) " >&6 -else - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo (void) { return 0; } -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_irix_exported_symbol=yes -else - lt_cv_irix_exported_symbol=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 -$as_echo "$lt_cv_irix_exported_symbol" >&6; } - if test "$lt_cv_irix_exported_symbol" = yes; then - archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' - fi - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - netbsd* | netbsdelf*-gnu) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='${wl}' - archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='${wl}-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='${wl}-z,text' - allow_undefined_flag='${wl}-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test x$host_vendor = xsni; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='${wl}-Blargedynsym' - ;; - esac - fi - fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -$as_echo "$ld_shlibs" >&6; } -test "$ld_shlibs" = no && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } -if ${lt_cv_archive_cmds_need_lc+:} false; then : - $as_echo_n "(cached) " >&6 -else - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -$as_echo_n "checking dynamic linker characteristics... " >&6; } - -if test "$GCC" = yes; then - case $host_os in - darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; - *) lt_awk_arg="/^libraries:/" ;; - esac - case $host_os in - mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; - *) lt_sed_strip_eq="s,=/,/,g" ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary. - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path/$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" - else - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS=" "; FS="/|\n";} { - lt_foo=""; - lt_count=0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo="/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's,/\([A-Za-z]:\),\1,g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32* | cegcc*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl*) - # Native MSVC - libname_spec='$name' - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - library_names_spec='${libname}.dll.lib' - - case $build_os in - mingw*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec="$LIB" - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC wrapper - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=yes - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if ${lt_cv_shlibpath_overrides_runpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -$as_echo "$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then - sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi -if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then - sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -$as_echo_n "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test "X$hardcode_automatic" = "Xyes" ; then - - # We can hardcode non-existent directories. - if test "$hardcode_direct" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && - test "$hardcode_minus_L" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -$as_echo "$hardcode_action" >&6; } - -if test "$hardcode_action" = relink || - test "$inherit_rpath" = yes; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32* | cegcc*) - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen="dlopen" - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - - lt_cv_dlopen="dyld" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - -fi - - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = xyes; then : - lt_cv_dlopen="shl_load" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -$as_echo_n "checking for shl_load in -ldld... " >&6; } -if ${ac_cv_lib_dld_shl_load+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dld_shl_load=yes -else - ac_cv_lib_dld_shl_load=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -$as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = xyes; then : - lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" -else - ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if ${ac_cv_lib_dl_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -$as_echo_n "checking for dlopen in -lsvld... " >&6; } -if ${ac_cv_lib_svld_dlopen+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_svld_dlopen=yes -else - ac_cv_lib_svld_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -$as_echo "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = xyes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -$as_echo_n "checking for dld_link in -ldld... " >&6; } -if ${ac_cv_lib_dld_dld_link+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (); -int -main () -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dld_dld_link=yes -else - ac_cv_lib_dld_dld_link=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -$as_echo "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = xyes; then : - lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" -fi - - -fi - - -fi - - -fi - - -fi - - -fi - - ;; - esac - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else - enable_dlopen=no - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS="$LDFLAGS" - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS="$LIBS" - LIBS="$lt_cv_dlopen_libs $LIBS" - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -$as_echo_n "checking whether a program can dlopen itself... " >&6; } -if ${lt_cv_dlopen_self+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisbility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -$as_echo "$lt_cv_dlopen_self" >&6; } - - if test "x$lt_cv_dlopen_self" = xyes; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } -if ${lt_cv_dlopen_self_static+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line $LINENO "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisbility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -int fnord () __attribute__((visibility("default"))); -#endif - -int fnord () { return 42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -$as_echo "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -$as_echo_n "checking whether stripping libraries is possible... " >&6; } -if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - ;; - esac -fi - - - - - - - - - - - - - # Report which library types will actually be built - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -$as_echo_n "checking if libtool supports shared libraries... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -$as_echo "$can_build_shared" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -$as_echo_n "checking whether to build shared libraries... " >&6; } - test "$can_build_shared" = "no" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -$as_echo "$enable_shared" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -$as_echo_n "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test "$enable_shared" = yes || enable_static=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -$as_echo "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 -$as_echo_n "checking how to run the C++ preprocessor... " >&6; } -if test -z "$CXXCPP"; then - if ${ac_cv_prog_CXXCPP+:} false; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CXXCPP needs to be expanded - for CXXCPP in "$CXX -E" "/lib/cpp" - do - ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CXXCPP=$CXXCPP - -fi - CXXCPP=$ac_cv_prog_CXXCPP -else - ac_cv_prog_CXXCPP=$CXXCPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 -$as_echo "$CXXCPP" >&6; } -ac_preproc_ok=false -for ac_cxx_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.i conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.i conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -else - _lt_caught_CXX_error=yes -fi - -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -archive_cmds_need_lc_CXX=no -allow_undefined_flag_CXX= -always_export_symbols_CXX=no -archive_expsym_cmds_CXX= -compiler_needs_object_CXX=no -export_dynamic_flag_spec_CXX= -hardcode_direct_CXX=no -hardcode_direct_absolute_CXX=no -hardcode_libdir_flag_spec_CXX= -hardcode_libdir_separator_CXX= -hardcode_minus_L_CXX=no -hardcode_shlibpath_var_CXX=unsupported -hardcode_automatic_CXX=no -inherit_rpath_CXX=no -module_cmds_CXX= -module_expsym_cmds_CXX= -link_all_deplibs_CXX=unknown -old_archive_cmds_CXX=$old_archive_cmds -reload_flag_CXX=$reload_flag -reload_cmds_CXX=$reload_cmds -no_undefined_flag_CXX= -whole_archive_flag_spec_CXX= -enable_shared_with_static_runtimes_CXX=no - -# Source file extension for C++ test sources. -ac_ext=cpp - -# Object file extension for compiled C++ test sources. -objext=o -objext_CXX=$objext - -# No sense in running all these tests if we already determined that -# the CXX compiler isn't working. Some variables (like enable_shared) -# are currently assumed to apply to all compilers on this platform, -# and will be corrupted by setting them based on a non-working compiler. -if test "$_lt_caught_CXX_error" != yes; then - # Code to be used in simple compile tests - lt_simple_compile_test_code="int some_variable = 0;" - - # Code to be used in simple link tests - lt_simple_link_test_code='int main(int, char *[]) { return(0); }' - - # ltmain only uses $CC for tagged configurations so make sure $CC is set. - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - - # save warnings/boilerplate of simple test code - ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - - ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - - # Allow CC to be a program name with arguments. - lt_save_CC=$CC - lt_save_CFLAGS=$CFLAGS - lt_save_LD=$LD - lt_save_GCC=$GCC - GCC=$GXX - lt_save_with_gnu_ld=$with_gnu_ld - lt_save_path_LD=$lt_cv_path_LD - if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then - lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx - else - $as_unset lt_cv_prog_gnu_ld - fi - if test -n "${lt_cv_path_LDCXX+set}"; then - lt_cv_path_LD=$lt_cv_path_LDCXX - else - $as_unset lt_cv_path_LD - fi - test -z "${LDCXX+set}" || LD=$LDCXX - CC=${CXX-"c++"} - CFLAGS=$CXXFLAGS - compiler=$CC - compiler_CXX=$CC - for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` - - - if test -n "$compiler"; then - # We don't want -fno-exception when compiling C++ code, so set the - # no_builtin_flag separately - if test "$GXX" = yes; then - lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' - else - lt_prog_compiler_no_builtin_flag_CXX= - fi - - if test "$GXX" = yes; then - # Set up default GNU C++ configuration - - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -$as_echo_n "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if ${lt_cv_path_LD+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if ${lt_cv_prog_gnu_ld+:} false; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -$as_echo "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - # Check if GNU C++ uses GNU ld as the underlying linker, since the - # archiving commands below assume that GNU ld is being used. - if test "$with_gnu_ld" = yes; then - archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - - # If archive_cmds runs LD, not CC, wlarc should be empty - # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to - # investigate it a little bit more. (MM) - wlarc='${wl}' - - # ancient GNU ld didn't support --whole-archive et. al. - if eval "`$CC -print-prog-name=ld` --help 2>&1" | - $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec_CXX= - fi - else - with_gnu_ld=no - wlarc= - - # A generic and very simple default shared library creation - # command for GNU C++ for the case where it uses the native - # linker, instead of GNU ld. If possible, this setting should - # overridden to take advantage of the native linker features on - # the platform it is being used on. - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - fi - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - - else - GXX=no - with_gnu_ld=no - wlarc= - fi - - # PORTME: fill in a description of your system's C++ link characteristics - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - ld_shlibs_CXX=yes - case $host_os in - aix3*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - case $ld_flag in - *-brtl*) - aix_use_runtimelinking=yes - break - ;; - esac - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds_CXX='' - hardcode_direct_CXX=yes - hardcode_direct_absolute_CXX=yes - hardcode_libdir_separator_CXX=':' - link_all_deplibs_CXX=yes - file_list_spec_CXX='${wl}-f,' - - if test "$GXX" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct_CXX=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L_CXX=yes - hardcode_libdir_flag_spec_CXX='-L$libdir' - hardcode_libdir_separator_CXX= - fi - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - export_dynamic_flag_spec_CXX='${wl}-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to - # export. - always_export_symbols_CXX=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag_CXX='-berok' - # Determine the default libpath from the value encoded in an empty - # executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath__CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath__CXX -fi - - hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" - - archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag_CXX="-z nodefs" - archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - if test "${lt_cv_aix_libpath+set}" = set; then - aix_libpath=$lt_cv_aix_libpath -else - if ${lt_cv_aix_libpath__CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - - lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\([^ ]*\) *$/\1/ - p - } - }' - lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - # Check for a 64-bit object if we didn't find anything. - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` - fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test -z "$lt_cv_aix_libpath__CXX"; then - lt_cv_aix_libpath__CXX="/usr/lib:/lib" - fi - -fi - - aix_libpath=$lt_cv_aix_libpath__CXX -fi - - hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag_CXX=' ${wl}-bernotok' - allow_undefined_flag_CXX=' ${wl}-berok' - if test "$with_gnu_ld" = yes; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec_CXX='$convenience' - fi - archive_cmds_need_lc_CXX=yes - # This is similar to how AIX traditionally builds its shared - # libraries. - archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag_CXX=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs_CXX=no - fi - ;; - - chorus*) - case $cc_basename in - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - cygwin* | mingw* | pw32* | cegcc*) - case $GXX,$cc_basename in - ,cl* | no,cl*) - # Native MSVC - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec_CXX=' ' - allow_undefined_flag_CXX=unsupported - always_export_symbols_CXX=yes - file_list_spec_CXX='@' - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' - archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; - else - $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; - fi~ - $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ - linknames=' - # The linker will not automatically build a static lib if we build a DLL. - # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' - enable_shared_with_static_runtimes_CXX=yes - # Don't use ranlib - old_postinstall_cmds_CXX='chmod 644 $oldlib' - postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ - lt_tool_outputfile="@TOOL_OUTPUT@"~ - case $lt_outputfile in - *.exe|*.EXE) ;; - *) - lt_outputfile="$lt_outputfile.exe" - lt_tool_outputfile="$lt_tool_outputfile.exe" - ;; - esac~ - func_to_tool_file "$lt_outputfile"~ - if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then - $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; - $RM "$lt_outputfile.manifest"; - fi' - ;; - *) - # g++ - # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec_CXX='-L$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' - allow_undefined_flag_CXX=unsupported - always_export_symbols_CXX=no - enable_shared_with_static_runtimes_CXX=yes - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs_CXX=no - fi - ;; - esac - ;; - darwin* | rhapsody*) - - - archive_cmds_need_lc_CXX=no - hardcode_direct_CXX=no - hardcode_automatic_CXX=yes - hardcode_shlibpath_var_CXX=unsupported - if test "$lt_cv_ld_force_load" = "yes"; then - whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - - else - whole_archive_flag_spec_CXX='' - fi - link_all_deplibs_CXX=yes - allow_undefined_flag_CXX="$_lt_dar_allow_undefined" - case $cc_basename in - ifort*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=func_echo_all - archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" - module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" - archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" - module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" - if test "$lt_cv_apple_cc_single_mod" != "yes"; then - archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" - archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" - fi - - else - ld_shlibs_CXX=no - fi - - ;; - - dgux*) - case $cc_basename in - ec++*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - ghcx*) - # Green Hills C++ Compiler - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - freebsd2.*) - # C++ shared libraries reported to be fairly broken before - # switch to ELF - ld_shlibs_CXX=no - ;; - - freebsd-elf*) - archive_cmds_need_lc_CXX=no - ;; - - freebsd* | dragonfly*) - # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF - # conventions - ld_shlibs_CXX=yes - ;; - - haiku*) - archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - link_all_deplibs_CXX=yes - ;; - - hpux9*) - hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_CXX=: - export_dynamic_flag_spec_CXX='${wl}-E' - hardcode_direct_CXX=yes - hardcode_minus_L_CXX=yes # Not in the search PATH, - # but as the default - # location of the library. - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aCC*) - archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test "$GXX" = yes; then - archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - - hpux10*|hpux11*) - if test $with_gnu_ld = no; then - hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - case $host_cpu in - hppa*64*|ia64*) - ;; - *) - export_dynamic_flag_spec_CXX='${wl}-E' - ;; - esac - fi - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct_CXX=no - hardcode_shlibpath_var_CXX=no - ;; - *) - hardcode_direct_CXX=yes - hardcode_direct_absolute_CXX=yes - hardcode_minus_L_CXX=yes # Not in the search PATH, - # but as the default - # location of the library. - ;; - esac - - case $cc_basename in - CC*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - aCC*) - case $host_cpu in - hppa*64*) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test "$GXX" = yes; then - if test $with_gnu_ld = no; then - case $host_cpu in - hppa*64*) - archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - ia64*) - archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - ;; - esac - fi - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - - interix[3-9]*) - hardcode_direct_CXX=no - hardcode_shlibpath_var_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - irix5* | irix6*) - case $cc_basename in - CC*) - # SGI C++ - archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - - # Archives containing C++ object files must be created using - # "CC -ar", where "CC" is the IRIX C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' - ;; - *) - if test "$GXX" = yes; then - if test "$with_gnu_ld" = no; then - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' - fi - fi - link_all_deplibs_CXX=yes - ;; - esac - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - inherit_rpath_CXX=yes - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - - # Archives containing C++ object files must be created using - # "CC -Bstatic", where "CC" is the KAI C++ compiler. - old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' - ;; - icpc* | ecpc* ) - # Intel C++ - with_gnu_ld=yes - # version 8.0 and above of icpc choke on multiply defined symbols - # if we add $predep_objects and $postdep_objects, however 7.1 and - # earlier do not add the objects themselves. - case `$CC -V 2>&1` in - *"Version 7."*) - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - *) # Version 8.0 or newer - tmp_idyn= - case $host_cpu in - ia64*) tmp_idyn=' -i_dynamic';; - esac - archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - ;; - esac - archive_cmds_need_lc_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - ;; - pgCC* | pgcpp*) - # Portland Group C++ compiler - case `$CC -V` in - *pgCC\ [1-5].* | *pgcpp\ [1-5].*) - prelink_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ - compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' - old_archive_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ - $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ - $RANLIB $oldlib' - archive_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' - archive_expsym_cmds_CXX='tpldir=Template.dir~ - rm -rf $tpldir~ - $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' - ;; - *) # Version 6 and above use weak symbols - archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' - ;; - esac - - hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - ;; - cxx*) - # Compaq C++ - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' - - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec_CXX='-rpath $libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' - ;; - xl* | mpixl* | bgxl*) - # IBM XL 8.0 on PPC, with GNU ld - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec_CXX='${wl}--export-dynamic' - archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - no_undefined_flag_CXX=' -zdefs' - archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' - hardcode_libdir_flag_spec_CXX='-R$libdir' - whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object_CXX=yes - - # Not sure whether something based on - # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 - # would be better. - output_verbose_link_cmd='func_echo_all' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' - ;; - esac - ;; - esac - ;; - - lynxos*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - m88k*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - mvs*) - case $cc_basename in - cxx*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' - wlarc= - hardcode_libdir_flag_spec_CXX='-R$libdir' - hardcode_direct_CXX=yes - hardcode_shlibpath_var_CXX=no - fi - # Workaround some broken pre-1.5 toolchains - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' - ;; - - *nto* | *qnx*) - ld_shlibs_CXX=yes - ;; - - openbsd2*) - # C++ shared libraries are fairly broken - ld_shlibs_CXX=no - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct_CXX=yes - hardcode_shlibpath_var_CXX=no - hardcode_direct_absolute_CXX=yes - archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' - export_dynamic_flag_spec_CXX='${wl}-E' - whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - fi - output_verbose_link_cmd=func_echo_all - else - ld_shlibs_CXX=no - fi - ;; - - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - # Kuck and Associates, Inc. (KAI) C++ Compiler - - # KCC will only create a shared library if the output file - # ends with ".so" (or ".sl" for HP-UX), so rename the library - # to its proper name (with version) after linking. - archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' - - hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' - hardcode_libdir_separator_CXX=: - - # Archives containing C++ object files must be created using - # the KAI C++ compiler. - case $host in - osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; - *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; - esac - ;; - RCC*) - # Rational C++ 2.4.1 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - cxx*) - case $host in - osf3*) - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - ;; - *) - allow_undefined_flag_CXX=' -expect_unresolved \*' - archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ - echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ - $RM $lib.exp' - hardcode_libdir_flag_spec_CXX='-rpath $libdir' - ;; - esac - - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - # - # There doesn't appear to be a way to prevent this compiler from - # explicitly linking system object files so we need to strip them - # from the output so that they don't get included in the library - # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' - ;; - *) - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' - case $host in - osf3*) - archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - ;; - *) - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - ;; - esac - - hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator_CXX=: - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - - else - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - fi - ;; - esac - ;; - - psos*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - lcc*) - # Lucid - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - solaris*) - case $cc_basename in - CC* | sunCC*) - # Sun C++ 4.2, 5.x and Centerline C++ - archive_cmds_need_lc_CXX=yes - no_undefined_flag_CXX=' -zdefs' - archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' - archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - hardcode_libdir_flag_spec_CXX='-R$libdir' - hardcode_shlibpath_var_CXX=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. - # Supported since Solaris 2.6 (maybe 2.5.1?) - whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' - ;; - esac - link_all_deplibs_CXX=yes - - output_verbose_link_cmd='func_echo_all' - - # Archives containing C++ object files must be created using - # "CC -xar", where "CC" is the Sun C++ compiler. This is - # necessary to make sure instantiated templates are included - # in the archive. - old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' - ;; - gcx*) - # Green Hills C++ Compiler - archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - - # The C++ compiler must be used to create the archive. - old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' - ;; - *) - # GNU C++ compiler with Solaris linker - if test "$GXX" = yes && test "$with_gnu_ld" = no; then - no_undefined_flag_CXX=' ${wl}-z ${wl}defs' - if $CC --version | $GREP -v '^2\.7' > /dev/null; then - archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - else - # g++ 2.7 appears to require `-G' NOT `-shared' on this - # platform. - archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' - archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' - - # Commands to make compiler produce verbose output that lists - # what "hidden" libraries, object files and flags are used when - # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' - fi - - hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - ;; - esac - fi - ;; - esac - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag_CXX='${wl}-z,text' - archive_cmds_need_lc_CXX=no - hardcode_shlibpath_var_CXX=no - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag_CXX='${wl}-z,text' - allow_undefined_flag_CXX='${wl}-z,nodefs' - archive_cmds_need_lc_CXX=no - hardcode_shlibpath_var_CXX=no - hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' - hardcode_libdir_separator_CXX=':' - link_all_deplibs_CXX=yes - export_dynamic_flag_spec_CXX='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - case $cc_basename in - CC*) - archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ - '"$old_archive_cmds_CXX" - reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ - '"$reload_cmds_CXX" - ;; - *) - archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - ;; - - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - ;; - - vxworks*) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - - *) - # FIXME: insert proper C++ library support - ld_shlibs_CXX=no - ;; - esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 -$as_echo "$ld_shlibs_CXX" >&6; } - test "$ld_shlibs_CXX" = no && can_build_shared=no - - GCC_CXX="$GXX" - LD_CXX="$LD" - - ## CAVEAT EMPTOR: - ## There is no encapsulation within the following macros, do not change - ## the running order or otherwise move them around unless you know exactly - ## what you are doing... - # Dependencies to place before and after the object being linked: -predep_objects_CXX= -postdep_objects_CXX= -predeps_CXX= -postdeps_CXX= -compiler_lib_search_path_CXX= - -cat > conftest.$ac_ext <<_LT_EOF -class Foo -{ -public: - Foo (void) { a = 0; } -private: - int a; -}; -_LT_EOF - - -_lt_libdeps_save_CFLAGS=$CFLAGS -case "$CC $CFLAGS " in #( -*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; -*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; -*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; -esac - -if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Parse the compiler output and extract the necessary - # objects, libraries and library flags. - - # Sentinel used to keep track of whether or not we are before - # the conftest object file. - pre_test_object_deps_done=no - - for p in `eval "$output_verbose_link_cmd"`; do - case ${prev}${p} in - - -L* | -R* | -l*) - # Some compilers place space between "-{L,R}" and the path. - # Remove the space. - if test $p = "-L" || - test $p = "-R"; then - prev=$p - continue - fi - - # Expand the sysroot to ease extracting the directories later. - if test -z "$prev"; then - case $p in - -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; - -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; - -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; - esac - fi - case $p in - =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; - esac - if test "$pre_test_object_deps_done" = no; then - case ${prev} in - -L | -R) - # Internal compiler library paths should come after those - # provided the user. The postdeps already come after the - # user supplied libs so there is no need to process them. - if test -z "$compiler_lib_search_path_CXX"; then - compiler_lib_search_path_CXX="${prev}${p}" - else - compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" - fi - ;; - # The "-l" case would never come before the object being - # linked, so don't bother handling this case. - esac - else - if test -z "$postdeps_CXX"; then - postdeps_CXX="${prev}${p}" - else - postdeps_CXX="${postdeps_CXX} ${prev}${p}" - fi - fi - prev= - ;; - - *.lto.$objext) ;; # Ignore GCC LTO objects - *.$objext) - # This assumes that the test object file only shows up - # once in the compiler output. - if test "$p" = "conftest.$objext"; then - pre_test_object_deps_done=yes - continue - fi - - if test "$pre_test_object_deps_done" = no; then - if test -z "$predep_objects_CXX"; then - predep_objects_CXX="$p" - else - predep_objects_CXX="$predep_objects_CXX $p" - fi - else - if test -z "$postdep_objects_CXX"; then - postdep_objects_CXX="$p" - else - postdep_objects_CXX="$postdep_objects_CXX $p" - fi - fi - ;; - - *) ;; # Ignore the rest. - - esac - done - - # Clean up. - rm -f a.out a.exe -else - echo "libtool.m4: error: problem compiling CXX test program" -fi - -$RM -f confest.$objext -CFLAGS=$_lt_libdeps_save_CFLAGS - -# PORTME: override above test on systems where it is broken -case $host_os in -interix[3-9]*) - # Interix 3.5 installs completely hosed .la files for C++, so rather than - # hack all around it, let's just trust "g++" to DTRT. - predep_objects_CXX= - postdep_objects_CXX= - postdeps_CXX= - ;; - -linux*) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - - if test "$solaris_use_stlport4" != yes; then - postdeps_CXX='-library=Cstd -library=Crun' - fi - ;; - esac - ;; - -solaris*) - case $cc_basename in - CC* | sunCC*) - # The more standards-conforming stlport4 library is - # incompatible with the Cstd library. Avoid specifying - # it if it's in CXXFLAGS. Ignore libCrun as - # -library=stlport4 depends on it. - case " $CXX $CXXFLAGS " in - *" -library=stlport4 "*) - solaris_use_stlport4=yes - ;; - esac - - # Adding this requires a known-good setup of shared libraries for - # Sun compiler versions before 5.6, else PIC objects from an old - # archive will be linked into the output, leading to subtle bugs. - if test "$solaris_use_stlport4" != yes; then - postdeps_CXX='-library=Cstd -library=Crun' - fi - ;; - esac - ;; -esac - - -case " $postdeps_CXX " in -*" -lc "*) archive_cmds_need_lc_CXX=no ;; -esac - compiler_lib_search_dirs_CXX= -if test -n "${compiler_lib_search_path_CXX}"; then - compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - lt_prog_compiler_wl_CXX= -lt_prog_compiler_pic_CXX= -lt_prog_compiler_static_CXX= - - - # C++ specific cases for pic, static, wl, etc. - if test "$GXX" = yes; then - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_CXX='-Bstatic' - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic_CXX='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic_CXX='-DDLL_EXPORT' - ;; - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic_CXX='-fno-common' - ;; - *djgpp*) - # DJGPP does not support shared libraries at all - lt_prog_compiler_pic_CXX= - ;; - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static_CXX= - ;; - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic_CXX=-Kconform_pic - fi - ;; - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - ;; - *) - lt_prog_compiler_pic_CXX='-fPIC' - ;; - esac - ;; - *qnx* | *nto*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic_CXX='-fPIC -shared' - ;; - *) - lt_prog_compiler_pic_CXX='-fPIC' - ;; - esac - else - case $host_os in - aix[4-9]*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static_CXX='-Bstatic' - else - lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' - fi - ;; - chorus*) - case $cc_basename in - cxch68*) - # Green Hills C++ Compiler - # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" - ;; - esac - ;; - mingw* | cygwin* | os2* | pw32* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic_CXX='-DDLL_EXPORT' - ;; - dgux*) - case $cc_basename in - ec++*) - lt_prog_compiler_pic_CXX='-KPIC' - ;; - ghcx*) - # Green Hills C++ Compiler - lt_prog_compiler_pic_CXX='-pic' - ;; - *) - ;; - esac - ;; - freebsd* | dragonfly*) - # FreeBSD uses GNU C++ - ;; - hpux9* | hpux10* | hpux11*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' - if test "$host_cpu" != ia64; then - lt_prog_compiler_pic_CXX='+Z' - fi - ;; - aCC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic_CXX='+Z' - ;; - esac - ;; - *) - ;; - esac - ;; - interix*) - # This is c89, which is MS Visual C++ (no shared libs) - # Anyone wants to do a port? - ;; - irix5* | irix6* | nonstopux*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_static_CXX='-non_shared' - # CC pic flag -KPIC is the default. - ;; - *) - ;; - esac - ;; - linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - case $cc_basename in - KCC*) - # KAI C++ Compiler - lt_prog_compiler_wl_CXX='--backend -Wl,' - lt_prog_compiler_pic_CXX='-fPIC' - ;; - ecpc* ) - # old Intel C++ for x86_64 which still supported -KPIC. - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-static' - ;; - icpc* ) - # Intel C++, used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-fPIC' - lt_prog_compiler_static_CXX='-static' - ;; - pgCC* | pgcpp*) - # Portland Group C++ compiler - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-fpic' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - cxx*) - # Compaq C++ - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - lt_prog_compiler_pic_CXX= - lt_prog_compiler_static_CXX='-non_shared' - ;; - xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) - # IBM XL 8.0, 9.0 on PPC and BlueGene - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-qpic' - lt_prog_compiler_static_CXX='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) - # Sun C++ 5.9 - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - lt_prog_compiler_wl_CXX='-Qoption ld ' - ;; - esac - ;; - esac - ;; - lynxos*) - ;; - m88k*) - ;; - mvs*) - case $cc_basename in - cxx*) - lt_prog_compiler_pic_CXX='-W c,exportall' - ;; - *) - ;; - esac - ;; - netbsd* | netbsdelf*-gnu) - ;; - *qnx* | *nto*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic_CXX='-fPIC -shared' - ;; - osf3* | osf4* | osf5*) - case $cc_basename in - KCC*) - lt_prog_compiler_wl_CXX='--backend -Wl,' - ;; - RCC*) - # Rational C++ 2.4.1 - lt_prog_compiler_pic_CXX='-pic' - ;; - cxx*) - # Digital/Compaq C++ - lt_prog_compiler_wl_CXX='-Wl,' - # Make sure the PIC flag is empty. It appears that all Alpha - # Linux and Compaq Tru64 Unix objects are PIC. - lt_prog_compiler_pic_CXX= - lt_prog_compiler_static_CXX='-non_shared' - ;; - *) - ;; - esac - ;; - psos*) - ;; - solaris*) - case $cc_basename in - CC* | sunCC*) - # Sun C++ 4.2, 5.x and Centerline C++ - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - lt_prog_compiler_wl_CXX='-Qoption ld ' - ;; - gcx*) - # Green Hills C++ Compiler - lt_prog_compiler_pic_CXX='-PIC' - ;; - *) - ;; - esac - ;; - sunos4*) - case $cc_basename in - CC*) - # Sun C++ 4.x - lt_prog_compiler_pic_CXX='-pic' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - lcc*) - # Lucid - lt_prog_compiler_pic_CXX='-pic' - ;; - *) - ;; - esac - ;; - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - case $cc_basename in - CC*) - lt_prog_compiler_wl_CXX='-Wl,' - lt_prog_compiler_pic_CXX='-KPIC' - lt_prog_compiler_static_CXX='-Bstatic' - ;; - esac - ;; - tandem*) - case $cc_basename in - NCC*) - # NonStop-UX NCC 3.20 - lt_prog_compiler_pic_CXX='-KPIC' - ;; - *) - ;; - esac - ;; - vxworks*) - ;; - *) - lt_prog_compiler_can_build_shared_CXX=no - ;; - esac - fi - -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic_CXX= - ;; - *) - lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" - ;; -esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } -if ${lt_cv_prog_compiler_pic_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } -lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic_CXX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 -$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } -if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_works_CXX=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works_CXX=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } - -if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then - case $lt_prog_compiler_pic_CXX in - "" | " "*) ;; - *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; - esac -else - lt_prog_compiler_pic_CXX= - lt_prog_compiler_can_build_shared_CXX=no -fi - -fi - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_static_works_CXX=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works_CXX=yes - fi - else - lt_cv_prog_compiler_static_works_CXX=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } - -if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then - : -else - lt_prog_compiler_static_CXX= -fi - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o_CXX=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_CXX=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o_CXX=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o_CXX=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 -$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } - - - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -$as_echo_n "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -$as_echo "$hard_links" >&6; } - if test "$hard_links" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - case $host_os in - aix[4-9]*) - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - # Also, AIX nm treats weak defined symbols like other global defined - # symbols, whereas GNU nm marks them as "W". - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - fi - ;; - pw32*) - export_symbols_cmds_CXX="$ltdll_cmds" - ;; - cygwin* | mingw* | cegcc*) - case $cc_basename in - cl*) - exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' - ;; - *) - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' - exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' - ;; - esac - ;; - linux* | k*bsd*-gnu | gnu*) - link_all_deplibs_CXX=no - ;; - *) - export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; - esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 -$as_echo "$ld_shlibs_CXX" >&6; } -test "$ld_shlibs_CXX" = no && can_build_shared=no - -with_gnu_ld_CXX=$with_gnu_ld - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc_CXX" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc_CXX=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds_CXX in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } -if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl_CXX - pic_flag=$lt_prog_compiler_pic_CXX - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag_CXX - allow_undefined_flag_CXX= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc_CXX=no - else - lt_cv_archive_cmds_need_lc_CXX=yes - fi - allow_undefined_flag_CXX=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 -$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } - archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -$as_echo_n "checking dynamic linker characteristics... " >&6; } - -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix[4-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32* | cegcc*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$cc_basename in - yes,*) - # gcc - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - - ;; - mingw* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - dynamic_linker='Win32 ld.exe' - ;; - - *,cl*) - # Native MSVC - libname_spec='$name' - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - library_names_spec='${libname}.dll.lib' - - case $build_os in - mingw*) - sys_lib_search_path_spec= - lt_save_ifs=$IFS - IFS=';' - for lt_path in $LIB - do - IFS=$lt_save_ifs - # Let DOS variable expansion print the short 8.3 style file name. - lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` - sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" - done - IFS=$lt_save_ifs - # Convert to MSYS style. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` - ;; - cygwin*) - # Convert to unix form, then to dos form, then back to unix form - # but this time dos style (no spaces!) so that the unix form looks - # like /cygdrive/c/PROGRA~1:/cygdr... - sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` - sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` - sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - ;; - *) - sys_lib_search_path_spec="$LIB" - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi - # FIXME: find the short name or the path components, as spaces are - # common. (e.g. "Program Files" -> "PROGRA~1") - ;; - esac - - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - dynamic_linker='Win32 link.exe' - ;; - - *) - # Assume MSVC wrapper - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - dynamic_linker='Win32 ld.exe' - ;; - esac - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -haiku*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=yes - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux # correct to gnu/linux during the next big refactor - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be glibc/ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if ${lt_cv_shlibpath_overrides_runpath+:} false; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsdelf*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='NetBSD ld.elf_so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux # correct to gnu/linux during the next big refactor - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux # correct to gnu/linux during the next big refactor - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -$as_echo "$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then - sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi -if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then - sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -$as_echo_n "checking how to hardcode library paths into programs... " >&6; } -hardcode_action_CXX= -if test -n "$hardcode_libdir_flag_spec_CXX" || - test -n "$runpath_var_CXX" || - test "X$hardcode_automatic_CXX" = "Xyes" ; then - - # We can hardcode non-existent directories. - if test "$hardcode_direct_CXX" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && - test "$hardcode_minus_L_CXX" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action_CXX=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action_CXX=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action_CXX=unsupported -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 -$as_echo "$hardcode_action_CXX" >&6; } - -if test "$hardcode_action_CXX" = relink || - test "$inherit_rpath_CXX" = yes; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - - fi # test -n "$compiler" - - CC=$lt_save_CC - CFLAGS=$lt_save_CFLAGS - LDCXX=$LD - LD=$lt_save_LD - GCC=$lt_save_GCC - with_gnu_ld=$lt_save_with_gnu_ld - lt_cv_path_LDCXX=$lt_cv_path_LD - lt_cv_path_LD=$lt_save_path_LD - lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld - lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld -fi # test "$_lt_caught_CXX_error" != yes - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - - -ac_config_headers="$ac_config_headers config.h" - - -# Checks for programs. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 -$as_echo_n "checking whether byte ordering is bigendian... " >&6; } -if ${ac_cv_c_bigendian+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_bigendian=unknown - # See if we're dealing with a universal compiler. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __APPLE_CC__ - not a universal capable compiler - #endif - typedef int dummy; - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - - # Check for potential -arch flags. It is not universal unless - # there are at least two -arch flags with different values. - ac_arch= - ac_prev= - for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do - if test -n "$ac_prev"; then - case $ac_word in - i?86 | x86_64 | ppc | ppc64) - if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then - ac_arch=$ac_word - else - ac_cv_c_bigendian=universal - break - fi - ;; - esac - ac_prev= - elif test "x$ac_word" = "x-arch"; then - ac_prev=arch - fi - done -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if test $ac_cv_c_bigendian = unknown; then - # See if sys/param.h defines the BYTE_ORDER macro. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - -int -main () -{ -#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ - && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ - && LITTLE_ENDIAN) - bogus endian macros - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # It does; now see whether it defined to BIG_ENDIAN or not. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - #include - -int -main () -{ -#if BYTE_ORDER != BIG_ENDIAN - not big endian - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_bigendian=yes -else - ac_cv_c_bigendian=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $ac_cv_c_bigendian = unknown; then - # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) - bogus endian macros - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - # It does; now see whether it defined to _BIG_ENDIAN or not. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -int -main () -{ -#ifndef _BIG_ENDIAN - not big endian - #endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_bigendian=yes -else - ac_cv_c_bigendian=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi - if test $ac_cv_c_bigendian = unknown; then - # Compile a test program. - if test "$cross_compiling" = yes; then : - # Try to guess by grepping values from an object file. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -short int ascii_mm[] = - { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; - short int ascii_ii[] = - { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; - int use_ascii (int i) { - return ascii_mm[i] + ascii_ii[i]; - } - short int ebcdic_ii[] = - { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; - short int ebcdic_mm[] = - { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; - int use_ebcdic (int i) { - return ebcdic_mm[i] + ebcdic_ii[i]; - } - extern int foo; - -int -main () -{ -return use_ascii (foo) == use_ebcdic (foo); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then - ac_cv_c_bigendian=yes - fi - if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then - if test "$ac_cv_c_bigendian" = unknown; then - ac_cv_c_bigendian=no - else - # finding both strings is unlikely to happen, but who knows? - ac_cv_c_bigendian=unknown - fi - fi -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int -main () -{ - - /* Are we little or big endian? From Harbison&Steele. */ - union - { - long int l; - char c[sizeof (long int)]; - } u; - u.l = 1; - return u.c[sizeof (long int) - 1] == 1; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_c_bigendian=no -else - ac_cv_c_bigendian=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -$as_echo "$ac_cv_c_bigendian" >&6; } - case $ac_cv_c_bigendian in #( - yes) - $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h -;; #( - no) - ;; #( - universal) - -$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h - - ;; #( - *) - as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; - esac - - if test x$cross_compiling = xyes; then - CROSS_COMPILING_TRUE= - CROSS_COMPILING_FALSE='#' -else - CROSS_COMPILING_TRUE='#' - CROSS_COMPILING_FALSE= -fi - - -# Building documentation requires doxygen, pdflatex, and makeindex. -for ac_prog in doxygen -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_DOXYGEN+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DOXYGEN"; then - ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_DOXYGEN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DOXYGEN=$ac_cv_prog_DOXYGEN -if test -n "$DOXYGEN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 -$as_echo "$DOXYGEN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$DOXYGEN" && break -done - -if test -z "$DOXYGEN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Doxygen not found - continuing without Doxygen support" >&5 -$as_echo "$as_me: WARNING: Doxygen not found - continuing without Doxygen support" >&2;} -fi - if test -n "$DOXYGEN"; then - HAVE_DOXYGEN_TRUE= - HAVE_DOXYGEN_FALSE='#' -else - HAVE_DOXYGEN_TRUE='#' - HAVE_DOXYGEN_FALSE= -fi - -if test -z "$HAVE_DOXYGEN_TRUE"; then : - ac_config_files="$ac_config_files Doxyfile" - -fi - -for ac_prog in pdflatex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_PDFLATEX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$PDFLATEX"; then - ac_cv_prog_PDFLATEX="$PDFLATEX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_PDFLATEX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -PDFLATEX=$ac_cv_prog_PDFLATEX -if test -n "$PDFLATEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 -$as_echo "$PDFLATEX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$PDFLATEX" && break -done - -if test -z "$PDFLATEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pdflatex not found - unable to compile manual to PDF" >&5 -$as_echo "$as_me: WARNING: pdflatex not found - unable to compile manual to PDF" >&2;} -fi -for ac_prog in makeindex -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_MAKEINDEX+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$MAKEINDEX"; then - ac_cv_prog_MAKEINDEX="$MAKEINDEX" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_MAKEINDEX="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -MAKEINDEX=$ac_cv_prog_MAKEINDEX -if test -n "$MAKEINDEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKEINDEX" >&5 -$as_echo "$MAKEINDEX" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$MAKEINDEX" && break -done - -if test -z "$MAKEINDEX"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: makeindex not found - unable to compile manual to PDF" >&5 -$as_echo "$as_me: WARNING: makeindex not found - unable to compile manual to PDF" >&2;} -fi - if test -n "$PDFLATEX" && test -n "$MAKEINDEX"; then - HAVE_PDFLATEX_TRUE= - HAVE_PDFLATEX_FALSE='#' -else - HAVE_PDFLATEX_TRUE='#' - HAVE_PDFLATEX_FALSE= -fi - -if test -z "$HAVE_PDFLATEX_TRUE"; then : - ac_config_files="$ac_config_files doc/cudd.tex" - -fi - -# Checks for libraries. -#AC_CHECK_LIB([m],[pow]) -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5 -$as_echo_n "checking for library containing pow... " >&6; } -if ${ac_cv_search_pow+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pow (); -int -main () -{ -return pow (); - ; - return 0; -} -_ACEOF -for ac_lib in '' m; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_pow=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_pow+:} false; then : - break -fi -done -if ${ac_cv_search_pow+:} false; then : - -else - ac_cv_search_pow=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5 -$as_echo "$ac_cv_search_pow" >&6; } -ac_res=$ac_cv_search_pow -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 -$as_echo_n "checking for pthread_create in -lpthread... " >&6; } -if ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lpthread $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char pthread_create (); -int -main () -{ -return pthread_create (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_pthread_pthread_create=yes -else - ac_cv_lib_pthread_pthread_create=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 -$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } -if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then : - have_pthreads=yes -else - have_pthreads=no -fi - - if test x$have_pthreads = xyes; then - HAVE_PTHREADS_TRUE= - HAVE_PTHREADS_FALSE='#' -else - HAVE_PTHREADS_TRUE='#' - HAVE_PTHREADS_FALSE= -fi - -# Check for Windows API functions. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing WSAStartup" >&5 -$as_echo_n "checking for library containing WSAStartup... " >&6; } -if ${ac_cv_search_WSAStartup+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char WSAStartup (); -int -main () -{ -return WSAStartup (); - ; - return 0; -} -_ACEOF -for ac_lib in '' ws2_32; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_WSAStartup=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_WSAStartup+:} false; then : - break -fi -done -if ${ac_cv_search_WSAStartup+:} false; then : - -else - ac_cv_search_WSAStartup=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_WSAStartup" >&5 -$as_echo "$ac_cv_search_WSAStartup" >&6; } -ac_res=$ac_cv_search_WSAStartup -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing GetProcessMemoryInfo" >&5 -$as_echo_n "checking for library containing GetProcessMemoryInfo... " >&6; } -if ${ac_cv_search_GetProcessMemoryInfo+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char GetProcessMemoryInfo (); -int -main () -{ -return GetProcessMemoryInfo (); - ; - return 0; -} -_ACEOF -for ac_lib in '' psapi; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_GetProcessMemoryInfo=$ac_res -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search_GetProcessMemoryInfo+:} false; then : - break -fi -done -if ${ac_cv_search_GetProcessMemoryInfo+:} false; then : - -else - ac_cv_search_GetProcessMemoryInfo=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_GetProcessMemoryInfo" >&5 -$as_echo "$ac_cv_search_GetProcessMemoryInfo" >&6; } -ac_res=$ac_cv_search_GetProcessMemoryInfo -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - -fi - - -# Checks for header files. -# First check for mandatory headers... -for ac_header in float.h inttypes.h limits.h stddef.h stdlib.h string.h assert.h math.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -else - have_mandatory_headers=no -fi - -done - -if test "x${have_mandatory_headers}" = xno; then - as_fn_error $? "One or more mandatory headers missing. Check 'config.log'." "$LINENO" 5 -fi -# ...then check for optional C headers. -for ac_header in unistd.h sys/time.h sys/times.h sys/resource.h sys/wait.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -# Finally, check C++ optional headers. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working C++ thread header" >&5 -$as_echo_n "checking for working C++ thread header... " >&6; } -ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - std::thread([] {}).join() - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - have_working_thread=yes -else - have_working_thread=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -if test x$have_working_thread = xyes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -$as_echo "#define HAVE_WORKING_THREAD 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - -# Checks for typedefs, structures, and compiler characteristics. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 -$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } -if ${ac_cv_header_stdbool_h+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - #include - #ifndef bool - "error: bool is not defined" - #endif - #ifndef false - "error: false is not defined" - #endif - #if false - "error: false is not 0" - #endif - #ifndef true - "error: true is not defined" - #endif - #if true != 1 - "error: true is not 1" - #endif - #ifndef __bool_true_false_are_defined - "error: __bool_true_false_are_defined is not defined" - #endif - - struct s { _Bool s: 1; _Bool t; } s; - - char a[true == 1 ? 1 : -1]; - char b[false == 0 ? 1 : -1]; - char c[__bool_true_false_are_defined == 1 ? 1 : -1]; - char d[(bool) 0.5 == true ? 1 : -1]; - /* See body of main program for 'e'. */ - char f[(_Bool) 0.0 == false ? 1 : -1]; - char g[true]; - char h[sizeof (_Bool)]; - char i[sizeof s.t]; - enum { j = false, k = true, l = false * true, m = true * 256 }; - /* The following fails for - HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ - _Bool n[m]; - char o[sizeof n == m * sizeof n[0] ? 1 : -1]; - char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; - /* Catch a bug in an HP-UX C compiler. See - http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html - http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html - */ - _Bool q = true; - _Bool *pq = &q; - -int -main () -{ - - bool e = &s; - *pq |= q; - *pq |= ! q; - /* Refer to every declared value, to avoid compiler optimizations. */ - return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l - + !m + !n + !o + !p + !q + !pq); - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdbool_h=yes -else - ac_cv_header_stdbool_h=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 -$as_echo "$ac_cv_header_stdbool_h" >&6; } - ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" -if test "x$ac_cv_type__Bool" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE__BOOL 1 -_ACEOF - - -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 -$as_echo_n "checking for inline... " >&6; } -if ${ac_cv_c_inline+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_c_inline=no -for ac_kw in inline __inline__ __inline; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifndef __cplusplus -typedef int foo_t; -static $ac_kw foo_t static_foo () {return 0; } -$ac_kw foo_t foo () {return 0; } -#endif - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_c_inline=$ac_kw -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - test "$ac_cv_c_inline" != no && break -done - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -$as_echo "$ac_cv_c_inline" >&6; } - -case $ac_cv_c_inline in - inline | yes) ;; - *) - case $ac_cv_c_inline in - no) ac_val=;; - *) ac_val=$ac_cv_c_inline;; - esac - cat >>confdefs.h <<_ACEOF -#ifndef __cplusplus -#define inline $ac_val -#endif -_ACEOF - ;; -esac - -ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = xyes; then : - -else - -cat >>confdefs.h <<_ACEOF -#define size_t unsigned int -_ACEOF - -fi - -ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" -case $ac_cv_c_uint16_t in #( - no|yes) ;; #( - *) - - -cat >>confdefs.h <<_ACEOF -#define uint16_t $ac_cv_c_uint16_t -_ACEOF -;; - esac - -ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" -case $ac_cv_c_uint32_t in #( - no|yes) ;; #( - *) - -$as_echo "#define _UINT32_T 1" >>confdefs.h - - -cat >>confdefs.h <<_ACEOF -#define uint32_t $ac_cv_c_uint32_t -_ACEOF -;; - esac - -ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" -if test "x$ac_cv_type_ptrdiff_t" = xyes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_PTRDIFF_T 1 -_ACEOF - - -fi - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if ${ac_cv_sizeof_int+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_int=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if ${ac_cv_sizeof_long+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if ${ac_cv_sizeof_void_p+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_void_p=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF - - -# The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long double" >&5 -$as_echo_n "checking size of long double... " >&6; } -if ${ac_cv_sizeof_long_double+:} false; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long double))" "ac_cv_sizeof_long_double" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long_double" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long double) -See \`config.log' for more details" "$LINENO" 5; } - else - ac_cv_sizeof_long_double=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_double" >&5 -$as_echo "$ac_cv_sizeof_long_double" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double -_ACEOF - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are building for a Win32 host" >&5 -$as_echo_n "checking whether we are building for a Win32 host... " >&6; } -if ${mingw_cv_win32_host+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#ifdef _WIN32 - choke me -#endif -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - mingw_cv_win32_host=no -else - mingw_cv_win32_host=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mingw_cv_win32_host" >&5 -$as_echo "$mingw_cv_win32_host" >&6; } - if test x$mingw_cv_win32_host = xyes; then - MINGW64_TRUE= - MINGW64_FALSE='#' -else - MINGW64_TRUE='#' - MINGW64_FALSE= -fi - -if test x$mingw_cv_win32_host = xyes ; then - -$as_echo "#define __USE_MINGW_ANSI_STDIO 1" >>confdefs.h - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether enough of C++11 is supported" >&5 -$as_echo_n "checking whether enough of C++11 is supported... " >&6; } -if ${ac_cv_have_modern_cxx+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -class Myclass { explicit operator bool() const { return true; } }; -int main() { - void *p = nullptr; -} -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - ac_cv_have_modern_cxx=yes -else - ac_cv_have_modern_cxx=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_modern_cxx" >&5 -$as_echo "$ac_cv_have_modern_cxx" >&6; } -if test x$ac_cv_have_modern_cxx = xyes ; then - -$as_echo "#define HAVE_MODERN_CXX 1" >>confdefs.h - -fi - -# Checks for library functions. -# First the mandatory functions... -for ac_func in pow sqrt strchr strstr -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -else - have_mandatory_functions=no -fi -done - -if test "x${have_mandatory_functions}" = xno; then - as_fn_error $? "One or more mandatory functions missing. Check 'config.log'." "$LINENO" 5 -fi -# ...then check for optional functions. -for ac_func in powl gethostname getrlimit getrusage sysconf -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -# Check for a working implementation of IEEE 754 floating point -# Specifically, check for correct treatment of +Infinity -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for +Infinity (IEEE 754 floating point)" >&5 -$as_echo_n "checking for +Infinity (IEEE 754 floating point)... " >&6; } -if ${ac_cv_have_ieee_754+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - ac_cv_have_ieee_754=maybe -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -main(void) -{ - if (HUGE_VAL != HUGE_VAL * 3 || HUGE_VAL != HUGE_VAL / 3) return 1; - return 0; -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_have_ieee_754=yes -else - ac_cv_have_ieee_754=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi - -if test x$ac_cv_have_ieee_754 = xmaybe ; then - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ - double x = INFINITY - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_have_ieee_754=yes -else - ac_cv_have_ieee_754=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -if test x$ac_cv_have_ieee_754 = xyes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -$as_echo "#define HAVE_IEEE_754 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -ac_config_files="$ac_config_files Makefile" - -ac_config_files="$ac_config_files dddmp/exp/test1.sh" - -ac_config_files="$ac_config_files dddmp/exp/test2.sh" - -ac_config_files="$ac_config_files dddmp/exp/test3.sh" - -ac_config_files="$ac_config_files dddmp/exp/test4.sh" - -ac_config_files="$ac_config_files dddmp/exp/test5.sh" - -ac_config_files="$ac_config_files dddmp/exp/test6.sh" - -ac_config_files="$ac_config_files dddmp/exp/test7.sh" - - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - if test ! -f "$cache_file" || test -h "$cache_file"; then - cat confcache >"$cache_file" - else - case $cache_file in #( - */* | ?:*) - mv -f confcache "$cache_file"$$ && - mv -f "$cache_file"$$ "$cache_file" ;; #( - *) - mv -f confcache "$cache_file" ;; - esac - fi - fi - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -U= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -$as_echo_n "checking that generated files are newer than configure... " >&6; } - if test -n "$am_sleep_pid"; then - # Hide warnings about reused PIDs. - wait $am_sleep_pid 2>/dev/null - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 -$as_echo "done" >&6; } - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${DDDMP_TRUE}" && test -z "${DDDMP_FALSE}"; then - as_fn_error $? "conditional \"DDDMP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${OBJ_TRUE}" && test -z "${OBJ_FALSE}"; then - as_fn_error $? "conditional \"OBJ\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then - as_fn_error $? "conditional \"AMDEP\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCC\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then - as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -if test -z "${CROSS_COMPILING_TRUE}" && test -z "${CROSS_COMPILING_FALSE}"; then - as_fn_error $? "conditional \"CROSS_COMPILING\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_DOXYGEN_TRUE}" && test -z "${HAVE_DOXYGEN_FALSE}"; then - as_fn_error $? "conditional \"HAVE_DOXYGEN\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_PDFLATEX_TRUE}" && test -z "${HAVE_PDFLATEX_FALSE}"; then - as_fn_error $? "conditional \"HAVE_PDFLATEX\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${HAVE_PTHREADS_TRUE}" && test -z "${HAVE_PTHREADS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_PTHREADS\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MINGW64_TRUE}" && test -z "${MINGW64_FALSE}"; then - as_fn_error $? "conditional \"MINGW64\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: "${CONFIG_STATUS=./config.status}" -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -as_myself= -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. -as_fn_error () -{ - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 - fi - $as_echo "$as_me: error: $2" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -pR' - fi -else - as_ln_s='cp -pR' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by cudd $as_me 3.0.0, which was -generated by GNU Autoconf 2.69. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - --config print configuration, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to ." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" -ac_cs_version="\\ -cudd config.status 3.0.0 -configured by $0, generated by GNU Autoconf 2.69, - with options \\"\$ac_cs_config\\" - -Copyright (C) 2012 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=?*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# -AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`' -DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' -lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' -want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' -sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' -lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' -predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' -postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' -predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' -postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' -LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' -reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' -reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' -old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' -compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' -GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' -compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' -archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' -module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' -with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' -no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' -inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' -link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' -always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' -exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' -include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' -prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' -postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' -file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' -hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' -predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' -postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' -predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' -postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' -compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in AS \ -DLLTOOL \ -OBJDUMP \ -SHELL \ -ECHO \ -PATH_SEPARATOR \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -deplibs_check_method \ -file_magic_cmd \ -file_magic_glob \ -want_nocaseglob \ -sharedlib_from_linklib_cmd \ -AR \ -AR_FLAGS \ -archiver_list_spec \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -nm_file_list_spec \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_pic \ -lt_prog_compiler_wl \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -MANIFEST_TOOL \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_separator \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib \ -compiler_lib_search_dirs \ -predep_objects \ -postdep_objects \ -predeps \ -postdeps \ -compiler_lib_search_path \ -LD_CXX \ -reload_flag_CXX \ -compiler_CXX \ -lt_prog_compiler_no_builtin_flag_CXX \ -lt_prog_compiler_pic_CXX \ -lt_prog_compiler_wl_CXX \ -lt_prog_compiler_static_CXX \ -lt_cv_prog_compiler_c_o_CXX \ -export_dynamic_flag_spec_CXX \ -whole_archive_flag_spec_CXX \ -compiler_needs_object_CXX \ -with_gnu_ld_CXX \ -allow_undefined_flag_CXX \ -no_undefined_flag_CXX \ -hardcode_libdir_flag_spec_CXX \ -hardcode_libdir_separator_CXX \ -exclude_expsyms_CXX \ -include_expsyms_CXX \ -file_list_spec_CXX \ -compiler_lib_search_dirs_CXX \ -predep_objects_CXX \ -postdep_objects_CXX \ -predeps_CXX \ -postdeps_CXX \ -compiler_lib_search_path_CXX; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postlink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -sys_lib_dlsearch_path_spec \ -reload_cmds_CXX \ -old_archive_cmds_CXX \ -old_archive_from_new_cmds_CXX \ -old_archive_from_expsyms_cmds_CXX \ -archive_cmds_CXX \ -archive_expsym_cmds_CXX \ -module_cmds_CXX \ -module_expsym_cmds_CXX \ -export_symbols_cmds_CXX \ -prelink_cmds_CXX \ -postlink_cmds_CXX; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' -xsi_shell='$xsi_shell' -lt_shell_append='$lt_shell_append' - -# See if we are running on zsh, and set the options which allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - TIMESTAMP='$TIMESTAMP' - RM='$RM' - ofile='$ofile' - - - - - - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;; - "doc/cudd.tex") CONFIG_FILES="$CONFIG_FILES doc/cudd.tex" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "dddmp/exp/test1.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test1.sh" ;; - "dddmp/exp/test2.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test2.sh" ;; - "dddmp/exp/test3.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test3.sh" ;; - "dddmp/exp/test4.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test4.sh" ;; - "dddmp/exp/test5.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test5.sh" ;; - "dddmp/exp/test6.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test6.sh" ;; - "dddmp/exp/test7.sh") CONFIG_FILES="$CONFIG_FILES dddmp/exp/test7.sh" ;; - - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= ac_tmp= - trap 'exit_status=$? - : "${ac_tmp:=$tmp}" - { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 -ac_tmp=$tmp - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$ac_tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\)..*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\)..*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// -s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$ac_tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_tt=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_tt"; then - break - elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$ac_tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$ac_tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ - >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ - "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} - - rm -f "$ac_tmp/stdin" - case $ac_file in - -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; - *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; - esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" - } >"$ac_tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$ac_tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "depfiles":C) test x"$AMDEP_TRUE" != x"" || { - # Older Autoconf quotes --file arguments for eval, but not when files - # are listed without --file. Let's play safe and only enable the eval - # if we detect the quoting. - case $CONFIG_FILES in - *\'*) eval set x "$CONFIG_FILES" ;; - *) set x $CONFIG_FILES ;; - esac - shift - for mf - do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named 'Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. - # Grep'ing the whole file is not good either: AIX grep has a line - # limit of 2048, but all sed's we know have understand at least 4000. - if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`$as_dirname -- "$mf" || -$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$mf" : 'X\(//\)[^/]' \| \ - X"$mf" : 'X\(//\)$' \| \ - X"$mf" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$mf" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running 'make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "$am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`$as_dirname -- "$file" || -$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$file" : 'X\(//\)[^/]' \| \ - X"$file" : 'X\(//\)$' \| \ - X"$file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir=$dirpart/$fdir; as_fn_mkdir_p - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done - done -} - ;; - "libtool":C) - - # See if we are running on zsh, and set the options which allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - - cfgfile="${ofile}T" - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL - -# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# NOTE: Changes made to this file will be lost: look at ltmain.sh. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008, 2009, 2010, 2011 Free Software -# Foundation, Inc. -# Written by Gordon Matzigkeit, 1996 -# -# This file is part of GNU Libtool. -# -# GNU Libtool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Libtool; see the file COPYING. If not, a copy -# can be downloaded from http://www.gnu.org/licenses/gpl.html, or -# obtained by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -# The names of the tagged configurations supported by this script. -available_tags="CXX " - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Assembler program. -AS=$lt_AS - -# DLL creation program. -DLLTOOL=$lt_DLLTOOL - -# Object dumper program. -OBJDUMP=$lt_OBJDUMP - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The PATH separator for the build system. -PATH_SEPARATOR=$lt_PATH_SEPARATOR - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# convert \$build file names to \$host format. -to_host_file_cmd=$lt_cv_to_host_file_cmd - -# convert \$build files to toolchain format. -to_tool_file_cmd=$lt_cv_to_tool_file_cmd - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method = "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# How to find potential files when deplibs_check_method = "file_magic". -file_magic_glob=$lt_file_magic_glob - -# Find potential files using nocaseglob when deplibs_check_method = "file_magic". -want_nocaseglob=$lt_want_nocaseglob - -# Command to associate shared and link libraries. -sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd - -# The archiver. -AR=$lt_AR - -# Flags to create an archive. -AR_FLAGS=$lt_AR_FLAGS - -# How to feed a file listing to the archiver. -archiver_list_spec=$lt_archiver_list_spec - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# Specify filename containing input files for \$NM. -nm_file_list_spec=$lt_nm_file_list_spec - -# The root where to search for dependent libraries,and in which our libraries should be installed. -lt_sysroot=$lt_sysroot - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Manifest tool. -MANIFEST_TOOL=$lt_MANIFEST_TOOL - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \${shlibpath_var} if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# The directories searched by this compiler when creating a shared library. -compiler_lib_search_dirs=$lt_compiler_lib_search_dirs - -# Dependencies to place before and after the objects being linked to -# create a shared library. -predep_objects=$lt_predep_objects -postdep_objects=$lt_postdep_objects -predeps=$lt_predeps -postdeps=$lt_postdeps - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path - -# ### END LIBTOOL CONFIG - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - -ltmain="$ac_aux_dir/ltmain.sh" - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '$q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - if test x"$xsi_shell" = xyes; then - sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ -func_dirname ()\ -{\ -\ case ${1} in\ -\ */*) func_dirname_result="${1%/*}${2}" ;;\ -\ * ) func_dirname_result="${3}" ;;\ -\ esac\ -} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_basename ()$/,/^} # func_basename /c\ -func_basename ()\ -{\ -\ func_basename_result="${1##*/}"\ -} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ -func_dirname_and_basename ()\ -{\ -\ case ${1} in\ -\ */*) func_dirname_result="${1%/*}${2}" ;;\ -\ * ) func_dirname_result="${3}" ;;\ -\ esac\ -\ func_basename_result="${1##*/}"\ -} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ -func_stripname ()\ -{\ -\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ -\ # positional parameters, so assign one to ordinary parameter first.\ -\ func_stripname_result=${3}\ -\ func_stripname_result=${func_stripname_result#"${1}"}\ -\ func_stripname_result=${func_stripname_result%"${2}"}\ -} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ -func_split_long_opt ()\ -{\ -\ func_split_long_opt_name=${1%%=*}\ -\ func_split_long_opt_arg=${1#*=}\ -} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ -func_split_short_opt ()\ -{\ -\ func_split_short_opt_arg=${1#??}\ -\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ -} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ -func_lo2o ()\ -{\ -\ case ${1} in\ -\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ -\ *) func_lo2o_result=${1} ;;\ -\ esac\ -} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_xform ()$/,/^} # func_xform /c\ -func_xform ()\ -{\ - func_xform_result=${1%.*}.lo\ -} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_arith ()$/,/^} # func_arith /c\ -func_arith ()\ -{\ - func_arith_result=$(( $* ))\ -} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_len ()$/,/^} # func_len /c\ -func_len ()\ -{\ - func_len_result=${#1}\ -} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - -fi - -if test x"$lt_shell_append" = xyes; then - sed -e '/^func_append ()$/,/^} # func_append /c\ -func_append ()\ -{\ - eval "${1}+=\\${2}"\ -} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ -func_append_quoted ()\ -{\ -\ func_quote_for_eval "${2}"\ -\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ -} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") -test 0 -eq $? || _lt_function_replace_fail=: - - - # Save a `func_append' function call where possible by direct use of '+=' - sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") - test 0 -eq $? || _lt_function_replace_fail=: -else - # Save a `func_append' function call even when '+=' is not available - sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ - && mv -f "$cfgfile.tmp" "$cfgfile" \ - || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") - test 0 -eq $? || _lt_function_replace_fail=: -fi - -if test x"$_lt_function_replace_fail" = x":"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 -$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} -fi - - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - - cat <<_LT_EOF >> "$ofile" - -# ### BEGIN LIBTOOL TAG CONFIG: CXX - -# The linker used to build libraries. -LD=$lt_LD_CXX - -# How to create reloadable object files. -reload_flag=$lt_reload_flag_CXX -reload_cmds=$lt_reload_cmds_CXX - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds_CXX - -# A language specific compiler. -CC=$lt_compiler_CXX - -# Is the compiler the GNU compiler? -with_gcc=$GCC_CXX - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic_CXX - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl_CXX - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static_CXX - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc_CXX - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object_CXX - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds_CXX -archive_expsym_cmds=$lt_archive_expsym_cmds_CXX - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds_CXX -module_expsym_cmds=$lt_module_expsym_cmds_CXX - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld_CXX - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag_CXX - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag_CXX - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct_CXX - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \${shlibpath_var} if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute_CXX - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L_CXX - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic_CXX - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath_CXX - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs_CXX - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols_CXX - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds_CXX - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms_CXX - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms_CXX - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds_CXX - -# Commands necessary for finishing linking programs. -postlink_cmds=$lt_postlink_cmds_CXX - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec_CXX - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action_CXX - -# The directories searched by this compiler when creating a shared library. -compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX - -# Dependencies to place before and after the objects being linked to -# create a shared library. -predep_objects=$lt_predep_objects_CXX -postdep_objects=$lt_postdep_objects_CXX -predeps=$lt_predeps_CXX -postdeps=$lt_postdeps_CXX - -# The library search path used internally by the compiler when linking -# a shared library. -compiler_lib_search_path=$lt_compiler_lib_search_path_CXX - -# ### END LIBTOOL TAG CONFIG: CXX -_LT_EOF - - ;; - "dddmp/exp/test1.sh":F) chmod +x dddmp/exp/test1.sh ;; - "dddmp/exp/test2.sh":F) chmod +x dddmp/exp/test2.sh ;; - "dddmp/exp/test3.sh":F) chmod +x dddmp/exp/test3.sh ;; - "dddmp/exp/test4.sh":F) chmod +x dddmp/exp/test4.sh ;; - "dddmp/exp/test5.sh":F) chmod +x dddmp/exp/test5.sh ;; - "dddmp/exp/test6.sh":F) chmod +x dddmp/exp/test6.sh ;; - "dddmp/exp/test7.sh":F) chmod +x dddmp/exp/test7.sh ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - - -echo \ -"-------------------------------------------------- -Configuration summary for ${PACKAGE_NAME} ${PACKAGE_VERSION} - -Build system : ${build} -Host system : ${host} -Prefix : '${prefix}' -Compilers : '${CC} ${AM_CPPFLAGS} ${CPPFLAGS} ${AM_CFLAGS} ${CFLAGS}' - : '${CXX} ${AM_CPPFLAGS} ${CPPFLAGS} ${AM_CXXFLAGS} ${CXXFLAGS}' -Shared library : ${enable_shared} - dddmp enabled : ${enable_dddmp:-no} - obj enabled : ${enable_obj:-no} ---------------------------------------------------" diff --git a/resources/3rdparty/z3/output_version.cpp b/resources/3rdparty/z3/output_version.cpp new file mode 100644 index 000000000..3f631199e --- /dev/null +++ b/resources/3rdparty/z3/output_version.cpp @@ -0,0 +1,9 @@ +#include +#include + +int main() { + unsigned major, minor, build_number, revision_number; + Z3_get_version(&major, &minor, &build_number, &revision_number); + std::cout << major << "." << minor << "." << build_number << std::endl; + return 0; +} diff --git a/resources/cmake/find_modules/FindZ3.cmake b/resources/cmake/find_modules/FindZ3.cmake index cf838874d..d0978b3bc 100644 --- a/resources/cmake/find_modules/FindZ3.cmake +++ b/resources/cmake/find_modules/FindZ3.cmake @@ -10,7 +10,7 @@ # find include dir by searching for a concrete file, which definitely must be in it find_path(Z3_INCLUDE_DIR NAMES z3++.h - PATHS ENV PATH INCLUDE "/usr/include/z3" "/usr/local/include/z3/" "${Z3_ROOT}/include" + PATHS ENV PATH INCLUDE "${Z3_ROOT}/include" "/usr/include/z3" "/usr/local/include/z3/" ) # find library @@ -44,4 +44,4 @@ ENDIF (NOT Z3_FIND_QUIETLY) #message(${Z3_LIBRARY}) # make the set variables only visible in advanced mode -mark_as_advanced(Z3_LIBRARY Z3_INCLUDE_DIR Z3_SOLVER, Z3_EXEC) \ No newline at end of file +mark_as_advanced(Z3_LIBRARY Z3_INCLUDE_DIR Z3_SOLVER, Z3_EXEC) diff --git a/resources/cmake/macros/GetGitRevisionDescription.cmake b/resources/cmake/macros/GetGitRevisionDescription.cmake index 3653b95be..8ab03bc5f 100644 --- a/resources/cmake/macros/GetGitRevisionDescription.cmake +++ b/resources/cmake/macros/GetGitRevisionDescription.cmake @@ -18,6 +18,12 @@ # and adjusting the output so that it tests false if there was no exact # matching tag. # +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: @@ -37,10 +43,10 @@ set(__get_git_revision_description YES) # We must run the following at "include" time, not at function call time, # to find the path to this module rather than the path to a calling list file -get_filename_component(_gitdescmoddir GetGitRevisionDescription.cmake PATH) +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) function(get_git_head_revision _refspecvar _hashvar) - set(GIT_PARENT_DIR ${PROJECT_SOURCE_DIR}) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") set(GIT_DIR "${GIT_PARENT_DIR}/.git") while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") @@ -71,7 +77,7 @@ function(get_git_head_revision _refspecvar _hashvar) set(HEAD_FILE "${GIT_DATA}/HEAD") configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) - configure_file("${PROJECT_SOURCE_DIR}/resources/cmake/macros/GetGitRevisionDescription.cmake.in" + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" "${GIT_DATA}/grabRef.cmake" @ONLY) include("${GIT_DATA}/grabRef.cmake") @@ -110,7 +116,7 @@ function(git_describe _var) ${hash} ${ARGN} WORKING_DIRECTORY - "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE @@ -124,7 +130,12 @@ function(git_describe _var) set(${_var} "${out}" PARENT_SCOPE) endfunction() -function(git_describe_checkout _var) +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) if(NOT GIT_FOUND) find_package(Git QUIET) endif() @@ -138,39 +149,20 @@ function(git_describe_checkout _var) return() endif() - # TODO sanitize - #if((${ARGN}" MATCHES "&&") OR - # (ARGN MATCHES "||") OR - # (ARGN MATCHES "\\;")) - # message("Please report the following error to the project!") - # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") - #endif() - - #message(STATUS "Arguments to execute_process: ${ARGN}") - execute_process(COMMAND "${GIT_EXECUTABLE}" - describe - --tags - --dirty=-dirty - --long - ${ARGN} + diff-index --quiet HEAD -- WORKING_DIRECTORY - "${CMAKE_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}" RESULT_VARIABLE res OUTPUT_VARIABLE out ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT res EQUAL 0) - set(out "${out}-${res}-NOTFOUND") + if(res EQUAL 0) + set(${_var} "CLEAN" PARENT_SCOPE) + else() + set(${_var} "DIRTY" PARENT_SCOPE) endif() - - set(${_var} "${out}" PARENT_SCOPE) endfunction() - -function(git_get_exact_tag _var) - git_describe(out --exact-match ${ARGN}) - set(${_var} "${out}" PARENT_SCOPE) -endfunction() \ No newline at end of file diff --git a/resources/cmake/macros/GetGitRevisionDescription.cmake.in b/resources/cmake/macros/GetGitRevisionDescription.cmake.in index 30a115594..6d8b708ef 100644 --- a/resources/cmake/macros/GetGitRevisionDescription.cmake.in +++ b/resources/cmake/macros/GetGitRevisionDescription.cmake.in @@ -1,4 +1,4 @@ -# +# # Internal file for GetGitRevisionDescription.cmake # # Requires CMake 2.6 or newer (uses the 'function' command) @@ -23,9 +23,12 @@ if(HEAD_CONTENTS MATCHES "ref") string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") if(EXISTS "@GIT_DIR@/${HEAD_REF}") configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") - configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - set(HEAD_HASH "${HEAD_REF}") + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() endif() else() # detached HEAD @@ -35,4 +38,4 @@ endif() if(NOT HEAD_HASH) file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) string(STRIP "${HEAD_HASH}" HEAD_HASH) -endif() \ No newline at end of file +endif() diff --git a/resources/cmake/macros/export.cmake b/resources/cmake/macros/export.cmake index eb2e8fa84..606bde62f 100644 --- a/resources/cmake/macros/export.cmake +++ b/resources/cmake/macros/export.cmake @@ -8,7 +8,7 @@ message(STATUS "Registered with cmake") export(PACKAGE storm) set(DEP_TARGETS "") -foreach(dt ${STORM_DEP_TARGETS}) +foreach(dt ${STORM_DEP_TARGETS}) export_target(DEP_TARGETS ${dt}) endforeach() @@ -19,10 +19,26 @@ endforeach() include(CMakePackageConfigHelpers) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/stormConfigVersion.cmake + VERSION 0.1.0 + COMPATIBILITY SameMajorVersion ) + +# For the build tree set(CONF_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/include/") configure_package_config_file( resources/cmake/stormConfig.cmake.in ${PROJECT_BINARY_DIR}/stormConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_DIR} - PATH_VARS INCLUDE_INSTALL_DIR #SYSCONFIG_INSTALL_DIR + PATH_VARS INCLUDE_INSTALL_DIR +) + + # For the install tree +file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_DIR}" "${INCLUDE_INSTALL_DIR}") +set(CONF_INCLUDE_DIRS "\${storm_CMAKE_DIR}/${REL_INCLUDE_DIR}/storm") + +configure_package_config_file( + resources/cmake/stormConfig.cmake.in + ${PROJECT_BINARY_DIR}/stormConfig.install.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_DIR} + PATH_VARS INCLUDE_INSTALL_DIR ) diff --git a/resources/cmake/stormConfigVersion.cmake.in b/resources/cmake/stormConfigVersion.cmake.in new file mode 100644 index 000000000..d248393ad --- /dev/null +++ b/resources/cmake/stormConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION "@storm_VERSION@") + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/resources/examples/testfiles/ctmc/cluster2.drn b/resources/examples/testfiles/ctmc/cluster2.drn index a58875e50..4d32a5a0c 100644 --- a/resources/examples/testfiles/ctmc/cluster2.drn +++ b/resources/examples/testfiles/ctmc/cluster2.drn @@ -3,17 +3,19 @@ @type: CTMC @parameters +@reward_models +num_repairs @nr_states 276 @model -state 0 [0] init minimum premium +state 0 !0.0087 [0] init minimum premium action 0 [0] 1 : 0.004 2 : 0.004 3 : 0.0002 4 : 0.00025 5 : 0.00025 -state 1 [0] minimum premium +state 1 !10.0067 [0] minimum premium action 0 [0] 6 : 0.002 7 : 0.004 @@ -21,7 +23,7 @@ state 1 [0] minimum premium 9 : 0.00025 10 : 0.00025 11 : 10 -state 2 [0] minimum premium +state 2 !10.0067 [0] minimum premium action 0 [0] 7 : 0.004 12 : 0.002 @@ -29,35 +31,35 @@ state 2 [0] minimum premium 14 : 0.00025 15 : 0.00025 16 : 10 -state 3 [0] minimum premium +state 3 !10.0085 [0] minimum premium action 0 [0] 8 : 0.004 13 : 0.004 17 : 0.00025 18 : 0.00025 19 : 10 -state 4 [0] minimum premium +state 4 !10.0084 [0] minimum premium action 0 [0] 9 : 0.004 14 : 0.004 17 : 0.0002 20 : 0.00025 21 : 10 -state 5 [0] minimum premium +state 5 !10.0084 [0] minimum premium action 0 [0] 10 : 0.004 15 : 0.004 18 : 0.0002 20 : 0.00025 22 : 10 -state 6 [0] minimum premium +state 6 !10.0047 [0] minimum premium action 0 [0] 23 : 0.004 24 : 0.0002 25 : 0.00025 26 : 0.00025 27 : 10 -state 7 [0] minimum premium +state 7 !20.0047 [0] minimum premium action 0 [0] 23 : 0.002 28 : 0.002 @@ -66,7 +68,7 @@ state 7 [0] minimum premium 31 : 0.00025 32 : 10 33 : 10 -state 8 [0] minimum premium +state 8 !20.0065 [0] minimum premium action 0 [0] 24 : 0.002 29 : 0.004 @@ -74,7 +76,7 @@ state 8 [0] minimum premium 35 : 0.00025 36 : 10 37 : 10 -state 9 [0] minimum premium +state 9 !20.0065 [0] minimum premium action 0 [0] 25 : 0.002 30 : 0.004 @@ -82,7 +84,7 @@ state 9 [0] minimum premium 38 : 0.00025 39 : 10 40 : 10 -state 10 [0] minimum +state 10 !20.0065 [0] minimum action 0 [0] 26 : 0.002 31 : 0.004 @@ -90,7 +92,7 @@ state 10 [0] minimum 38 : 0.00025 41 : 10 42 : 10 -state 11 [0] minimum premium +state 11 !2.0067 [0] minimum premium action 0 [0.996661] 0 : 2 27 : 0.002 @@ -98,14 +100,14 @@ state 11 [0] minimum premium 36 : 0.0002 39 : 0.00025 41 : 0.00025 -state 12 [0] minimum premium +state 12 !10.0047 [0] minimum premium action 0 [0] 28 : 0.004 43 : 0.0002 44 : 0.00025 45 : 0.00025 46 : 10 -state 13 [0] minimum premium +state 13 !20.0065 [0] minimum premium action 0 [0] 29 : 0.004 43 : 0.002 @@ -113,7 +115,7 @@ state 13 [0] minimum premium 48 : 0.00025 49 : 10 50 : 10 -state 14 [0] minimum +state 14 !20.0065 [0] minimum action 0 [0] 30 : 0.004 44 : 0.002 @@ -121,7 +123,7 @@ state 14 [0] minimum 51 : 0.00025 52 : 10 53 : 10 -state 15 [0] minimum premium +state 15 !20.0065 [0] minimum premium action 0 [0] 31 : 0.004 45 : 0.002 @@ -129,7 +131,7 @@ state 15 [0] minimum premium 51 : 0.00025 54 : 10 55 : 10 -state 16 [0] minimum premium +state 16 !2.0067 [0] minimum premium action 0 [0.996661] 0 : 2 33 : 0.004 @@ -137,49 +139,49 @@ state 16 [0] minimum premium 49 : 0.0002 52 : 0.00025 54 : 0.00025 -state 17 [0] minimum premium +state 17 !20.0083 [0] minimum premium action 0 [0] 34 : 0.004 47 : 0.004 56 : 0.00025 57 : 10 58 : 10 -state 18 [0] minimum premium +state 18 !20.0083 [0] minimum premium action 0 [0] 35 : 0.004 48 : 0.004 56 : 0.00025 59 : 10 60 : 10 -state 19 [0] minimum premium +state 19 !0.1335 [0] minimum premium action 0 [0.93633] 0 : 0.125 37 : 0.004 50 : 0.004 58 : 0.00025 60 : 0.00025 -state 20 [0] +state 20 !20.0082 [0] action 0 [0] 38 : 0.004 51 : 0.004 56 : 0.0002 61 : 10 62 : 10 -state 21 [0] minimum premium +state 21 !0.25845 [0] minimum premium action 0 [0.967305] 0 : 0.25 40 : 0.004 53 : 0.004 57 : 0.0002 61 : 0.00025 -state 22 [0] minimum premium +state 22 !0.25845 [0] minimum premium action 0 [0.967305] 0 : 0.25 42 : 0.004 55 : 0.004 59 : 0.0002 62 : 0.00025 -state 23 [0] minimum +state 23 !20.0027 [0] minimum action 0 [0] 63 : 0.002 64 : 0.0002 @@ -187,35 +189,35 @@ state 23 [0] minimum 66 : 0.00025 67 : 10 68 : 10 -state 24 [0] minimum premium +state 24 !20.0045 [0] minimum premium action 0 [0] 64 : 0.004 69 : 0.00025 70 : 0.00025 71 : 10 72 : 10 -state 25 [0] minimum premium +state 25 !20.0044 [0] minimum premium action 0 [0] 65 : 0.004 69 : 0.0002 73 : 0.00025 74 : 10 75 : 10 -state 26 [0] +state 26 !20.0044 [0] action 0 [0] 66 : 0.004 70 : 0.0002 73 : 0.00025 76 : 10 77 : 10 -state 27 [0] minimum premium +state 27 !2.0047 [0] minimum premium action 0 [0.997656] 1 : 2 67 : 0.004 71 : 0.0002 74 : 0.00025 76 : 0.00025 -state 28 [0] minimum +state 28 !20.0027 [0] minimum action 0 [0] 63 : 0.002 78 : 0.0002 @@ -223,7 +225,7 @@ state 28 [0] minimum 80 : 0.00025 81 : 10 82 : 10 -state 29 [0] minimum +state 29 !30.0045 [0] minimum action 0 [0] 64 : 0.002 78 : 0.002 @@ -232,7 +234,7 @@ state 29 [0] minimum 85 : 10 86 : 10 87 : 10 -state 30 [0] minimum +state 30 !30.0044 [0] minimum action 0 [0] 65 : 0.002 79 : 0.002 @@ -241,7 +243,7 @@ state 30 [0] minimum 89 : 10 90 : 10 91 : 10 -state 31 [0] minimum +state 31 !30.0044 [0] minimum action 0 [0] 66 : 0.002 80 : 0.002 @@ -250,7 +252,7 @@ state 31 [0] minimum 92 : 10 93 : 10 94 : 10 -state 32 [0] minimum premium +state 32 !2.0047 [0] minimum premium action 0 [0.997656] 2 : 2 67 : 0.002 @@ -258,7 +260,7 @@ state 32 [0] minimum premium 85 : 0.0002 89 : 0.00025 92 : 0.00025 -state 33 [0] minimum premium +state 33 !2.0047 [0] minimum premium action 0 [0.997656] 1 : 2 68 : 0.002 @@ -266,7 +268,7 @@ state 33 [0] minimum premium 86 : 0.0002 90 : 0.00025 93 : 0.00025 -state 34 [0] minimum premium +state 34 !30.0063 [0] minimum premium action 0 [0] 69 : 0.002 83 : 0.004 @@ -274,7 +276,7 @@ state 34 [0] minimum premium 96 : 10 97 : 10 98 : 10 -state 35 [0] minimum +state 35 !30.0063 [0] minimum action 0 [0] 70 : 0.002 84 : 0.004 @@ -282,21 +284,21 @@ state 35 [0] minimum 99 : 10 100 : 10 101 : 10 -state 36 [0] minimum premium +state 36 !2.0065 [0] minimum premium action 0 [0.996761] 3 : 2 71 : 0.002 85 : 0.004 96 : 0.00025 99 : 0.00025 -state 37 [0] minimum premium +state 37 !0.1315 [0] minimum premium action 0 [0.95057] 1 : 0.125 72 : 0.002 87 : 0.004 98 : 0.00025 101 : 0.00025 -state 38 [0] +state 38 !30.0062 [0] action 0 [0] 73 : 0.002 88 : 0.004 @@ -304,63 +306,63 @@ state 38 [0] 102 : 10 103 : 10 104 : 10 -state 39 [0] minimum premium +state 39 !2.00645 [0] minimum premium action 0 [0.996785] 4 : 2 74 : 0.002 89 : 0.004 96 : 0.0002 102 : 0.00025 -state 40 [0] minimum premium +state 40 !0.25645 [0] minimum premium action 0 [0.974849] 1 : 0.25 75 : 0.002 91 : 0.004 97 : 0.0002 103 : 0.00025 -state 41 [0] minimum +state 41 !2.00645 [0] minimum action 0 [0.996785] 5 : 2 76 : 0.002 92 : 0.004 99 : 0.0002 102 : 0.00025 -state 42 [0] minimum +state 42 !0.25645 [0] minimum action 0 [0.974849] 1 : 0.25 77 : 0.002 94 : 0.004 100 : 0.0002 104 : 0.00025 -state 43 [0] minimum premium +state 43 !20.0045 [0] minimum premium action 0 [0] 78 : 0.004 105 : 0.00025 106 : 0.00025 107 : 10 108 : 10 -state 44 [0] +state 44 !20.0044 [0] action 0 [0] 79 : 0.004 105 : 0.0002 109 : 0.00025 110 : 10 111 : 10 -state 45 [0] minimum premium +state 45 !20.0044 [0] minimum premium action 0 [0] 80 : 0.004 106 : 0.0002 109 : 0.00025 112 : 10 113 : 10 -state 46 [0] minimum premium +state 46 !2.0047 [0] minimum premium action 0 [0.997656] 2 : 2 82 : 0.004 107 : 0.0002 110 : 0.00025 112 : 0.00025 -state 47 [0] minimum +state 47 !30.0063 [0] minimum action 0 [0] 83 : 0.004 105 : 0.002 @@ -368,7 +370,7 @@ state 47 [0] minimum 115 : 10 116 : 10 117 : 10 -state 48 [0] minimum premium +state 48 !30.0063 [0] minimum premium action 0 [0] 84 : 0.004 106 : 0.002 @@ -376,21 +378,21 @@ state 48 [0] minimum premium 118 : 10 119 : 10 120 : 10 -state 49 [0] minimum premium +state 49 !2.0065 [0] minimum premium action 0 [0.996761] 3 : 2 86 : 0.004 107 : 0.002 115 : 0.00025 118 : 0.00025 -state 50 [0] minimum premium +state 50 !0.1315 [0] minimum premium action 0 [0.95057] 2 : 0.125 87 : 0.004 108 : 0.002 117 : 0.00025 120 : 0.00025 -state 51 [0] +state 51 !30.0062 [0] action 0 [0] 88 : 0.004 109 : 0.002 @@ -398,85 +400,85 @@ state 51 [0] 121 : 10 122 : 10 123 : 10 -state 52 [0] minimum +state 52 !2.00645 [0] minimum action 0 [0.996785] 4 : 2 90 : 0.004 110 : 0.002 115 : 0.0002 121 : 0.00025 -state 53 [0] minimum +state 53 !0.25645 [0] minimum action 0 [0.974849] 2 : 0.25 91 : 0.004 111 : 0.002 116 : 0.0002 122 : 0.00025 -state 54 [0] minimum premium +state 54 !2.00645 [0] minimum premium action 0 [0.996785] 5 : 2 93 : 0.004 112 : 0.002 118 : 0.0002 121 : 0.00025 -state 55 [0] minimum premium +state 55 !0.25645 [0] minimum premium action 0 [0.974849] 2 : 0.25 94 : 0.004 113 : 0.002 119 : 0.0002 123 : 0.00025 -state 56 [0] +state 56 !30.008 [0] action 0 [0] 95 : 0.004 114 : 0.004 124 : 10 125 : 10 126 : 10 -state 57 [0] minimum premium +state 57 !0.25825 [0] minimum premium action 0 [0.968054] 3 : 0.25 97 : 0.004 116 : 0.004 124 : 0.00025 -state 58 [0] minimum premium +state 58 !0.13325 [0] minimum premium action 0 [0.938086] 4 : 0.125 98 : 0.004 117 : 0.004 126 : 0.00025 -state 59 [0] minimum premium +state 59 !0.25825 [0] minimum premium action 0 [0.968054] 3 : 0.25 100 : 0.004 119 : 0.004 125 : 0.00025 -state 60 [0] minimum premium +state 60 !0.13325 [0] minimum premium action 0 [0.938086] 5 : 0.125 101 : 0.004 120 : 0.004 126 : 0.00025 -state 61 [0] +state 61 !0.2582 [0] action 0 [0.968242] 5 : 0.25 103 : 0.004 122 : 0.004 124 : 0.0002 -state 62 [0] +state 62 !0.2582 [0] action 0 [0.968242] 4 : 0.25 104 : 0.004 123 : 0.004 125 : 0.0002 -state 63 [0] +state 63 !20.0007 [0] action 0 [0] 127 : 0.0002 128 : 0.00025 129 : 0.00025 130 : 10 131 : 10 -state 64 [0] minimum +state 64 !30.0025 [0] minimum action 0 [0] 127 : 0.002 132 : 0.00025 @@ -484,7 +486,7 @@ state 64 [0] minimum 134 : 10 135 : 10 136 : 10 -state 65 [0] minimum +state 65 !30.0024 [0] minimum action 0 [0] 128 : 0.002 132 : 0.0002 @@ -492,7 +494,7 @@ state 65 [0] minimum 138 : 10 139 : 10 140 : 10 -state 66 [0] +state 66 !30.0024 [0] action 0 [0] 129 : 0.002 133 : 0.0002 @@ -500,78 +502,78 @@ state 66 [0] 141 : 10 142 : 10 143 : 10 -state 67 [0] minimum +state 67 !2.0027 [0] minimum action 0 [0.998652] 7 : 2 130 : 0.002 134 : 0.0002 138 : 0.00025 141 : 0.00025 -state 68 [0] minimum +state 68 !2.0027 [0] minimum action 0 [0.998652] 6 : 2 131 : 0.002 135 : 0.0002 139 : 0.00025 142 : 0.00025 -state 69 [0] minimum premium +state 69 !30.0042 [0] minimum premium action 0 [0] 132 : 0.004 144 : 0.00025 145 : 10 146 : 10 147 : 10 -state 70 [0] +state 70 !30.0042 [0] action 0 [0] 133 : 0.004 144 : 0.00025 148 : 10 149 : 10 150 : 10 -state 71 [0] minimum premium +state 71 !2.0045 [0] minimum premium action 0 [0.997755] 8 : 2 134 : 0.004 145 : 0.00025 148 : 0.00025 -state 72 [0] minimum premium +state 72 !0.1295 [0] minimum premium action 0 [0.965251] 6 : 0.125 136 : 0.004 147 : 0.00025 150 : 0.00025 -state 73 [0] +state 73 !30.0042 [0] action 0 [0] 137 : 0.004 144 : 0.0002 151 : 10 152 : 10 153 : 10 -state 74 [0] minimum premium +state 74 !2.00445 [0] minimum premium action 0 [0.99778] 9 : 2 138 : 0.004 145 : 0.0002 151 : 0.00025 -state 75 [0] minimum premium +state 75 !0.25445 [0] minimum premium action 0 [0.982511] 6 : 0.25 140 : 0.004 146 : 0.0002 152 : 0.00025 -state 76 [0] +state 76 !2.00445 [0] action 0 [0.99778] 10 : 2 141 : 0.004 148 : 0.0002 151 : 0.00025 -state 77 [0] +state 77 !0.25445 [0] action 0 [0.982511] 6 : 0.25 143 : 0.004 149 : 0.0002 153 : 0.00025 -state 78 [0] minimum +state 78 !30.0025 [0] minimum action 0 [0] 127 : 0.002 154 : 0.00025 @@ -579,7 +581,7 @@ state 78 [0] minimum 156 : 10 157 : 10 158 : 10 -state 79 [0] +state 79 !30.0024 [0] action 0 [0] 128 : 0.002 154 : 0.0002 @@ -587,7 +589,7 @@ state 79 [0] 160 : 10 161 : 10 162 : 10 -state 80 [0] minimum +state 80 !30.0024 [0] minimum action 0 [0] 129 : 0.002 155 : 0.0002 @@ -595,21 +597,21 @@ state 80 [0] minimum 163 : 10 164 : 10 165 : 10 -state 81 [0] minimum +state 81 !2.0027 [0] minimum action 0 [0.998652] 12 : 2 130 : 0.002 156 : 0.0002 160 : 0.00025 163 : 0.00025 -state 82 [0] minimum +state 82 !2.0027 [0] minimum action 0 [0.998652] 7 : 2 131 : 0.002 157 : 0.0002 161 : 0.00025 164 : 0.00025 -state 83 [0] minimum +state 83 !40.0042 [0] minimum action 0 [0] 132 : 0.002 154 : 0.002 @@ -618,7 +620,7 @@ state 83 [0] minimum 168 : 10 169 : 10 170 : 10 -state 84 [0] minimum +state 84 !40.0042 [0] minimum action 0 [0] 133 : 0.002 155 : 0.002 @@ -627,28 +629,28 @@ state 84 [0] minimum 172 : 10 173 : 10 174 : 10 -state 85 [0] minimum +state 85 !2.0045 [0] minimum action 0 [0.997755] 13 : 2 134 : 0.002 156 : 0.002 167 : 0.00025 171 : 0.00025 -state 86 [0] minimum +state 86 !2.0045 [0] minimum action 0 [0.997755] 8 : 2 135 : 0.002 157 : 0.002 168 : 0.00025 172 : 0.00025 -state 87 [0] minimum +state 87 !0.1295 [0] minimum action 0 [0.965251] 7 : 0.125 136 : 0.002 158 : 0.002 170 : 0.00025 174 : 0.00025 -state 88 [0] +state 88 !40.0042 [0] action 0 [0] 137 : 0.002 159 : 0.002 @@ -657,49 +659,49 @@ state 88 [0] 176 : 10 177 : 10 178 : 10 -state 89 [0] minimum +state 89 !2.00445 [0] minimum action 0 [0.99778] 14 : 2 138 : 0.002 160 : 0.002 167 : 0.0002 175 : 0.00025 -state 90 [0] minimum +state 90 !2.00445 [0] minimum action 0 [0.99778] 9 : 2 139 : 0.002 161 : 0.002 168 : 0.0002 176 : 0.00025 -state 91 [0] minimum +state 91 !0.25445 [0] minimum action 0 [0.982511] 7 : 0.25 140 : 0.002 162 : 0.002 169 : 0.0002 177 : 0.00025 -state 92 [0] minimum +state 92 !2.00445 [0] minimum action 0 [0.99778] 15 : 2 141 : 0.002 163 : 0.002 171 : 0.0002 175 : 0.00025 -state 93 [0] minimum +state 93 !2.00445 [0] minimum action 0 [0.99778] 10 : 2 142 : 0.002 164 : 0.002 172 : 0.0002 176 : 0.00025 -state 94 [0] minimum +state 94 !0.25445 [0] minimum action 0 [0.982511] 7 : 0.25 143 : 0.002 165 : 0.002 173 : 0.0002 178 : 0.00025 -state 95 [0] +state 95 !40.006 [0] action 0 [0] 144 : 0.002 166 : 0.004 @@ -707,118 +709,118 @@ state 95 [0] 180 : 10 181 : 10 182 : 10 -state 96 [0] minimum premium +state 96 !2.00625 [0] minimum premium action 0 [0.996885] 17 : 2 145 : 0.002 167 : 0.004 179 : 0.00025 -state 97 [0] minimum premium +state 97 !0.25625 [0] minimum premium action 0 [0.97561] 8 : 0.25 146 : 0.002 169 : 0.004 180 : 0.00025 -state 98 [0] minimum premium +state 98 !0.13125 [0] minimum premium action 0 [0.952381] 9 : 0.125 147 : 0.002 170 : 0.004 182 : 0.00025 -state 99 [0] minimum +state 99 !2.00625 [0] minimum action 0 [0.996885] 18 : 2 148 : 0.002 171 : 0.004 179 : 0.00025 -state 100 [0] minimum +state 100 !0.25625 [0] minimum action 0 [0.97561] 8 : 0.25 149 : 0.002 173 : 0.004 181 : 0.00025 -state 101 [0] minimum +state 101 !0.13125 [0] minimum action 0 [0.952381] 10 : 0.125 150 : 0.002 174 : 0.004 182 : 0.00025 -state 102 [0] +state 102 !2.0062 [0] action 0 [0.99691] 20 : 2 151 : 0.002 175 : 0.004 179 : 0.0002 -state 103 [0] +state 103 !0.2562 [0] action 0 [0.9758] 10 : 0.25 152 : 0.002 177 : 0.004 180 : 0.0002 -state 104 [0] +state 104 !0.2562 [0] action 0 [0.9758] 9 : 0.25 153 : 0.002 178 : 0.004 181 : 0.0002 -state 105 [0] +state 105 !30.0042 [0] action 0 [0] 154 : 0.004 183 : 0.00025 184 : 10 185 : 10 186 : 10 -state 106 [0] minimum premium +state 106 !30.0042 [0] minimum premium action 0 [0] 155 : 0.004 183 : 0.00025 187 : 10 188 : 10 189 : 10 -state 107 [0] minimum premium +state 107 !2.0045 [0] minimum premium action 0 [0.997755] 13 : 2 157 : 0.004 184 : 0.00025 187 : 0.00025 -state 108 [0] minimum premium +state 108 !0.1295 [0] minimum premium action 0 [0.965251] 12 : 0.125 158 : 0.004 186 : 0.00025 189 : 0.00025 -state 109 [0] +state 109 !30.0042 [0] action 0 [0] 159 : 0.004 183 : 0.0002 190 : 10 191 : 10 192 : 10 -state 110 [0] +state 110 !2.00445 [0] action 0 [0.99778] 14 : 2 161 : 0.004 184 : 0.0002 190 : 0.00025 -state 111 [0] +state 111 !0.25445 [0] action 0 [0.982511] 12 : 0.25 162 : 0.004 185 : 0.0002 191 : 0.00025 -state 112 [0] minimum premium +state 112 !2.00445 [0] minimum premium action 0 [0.99778] 15 : 2 164 : 0.004 187 : 0.0002 190 : 0.00025 -state 113 [0] minimum premium +state 113 !0.25445 [0] minimum premium action 0 [0.982511] 12 : 0.25 165 : 0.004 188 : 0.0002 192 : 0.00025 -state 114 [0] +state 114 !40.006 [0] action 0 [0] 166 : 0.004 183 : 0.002 @@ -826,109 +828,109 @@ state 114 [0] 194 : 10 195 : 10 196 : 10 -state 115 [0] minimum +state 115 !2.00625 [0] minimum action 0 [0.996885] 17 : 2 168 : 0.004 184 : 0.002 193 : 0.00025 -state 116 [0] minimum +state 116 !0.25625 [0] minimum action 0 [0.97561] 13 : 0.25 169 : 0.004 185 : 0.002 194 : 0.00025 -state 117 [0] minimum +state 117 !0.13125 [0] minimum action 0 [0.952381] 14 : 0.125 170 : 0.004 186 : 0.002 196 : 0.00025 -state 118 [0] minimum premium +state 118 !2.00625 [0] minimum premium action 0 [0.996885] 18 : 2 172 : 0.004 187 : 0.002 193 : 0.00025 -state 119 [0] minimum premium +state 119 !0.25625 [0] minimum premium action 0 [0.97561] 13 : 0.25 173 : 0.004 188 : 0.002 195 : 0.00025 -state 120 [0] minimum premium +state 120 !0.13125 [0] minimum premium action 0 [0.952381] 15 : 0.125 174 : 0.004 189 : 0.002 196 : 0.00025 -state 121 [0] +state 121 !2.0062 [0] action 0 [0.99691] 20 : 2 176 : 0.004 190 : 0.002 193 : 0.0002 -state 122 [0] +state 122 !0.2562 [0] action 0 [0.9758] 15 : 0.25 177 : 0.004 191 : 0.002 194 : 0.0002 -state 123 [0] +state 123 !0.2562 [0] action 0 [0.9758] 14 : 0.25 178 : 0.004 192 : 0.002 195 : 0.0002 -state 124 [0] +state 124 !0.258 [0] action 0 [0.968992] 18 : 0.25 180 : 0.004 194 : 0.004 -state 125 [0] +state 125 !0.258 [0] action 0 [0.968992] 17 : 0.25 181 : 0.004 195 : 0.004 -state 126 [0] +state 126 !0.133 [0] action 0 [0.93985] 20 : 0.125 182 : 0.004 196 : 0.004 -state 127 [0] +state 127 !30.0005 [0] action 0 [0] 197 : 0.00025 198 : 0.00025 199 : 10 200 : 10 201 : 10 -state 128 [0] +state 128 !30.0005 [0] action 0 [0] 197 : 0.0002 202 : 0.00025 203 : 10 204 : 10 205 : 10 -state 129 [0] +state 129 !30.0005 [0] action 0 [0] 198 : 0.0002 202 : 0.00025 206 : 10 207 : 10 208 : 10 -state 130 [0] +state 130 !2.0007 [0] action 0 [0.99965] 28 : 2 199 : 0.0002 203 : 0.00025 206 : 0.00025 -state 131 [0] +state 131 !2.0007 [0] action 0 [0.99965] 23 : 2 200 : 0.0002 204 : 0.00025 207 : 0.00025 -state 132 [0] minimum +state 132 !40.0023 [0] minimum action 0 [0] 197 : 0.002 209 : 0.00025 @@ -936,7 +938,7 @@ state 132 [0] minimum 211 : 10 212 : 10 213 : 10 -state 133 [0] +state 133 !40.0023 [0] action 0 [0] 198 : 0.002 209 : 0.00025 @@ -944,25 +946,25 @@ state 133 [0] 215 : 10 216 : 10 217 : 10 -state 134 [0] minimum +state 134 !2.0025 [0] minimum action 0 [0.998752] 29 : 2 199 : 0.002 210 : 0.00025 214 : 0.00025 -state 135 [0] minimum +state 135 !2.0025 [0] minimum action 0 [0.998752] 24 : 2 200 : 0.002 211 : 0.00025 215 : 0.00025 -state 136 [0] minimum +state 136 !0.1275 [0] minimum action 0 [0.980392] 23 : 0.125 201 : 0.002 213 : 0.00025 217 : 0.00025 -state 137 [0] +state 137 !40.0022 [0] action 0 [0] 202 : 0.002 209 : 0.0002 @@ -970,95 +972,95 @@ state 137 [0] 219 : 10 220 : 10 221 : 10 -state 138 [0] minimum +state 138 !2.00245 [0] minimum action 0 [0.998776] 30 : 2 203 : 0.002 210 : 0.0002 218 : 0.00025 -state 139 [0] minimum +state 139 !2.00245 [0] minimum action 0 [0.998776] 25 : 2 204 : 0.002 211 : 0.0002 219 : 0.00025 -state 140 [0] minimum +state 140 !0.25245 [0] minimum action 0 [0.990295] 23 : 0.25 205 : 0.002 212 : 0.0002 220 : 0.00025 -state 141 [0] +state 141 !2.00245 [0] action 0 [0.998776] 31 : 2 206 : 0.002 214 : 0.0002 218 : 0.00025 -state 142 [0] +state 142 !2.00245 [0] action 0 [0.998776] 26 : 2 207 : 0.002 215 : 0.0002 219 : 0.00025 -state 143 [0] +state 143 !0.25245 [0] action 0 [0.990295] 23 : 0.25 208 : 0.002 216 : 0.0002 221 : 0.00025 -state 144 [0] +state 144 !40.004 [0] action 0 [0] 209 : 0.004 222 : 10 223 : 10 224 : 10 225 : 10 -state 145 [0] minimum premium +state 145 !2.00425 [0] minimum premium action 0 [0.99788] 34 : 2 210 : 0.004 222 : 0.00025 -state 146 [0] minimum premium +state 146 !0.25425 [0] minimum premium action 0 [0.983284] 24 : 0.25 212 : 0.004 223 : 0.00025 -state 147 [0] minimum premium +state 147 !0.12925 [0] minimum premium action 0 [0.967118] 25 : 0.125 213 : 0.004 225 : 0.00025 -state 148 [0] +state 148 !2.00425 [0] action 0 [0.99788] 35 : 2 214 : 0.004 222 : 0.00025 -state 149 [0] +state 149 !0.25425 [0] action 0 [0.983284] 24 : 0.25 216 : 0.004 224 : 0.00025 -state 150 [0] +state 150 !0.12925 [0] action 0 [0.967118] 26 : 0.125 217 : 0.004 225 : 0.00025 -state 151 [0] +state 151 !2.0042 [0] action 0 [0.997904] 38 : 2 218 : 0.004 222 : 0.0002 -state 152 [0] +state 152 !0.2542 [0] action 0 [0.983478] 26 : 0.25 220 : 0.004 223 : 0.0002 -state 153 [0] +state 153 !0.2542 [0] action 0 [0.983478] 25 : 0.25 221 : 0.004 224 : 0.0002 -state 154 [0] +state 154 !40.0023 [0] action 0 [0] 197 : 0.002 226 : 0.00025 @@ -1066,7 +1068,7 @@ state 154 [0] 228 : 10 229 : 10 230 : 10 -state 155 [0] minimum +state 155 !40.0023 [0] minimum action 0 [0] 198 : 0.002 226 : 0.00025 @@ -1074,25 +1076,25 @@ state 155 [0] minimum 232 : 10 233 : 10 234 : 10 -state 156 [0] minimum +state 156 !2.0025 [0] minimum action 0 [0.998752] 43 : 2 199 : 0.002 227 : 0.00025 231 : 0.00025 -state 157 [0] minimum +state 157 !2.0025 [0] minimum action 0 [0.998752] 29 : 2 200 : 0.002 228 : 0.00025 232 : 0.00025 -state 158 [0] minimum +state 158 !0.1275 [0] minimum action 0 [0.980392] 28 : 0.125 201 : 0.002 230 : 0.00025 234 : 0.00025 -state 159 [0] +state 159 !40.0022 [0] action 0 [0] 202 : 0.002 226 : 0.0002 @@ -1100,43 +1102,43 @@ state 159 [0] 236 : 10 237 : 10 238 : 10 -state 160 [0] +state 160 !2.00245 [0] action 0 [0.998776] 44 : 2 203 : 0.002 227 : 0.0002 235 : 0.00025 -state 161 [0] +state 161 !2.00245 [0] action 0 [0.998776] 30 : 2 204 : 0.002 228 : 0.0002 236 : 0.00025 -state 162 [0] +state 162 !0.25245 [0] action 0 [0.990295] 28 : 0.25 205 : 0.002 229 : 0.0002 237 : 0.00025 -state 163 [0] minimum +state 163 !2.00245 [0] minimum action 0 [0.998776] 45 : 2 206 : 0.002 231 : 0.0002 235 : 0.00025 -state 164 [0] minimum +state 164 !2.00245 [0] minimum action 0 [0.998776] 31 : 2 207 : 0.002 232 : 0.0002 236 : 0.00025 -state 165 [0] minimum +state 165 !0.25245 [0] minimum action 0 [0.990295] 28 : 0.25 208 : 0.002 233 : 0.0002 238 : 0.00025 -state 166 [0] +state 166 !50.004 [0] action 0 [0] 209 : 0.002 226 : 0.002 @@ -1145,237 +1147,237 @@ state 166 [0] 241 : 10 242 : 10 243 : 10 -state 167 [0] minimum +state 167 !2.00425 [0] minimum action 0 [0.99788] 47 : 2 210 : 0.002 227 : 0.002 239 : 0.00025 -state 168 [0] minimum +state 168 !2.00425 [0] minimum action 0 [0.99788] 34 : 2 211 : 0.002 228 : 0.002 240 : 0.00025 -state 169 [0] minimum +state 169 !0.25425 [0] minimum action 0 [0.983284] 29 : 0.25 212 : 0.002 229 : 0.002 241 : 0.00025 -state 170 [0] minimum +state 170 !0.12925 [0] minimum action 0 [0.967118] 30 : 0.125 213 : 0.002 230 : 0.002 243 : 0.00025 -state 171 [0] minimum +state 171 !2.00425 [0] minimum action 0 [0.99788] 48 : 2 214 : 0.002 231 : 0.002 239 : 0.00025 -state 172 [0] minimum +state 172 !2.00425 [0] minimum action 0 [0.99788] 35 : 2 215 : 0.002 232 : 0.002 240 : 0.00025 -state 173 [0] minimum +state 173 !0.25425 [0] minimum action 0 [0.983284] 29 : 0.25 216 : 0.002 233 : 0.002 242 : 0.00025 -state 174 [0] minimum +state 174 !0.12925 [0] minimum action 0 [0.967118] 31 : 0.125 217 : 0.002 234 : 0.002 243 : 0.00025 -state 175 [0] +state 175 !2.0042 [0] action 0 [0.997904] 51 : 2 218 : 0.002 235 : 0.002 239 : 0.0002 -state 176 [0] +state 176 !2.0042 [0] action 0 [0.997904] 38 : 2 219 : 0.002 236 : 0.002 240 : 0.0002 -state 177 [0] +state 177 !0.2542 [0] action 0 [0.983478] 31 : 0.25 220 : 0.002 237 : 0.002 241 : 0.0002 -state 178 [0] +state 178 !0.2542 [0] action 0 [0.983478] 30 : 0.25 221 : 0.002 238 : 0.002 242 : 0.0002 -state 179 [0] +state 179 !2.006 [0] action 0 [0.997009] 56 : 2 222 : 0.002 239 : 0.004 -state 180 [0] +state 180 !0.256 [0] action 0 [0.976562] 35 : 0.25 223 : 0.002 241 : 0.004 -state 181 [0] +state 181 !0.256 [0] action 0 [0.976562] 34 : 0.25 224 : 0.002 242 : 0.004 -state 182 [0] +state 182 !0.131 [0] action 0 [0.954198] 38 : 0.125 225 : 0.002 243 : 0.004 -state 183 [0] +state 183 !40.004 [0] action 0 [0] 226 : 0.004 244 : 10 245 : 10 246 : 10 247 : 10 -state 184 [0] +state 184 !2.00425 [0] action 0 [0.99788] 47 : 2 228 : 0.004 244 : 0.00025 -state 185 [0] +state 185 !0.25425 [0] action 0 [0.983284] 43 : 0.25 229 : 0.004 245 : 0.00025 -state 186 [0] +state 186 !0.12925 [0] action 0 [0.967118] 44 : 0.125 230 : 0.004 247 : 0.00025 -state 187 [0] minimum premium +state 187 !2.00425 [0] minimum premium action 0 [0.99788] 48 : 2 232 : 0.004 244 : 0.00025 -state 188 [0] minimum premium +state 188 !0.25425 [0] minimum premium action 0 [0.983284] 43 : 0.25 233 : 0.004 246 : 0.00025 -state 189 [0] minimum premium +state 189 !0.12925 [0] minimum premium action 0 [0.967118] 45 : 0.125 234 : 0.004 247 : 0.00025 -state 190 [0] +state 190 !2.0042 [0] action 0 [0.997904] 51 : 2 236 : 0.004 244 : 0.0002 -state 191 [0] +state 191 !0.2542 [0] action 0 [0.983478] 45 : 0.25 237 : 0.004 245 : 0.0002 -state 192 [0] +state 192 !0.2542 [0] action 0 [0.983478] 44 : 0.25 238 : 0.004 246 : 0.0002 -state 193 [0] +state 193 !2.006 [0] action 0 [0.997009] 56 : 2 240 : 0.004 244 : 0.002 -state 194 [0] +state 194 !0.256 [0] action 0 [0.976562] 48 : 0.25 241 : 0.004 245 : 0.002 -state 195 [0] +state 195 !0.256 [0] action 0 [0.976562] 47 : 0.25 242 : 0.004 246 : 0.002 -state 196 [0] +state 196 !0.131 [0] action 0 [0.954198] 51 : 0.125 243 : 0.004 247 : 0.002 -state 197 [0] +state 197 !40.0003 [0] action 0 [0] 248 : 0.00025 249 : 10 250 : 10 251 : 10 252 : 10 -state 198 [0] +state 198 !40.0003 [0] action 0 [0] 248 : 0.00025 253 : 10 254 : 10 255 : 10 256 : 10 -state 199 [0] +state 199 !2.0005 [0] action 0 [0.99975] 78 : 2 249 : 0.00025 253 : 0.00025 -state 200 [0] +state 200 !2.0005 [0] action 0 [0.99975] 64 : 2 250 : 0.00025 254 : 0.00025 -state 201 [0] +state 201 !0.1255 [0] action 0 [0.996016] 63 : 0.125 252 : 0.00025 256 : 0.00025 -state 202 [0] +state 202 !40.0002 [0] action 0 [0] 248 : 0.0002 257 : 10 258 : 10 259 : 10 260 : 10 -state 203 [0] +state 203 !2.00045 [0] action 0 [0.999775] 79 : 2 249 : 0.0002 257 : 0.00025 -state 204 [0] +state 204 !2.00045 [0] action 0 [0.999775] 65 : 2 250 : 0.0002 258 : 0.00025 -state 205 [0] +state 205 !0.25045 [0] action 0 [0.998203] 63 : 0.25 251 : 0.0002 259 : 0.00025 -state 206 [0] +state 206 !2.00045 [0] action 0 [0.999775] 80 : 2 253 : 0.0002 257 : 0.00025 -state 207 [0] +state 207 !2.00045 [0] action 0 [0.999775] 66 : 2 254 : 0.0002 258 : 0.00025 -state 208 [0] +state 208 !0.25045 [0] action 0 [0.998203] 63 : 0.25 255 : 0.0002 260 : 0.00025 -state 209 [0] +state 209 !50.002 [0] action 0 [0] 248 : 0.002 261 : 10 @@ -1383,83 +1385,83 @@ state 209 [0] 263 : 10 264 : 10 265 : 10 -state 210 [0] minimum +state 210 !2.00225 [0] minimum action 0 [0.998876] 83 : 2 249 : 0.002 261 : 0.00025 -state 211 [0] minimum +state 211 !2.00225 [0] minimum action 0 [0.998876] 69 : 2 250 : 0.002 262 : 0.00025 -state 212 [0] minimum +state 212 !0.25225 [0] minimum action 0 [0.99108] 64 : 0.25 251 : 0.002 263 : 0.00025 -state 213 [0] minimum +state 213 !0.12725 [0] minimum action 0 [0.982318] 65 : 0.125 252 : 0.002 265 : 0.00025 -state 214 [0] +state 214 !2.00225 [0] action 0 [0.998876] 84 : 2 253 : 0.002 261 : 0.00025 -state 215 [0] +state 215 !2.00225 [0] action 0 [0.998876] 70 : 2 254 : 0.002 262 : 0.00025 -state 216 [0] +state 216 !0.25225 [0] action 0 [0.99108] 64 : 0.25 255 : 0.002 264 : 0.00025 -state 217 [0] +state 217 !0.12725 [0] action 0 [0.982318] 66 : 0.125 256 : 0.002 265 : 0.00025 -state 218 [0] +state 218 !2.0022 [0] action 0 [0.998901] 88 : 2 257 : 0.002 261 : 0.0002 -state 219 [0] +state 219 !2.0022 [0] action 0 [0.998901] 73 : 2 258 : 0.002 262 : 0.0002 -state 220 [0] +state 220 !0.2522 [0] action 0 [0.991277] 66 : 0.25 259 : 0.002 263 : 0.0002 -state 221 [0] +state 221 !0.2522 [0] action 0 [0.991277] 65 : 0.25 260 : 0.002 264 : 0.0002 -state 222 [0] +state 222 !2.004 [0] action 0 [0.998004] 95 : 2 261 : 0.004 -state 223 [0] +state 223 !0.254 [0] action 0 [0.984252] 70 : 0.25 263 : 0.004 -state 224 [0] +state 224 !0.254 [0] action 0 [0.984252] 69 : 0.25 264 : 0.004 -state 225 [0] +state 225 !0.129 [0] action 0 [0.968992] 73 : 0.125 265 : 0.004 -state 226 [0] +state 226 !50.002 [0] action 0 [0] 248 : 0.002 266 : 10 @@ -1467,214 +1469,214 @@ state 226 [0] 268 : 10 269 : 10 270 : 10 -state 227 [0] +state 227 !2.00225 [0] action 0 [0.998876] 105 : 2 249 : 0.002 266 : 0.00025 -state 228 [0] +state 228 !2.00225 [0] action 0 [0.998876] 83 : 2 250 : 0.002 267 : 0.00025 -state 229 [0] +state 229 !0.25225 [0] action 0 [0.99108] 78 : 0.25 251 : 0.002 268 : 0.00025 -state 230 [0] +state 230 !0.12725 [0] action 0 [0.982318] 79 : 0.125 252 : 0.002 270 : 0.00025 -state 231 [0] minimum +state 231 !2.00225 [0] minimum action 0 [0.998876] 106 : 2 253 : 0.002 266 : 0.00025 -state 232 [0] minimum +state 232 !2.00225 [0] minimum action 0 [0.998876] 84 : 2 254 : 0.002 267 : 0.00025 -state 233 [0] minimum +state 233 !0.25225 [0] minimum action 0 [0.99108] 78 : 0.25 255 : 0.002 269 : 0.00025 -state 234 [0] minimum +state 234 !0.12725 [0] minimum action 0 [0.982318] 80 : 0.125 256 : 0.002 270 : 0.00025 -state 235 [0] +state 235 !2.0022 [0] action 0 [0.998901] 109 : 2 257 : 0.002 266 : 0.0002 -state 236 [0] +state 236 !2.0022 [0] action 0 [0.998901] 88 : 2 258 : 0.002 267 : 0.0002 -state 237 [0] +state 237 !0.2522 [0] action 0 [0.991277] 80 : 0.25 259 : 0.002 268 : 0.0002 -state 238 [0] +state 238 !0.2522 [0] action 0 [0.991277] 79 : 0.25 260 : 0.002 269 : 0.0002 -state 239 [0] +state 239 !2.004 [0] action 0 [0.998004] 114 : 2 261 : 0.002 266 : 0.002 -state 240 [0] +state 240 !2.004 [0] action 0 [0.998004] 95 : 2 262 : 0.002 267 : 0.002 -state 241 [0] +state 241 !0.254 [0] action 0 [0.984252] 84 : 0.25 263 : 0.002 268 : 0.002 -state 242 [0] +state 242 !0.254 [0] action 0 [0.984252] 83 : 0.25 264 : 0.002 269 : 0.002 -state 243 [0] +state 243 !0.129 [0] action 0 [0.968992] 88 : 0.125 265 : 0.002 270 : 0.002 -state 244 [0] +state 244 !2.004 [0] action 0 [0.998004] 114 : 2 267 : 0.004 -state 245 [0] +state 245 !0.254 [0] action 0 [0.984252] 106 : 0.25 268 : 0.004 -state 246 [0] +state 246 !0.254 [0] action 0 [0.984252] 105 : 0.25 269 : 0.004 -state 247 [0] +state 247 !0.129 [0] action 0 [0.968992] 109 : 0.125 270 : 0.004 -state 248 [0] +state 248 !50 [0] action 0 [0] 271 : 10 272 : 10 273 : 10 274 : 10 275 : 10 -state 249 [0] +state 249 !2.00025 [0] action 0 [0.999875] 154 : 2 271 : 0.00025 -state 250 [0] +state 250 !2.00025 [0] action 0 [0.999875] 132 : 2 272 : 0.00025 -state 251 [0] +state 251 !0.25025 [0] action 0 [0.999001] 127 : 0.25 273 : 0.00025 -state 252 [0] +state 252 !0.12525 [0] action 0 [0.998004] 128 : 0.125 275 : 0.00025 -state 253 [0] +state 253 !2.00025 [0] action 0 [0.999875] 155 : 2 271 : 0.00025 -state 254 [0] +state 254 !2.00025 [0] action 0 [0.999875] 133 : 2 272 : 0.00025 -state 255 [0] +state 255 !0.25025 [0] action 0 [0.999001] 127 : 0.25 274 : 0.00025 -state 256 [0] +state 256 !0.12525 [0] action 0 [0.998004] 129 : 0.125 275 : 0.00025 -state 257 [0] +state 257 !2.0002 [0] action 0 [0.9999] 159 : 2 271 : 0.0002 -state 258 [0] +state 258 !2.0002 [0] action 0 [0.9999] 137 : 2 272 : 0.0002 -state 259 [0] +state 259 !0.2502 [0] action 0 [0.999201] 129 : 0.25 273 : 0.0002 -state 260 [0] +state 260 !0.2502 [0] action 0 [0.999201] 128 : 0.25 274 : 0.0002 -state 261 [0] +state 261 !2.002 [0] action 0 [0.999001] 166 : 2 271 : 0.002 -state 262 [0] +state 262 !2.002 [0] action 0 [0.999001] 144 : 2 272 : 0.002 -state 263 [0] +state 263 !0.252 [0] action 0 [0.992063] 133 : 0.25 273 : 0.002 -state 264 [0] +state 264 !0.252 [0] action 0 [0.992063] 132 : 0.25 274 : 0.002 -state 265 [0] +state 265 !0.127 [0] action 0 [0.984252] 137 : 0.125 275 : 0.002 -state 266 [0] +state 266 !2.002 [0] action 0 [0.999001] 183 : 2 271 : 0.002 -state 267 [0] +state 267 !2.002 [0] action 0 [0.999001] 166 : 2 272 : 0.002 -state 268 [0] +state 268 !0.252 [0] action 0 [0.992063] 155 : 0.25 273 : 0.002 -state 269 [0] +state 269 !0.252 [0] action 0 [0.992063] 154 : 0.25 274 : 0.002 -state 270 [0] +state 270 !0.127 [0] action 0 [0.984252] 159 : 0.125 275 : 0.002 -state 271 [0] +state 271 !2 [0] action 0 [1] 226 : 2 -state 272 [0] +state 272 !2 [0] action 0 [1] 209 : 2 -state 273 [0] +state 273 !0.25 [0] action 0 [1] 198 : 0.25 -state 274 [0] +state 274 !0.25 [0] action 0 [1] 197 : 0.25 -state 275 [0] +state 275 !0.125 [0] action 0 [1] 202 : 0.125 diff --git a/resources/examples/testfiles/ctmc/simple2.sm b/resources/examples/testfiles/ctmc/simple2.sm new file mode 100644 index 000000000..5fcc0dcab --- /dev/null +++ b/resources/examples/testfiles/ctmc/simple2.sm @@ -0,0 +1,28 @@ + +ctmc + + +module main + + s : [0..4]; // current state: + + + <> s=0 -> 4 : (s'=1) + 4 : (s'=2); + <> s=1 -> 0.3 : (s'=2) + 0.7 : (s'=1); + <> s=2 -> 0.5 : (s'=2) + 0.5 : (s'=3); + <> s=3 -> 1 : (s'=4); + <> s=4 -> 1 : (s'=3); + +endmodule + +rewards "rew1" + s=0 : 7; + [] s=2 : 1; +endrewards + + +rewards "rew2" + s=0 : 7; + [] s=2 : 1; + [] s=4 : 100; +endrewards diff --git a/resources/examples/testfiles/dft/and.dft b/resources/examples/testfiles/dft/and.dft new file mode 100644 index 000000000..2b06cbe95 --- /dev/null +++ b/resources/examples/testfiles/dft/and.dft @@ -0,0 +1,4 @@ +toplevel "A"; +"A" and "B" "C"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/and.json b/resources/examples/testfiles/dft/and.json new file mode 100644 index 000000000..e6c0c0f2e --- /dev/null +++ b/resources/examples/testfiles/dft/and.json @@ -0,0 +1,71 @@ +{ + "toplevel": "2", + "parameters": {}, + "nodes": [ + { + "data": { + "id": "0", + "name": "A", + "type": "be", + "rate": "1", + "dorm": "1", + "label": "A (1)" + }, + "position": { + "x": 440, + "y": 260 + }, + "group": "nodes", + "removed": false, + "selected": false, + "selectable": true, + "locked": false, + "grabbable": true, + "classes": "be" + }, + { + "data": { + "id": "1", + "name": "B", + "type": "be", + "rate": "1", + "dorm": "1", + "label": "B (1)" + }, + "position": { + "x": 548, + "y": 265 + }, + "group": "nodes", + "removed": false, + "selected": false, + "selectable": true, + "locked": false, + "grabbable": true, + "classes": "be" + }, + { + "data": { + "id": "2", + "name": "Z", + "type": "and", + "children": [ + "0", + "1" + ], + "label": "Z" + }, + "position": { + "x": 505, + "y": 119 + }, + "group": "nodes", + "removed": false, + "selected": false, + "selectable": true, + "locked": false, + "grabbable": true, + "classes": "and" + } + ] +} diff --git a/resources/examples/testfiles/dft/fdep.dft b/resources/examples/testfiles/dft/fdep.dft new file mode 100644 index 000000000..e597c46ce --- /dev/null +++ b/resources/examples/testfiles/dft/fdep.dft @@ -0,0 +1,8 @@ +toplevel "System"; +"System" or "Power" "Machine"; +"Power" fdep "B_Power" "P" "B"; +"Machine" or "P" "B"; + +"B_Power" lambda=0.5 dorm=0; +"P" lambda=0.5 dorm=0; +"B" lambda=0.5 dorm=0.5; diff --git a/resources/examples/testfiles/dft/fdep2.dft b/resources/examples/testfiles/dft/fdep2.dft new file mode 100644 index 000000000..a444ed4be --- /dev/null +++ b/resources/examples/testfiles/dft/fdep2.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C"; +"F" fdep "B" "C"; +"B" lambda=0.5 dorm=0; +"C" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/fdep3.dft b/resources/examples/testfiles/dft/fdep3.dft new file mode 100644 index 000000000..3815c9973 --- /dev/null +++ b/resources/examples/testfiles/dft/fdep3.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C" "F"; +"F" fdep "B" "C"; +"B" lambda=0.4 dorm=0; +"C" lambda=0.8 dorm=0; diff --git a/resources/examples/testfiles/dft/fdep4.dft b/resources/examples/testfiles/dft/fdep4.dft new file mode 100644 index 000000000..7e3c5642a --- /dev/null +++ b/resources/examples/testfiles/dft/fdep4.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" or "F" "B"; +"F" fdep "E" "C" "D"; +"B" wsp "C" "D"; +"C" lambda=1 dorm=0; +"D" lambda=1 dorm=0.5; +"E" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/fdep5.dft b/resources/examples/testfiles/dft/fdep5.dft new file mode 100644 index 000000000..2e0625dfb --- /dev/null +++ b/resources/examples/testfiles/dft/fdep5.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" and "B" "C" "D" "E"; +"F" fdep "B" "C" "D"; +"B" lambda=0.5 dorm=0; +"C" lambda=0.5 dorm=0; +"D" lambda=0.5 dorm=0; +"E" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/or.dft b/resources/examples/testfiles/dft/or.dft new file mode 100644 index 000000000..b1003da11 --- /dev/null +++ b/resources/examples/testfiles/dft/or.dft @@ -0,0 +1,4 @@ +toplevel "A"; +"A" or "B" "C"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/pand.dft b/resources/examples/testfiles/dft/pand.dft new file mode 100644 index 000000000..d752517b4 --- /dev/null +++ b/resources/examples/testfiles/dft/pand.dft @@ -0,0 +1,4 @@ +toplevel "A"; +"A" pand "B" "C"; +"B" lambda=0.4 dorm=0.3; +"C" lambda=0.2 dorm=0.3; diff --git a/resources/examples/testfiles/dft/pdep.dft b/resources/examples/testfiles/dft/pdep.dft new file mode 100644 index 000000000..f8cb0382b --- /dev/null +++ b/resources/examples/testfiles/dft/pdep.dft @@ -0,0 +1,12 @@ +// From Junges2015 +// Example 3.19 + +toplevel "SF"; +"SF" or "A" "B" "PDEP"; +"A" pand "S" "MA"; +"B" and "MA" "MB"; +"PDEP" pdep=0.2 "MA" "S"; + +"S" lambda=0.5 dorm=0; +"MA" lambda=0.5 dorm=0; +"MB" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/pdep2.dft b/resources/examples/testfiles/dft/pdep2.dft new file mode 100644 index 000000000..ab1c7a9b8 --- /dev/null +++ b/resources/examples/testfiles/dft/pdep2.dft @@ -0,0 +1,9 @@ +toplevel "SF"; +"SF" or "A" "B" "PDEP"; +"A" pand "S" "MA"; +"B" and "MA" "MB"; +"PDEP" pdep=0.2 "MA" "S" "MB"; + +"S" lambda=0.5 dorm=0; +"MA" lambda=0.5 dorm=0; +"MB" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/pdep3.dft b/resources/examples/testfiles/dft/pdep3.dft new file mode 100644 index 000000000..a9a73f472 --- /dev/null +++ b/resources/examples/testfiles/dft/pdep3.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C" "F"; +"F" pdep=0.3 "B" "C"; +"B" lambda=0.4 dorm=0; +"C" lambda=0.8 dorm=0; diff --git a/resources/examples/testfiles/dft/pdep4.dft b/resources/examples/testfiles/dft/pdep4.dft new file mode 100644 index 000000000..eace91847 --- /dev/null +++ b/resources/examples/testfiles/dft/pdep4.dft @@ -0,0 +1,7 @@ +toplevel "SF"; +"SF" pand "S" "A" "B"; +"PDEP" pdep=0.2 "S" "A" "B"; + +"S" lambda=0.5 dorm=0; +"A" lambda=0.5 dorm=0; +"B" lambda=0.5 dorm=0; diff --git a/resources/examples/testfiles/dft/por.dft b/resources/examples/testfiles/dft/por.dft new file mode 100644 index 000000000..020687f62 --- /dev/null +++ b/resources/examples/testfiles/dft/por.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" por "B" "C" "D"; +"B" lambda=0.4 dorm=0.0; +"C" lambda=0.2 dorm=0.0; +"D" lambda=0.2 dorm=0.0; diff --git a/resources/examples/testfiles/dft/seq.dft b/resources/examples/testfiles/dft/seq.dft new file mode 100644 index 000000000..8f5459fd2 --- /dev/null +++ b/resources/examples/testfiles/dft/seq.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" and "B" "C"; +"X" seq "B" "C"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq2.dft b/resources/examples/testfiles/dft/seq2.dft new file mode 100644 index 000000000..408d4c26d --- /dev/null +++ b/resources/examples/testfiles/dft/seq2.dft @@ -0,0 +1,6 @@ +toplevel "A"; +"A" and "B" "C" "D"; +"X" seq "B" "C" "D"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; +"D" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq3.dft b/resources/examples/testfiles/dft/seq3.dft new file mode 100644 index 000000000..b22b9e8b6 --- /dev/null +++ b/resources/examples/testfiles/dft/seq3.dft @@ -0,0 +1,6 @@ +toplevel "A"; +"A" and "C" "D"; +"X" seq "B" "C" "D"; +"B" lambda=0.5 dorm=0.3; +"C" lambda=0.5 dorm=0.3; +"D" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq4.dft b/resources/examples/testfiles/dft/seq4.dft new file mode 100644 index 000000000..60bf149af --- /dev/null +++ b/resources/examples/testfiles/dft/seq4.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" and "T1" "B3"; +"T1" or "B1" "B2"; +"X" seq "B1" "B2" "B3"; +"B1" lambda=0.5 dorm=0.3; +"B2" lambda=0.5 dorm=0.3; +"B3" lambda=0.5 dorm=0.3; diff --git a/resources/examples/testfiles/dft/seq5.dft b/resources/examples/testfiles/dft/seq5.dft new file mode 100644 index 000000000..77b13ddeb --- /dev/null +++ b/resources/examples/testfiles/dft/seq5.dft @@ -0,0 +1,9 @@ +toplevel "A"; +"A" and "T1" "T2"; +"T1" pand "B1" "B2"; +"T2" pand "B3" "B4"; +"X" seq "B4" "B3"; +"B1" lambda=0.7 dorm=0.3; +"B2" lambda=0.5 dorm=0.3; +"B3" lambda=0.5 dorm=0.3; +"B4" lambda=0.7 dorm=0.3; diff --git a/resources/examples/testfiles/dft/spare.dft b/resources/examples/testfiles/dft/spare.dft new file mode 100644 index 000000000..4c5d44ff4 --- /dev/null +++ b/resources/examples/testfiles/dft/spare.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" wsp "I" "M"; +"I" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare2.dft b/resources/examples/testfiles/dft/spare2.dft new file mode 100644 index 000000000..21b40cf73 --- /dev/null +++ b/resources/examples/testfiles/dft/spare2.dft @@ -0,0 +1,8 @@ +toplevel "A"; +"A" or "B" "C"; +"B" wsp "I" "J"; +"C" wsp "M" "J"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare3.dft b/resources/examples/testfiles/dft/spare3.dft new file mode 100644 index 000000000..ba0ac01d4 --- /dev/null +++ b/resources/examples/testfiles/dft/spare3.dft @@ -0,0 +1,10 @@ +toplevel "A"; +"A" or "B" "C" "D"; +"B" wsp "I" "M"; +"C" wsp "J" "M"; +"D" wsp "K" "M"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"K" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare4.dft b/resources/examples/testfiles/dft/spare4.dft new file mode 100644 index 000000000..a217c6e43 --- /dev/null +++ b/resources/examples/testfiles/dft/spare4.dft @@ -0,0 +1,9 @@ +toplevel "A"; +"A" and "B" "C"; +"B" wsp "I" "J" "K"; +"C" wsp "M" "J"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"K" lambda=0.5 dorm=0.3; +"M" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/spare5.dft b/resources/examples/testfiles/dft/spare5.dft new file mode 100644 index 000000000..0cd15bf0e --- /dev/null +++ b/resources/examples/testfiles/dft/spare5.dft @@ -0,0 +1,9 @@ +toplevel "A"; +"A" wsp "I" "B"; +"B" or "C" "J"; +"C" or "K" "L"; +"I" lambda=0.5 dorm=0; +"J" lambda=0.5 dorm=0; +"K" lambda=0.5 dorm=0; +"L" lambda=0.5 dorm=0; + diff --git a/resources/examples/testfiles/dft/spare6.dft b/resources/examples/testfiles/dft/spare6.dft new file mode 100644 index 000000000..d5f2b270b --- /dev/null +++ b/resources/examples/testfiles/dft/spare6.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" or "I" "B"; +"B" wsp "J" "M"; +"I" lambda=0.5 dorm=0.5; +"J" lambda=0.5 dorm=0.5; +"M" lambda=0.5 dorm=0.5; + diff --git a/resources/examples/testfiles/dft/spare7.dft b/resources/examples/testfiles/dft/spare7.dft new file mode 100644 index 000000000..a16429e6f --- /dev/null +++ b/resources/examples/testfiles/dft/spare7.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" wsp "K" "J" "I"; +"I" lambda=0.5 dorm=0.5; +"J" lambda=1 dorm=0.5; +"K" lambda=0.5 dorm=0.5; diff --git a/resources/examples/testfiles/dft/spare8.dft b/resources/examples/testfiles/dft/spare8.dft new file mode 100644 index 000000000..c67eaf022 --- /dev/null +++ b/resources/examples/testfiles/dft/spare8.dft @@ -0,0 +1,7 @@ +toplevel "A"; +"A" wsp "I" "B"; +"B" wsp "J" "K"; +"I" lambda=0.5 dorm=0.3; +"J" lambda=0.5 dorm=0.3; +"K" lambda=0.5 dorm=0.3; + diff --git a/resources/examples/testfiles/dft/voting.dft b/resources/examples/testfiles/dft/voting.dft new file mode 100644 index 000000000..5c648d424 --- /dev/null +++ b/resources/examples/testfiles/dft/voting.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" 1of3 "B" "C" "D"; +"B" lambda=0.1 dorm=0; +"C" lambda=0.2 dorm=0; +"D" lambda=0.3 dorm=0; diff --git a/resources/examples/testfiles/dft/voting2.dft b/resources/examples/testfiles/dft/voting2.dft new file mode 100644 index 000000000..9cdf299f3 --- /dev/null +++ b/resources/examples/testfiles/dft/voting2.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" 1of3 "B" "C" "D"; +"B" lambda=0.3 dorm=0; +"C" lambda=0.4 dorm=0; +"D" lambda=1 dorm=0; diff --git a/resources/examples/testfiles/dft/voting3.dft b/resources/examples/testfiles/dft/voting3.dft new file mode 100644 index 000000000..107408fce --- /dev/null +++ b/resources/examples/testfiles/dft/voting3.dft @@ -0,0 +1,5 @@ +toplevel "A"; +"A" 2of3 "B" "C" "D"; +"B" lambda=0.3 dorm=0; +"C" lambda=0.4 dorm=0; +"D" lambda=1 dorm=0; diff --git a/resources/examples/testfiles/dft/voting4.dft b/resources/examples/testfiles/dft/voting4.dft new file mode 100644 index 000000000..412df12e5 --- /dev/null +++ b/resources/examples/testfiles/dft/voting4.dft @@ -0,0 +1,6 @@ +toplevel "A"; +"A" 2of3 "B" "C" "D"; +"D" or "E"; +"B" lambda=1 dorm=0.0; +"C" lambda=1 dorm=0.0; +"E" lambda=1 dorm=0.0; diff --git a/resources/examples/testfiles/dtmc/crowds-5-5.drn b/resources/examples/testfiles/dtmc/crowds-5-5.drn new file mode 100644 index 000000000..54dfa7161 --- /dev/null +++ b/resources/examples/testfiles/dtmc/crowds-5-5.drn @@ -0,0 +1,32337 @@ +// Exported by storm +// Original model type: DTMC +@type: DTMC +@parameters + +@reward_models + +@nr_states +8607 +@model +state 0 init + action 0 + 1 : 1 +state 1 + action 0 + 2 : 0.833 + 3 : 0.167 +state 2 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 3 + action 0 + 9 : 1 +state 4 + action 0 + 10 : 0.8 + 11 : 0.2 +state 5 + action 0 + 12 : 0.8 + 13 : 0.2 +state 6 + action 0 + 14 : 0.8 + 15 : 0.2 +state 7 + action 0 + 16 : 0.8 + 17 : 0.2 +state 8 + action 0 + 18 : 0.8 + 19 : 0.2 +state 9 + action 0 + 20 : 1 +state 10 + action 0 + 2 : 0.833 + 3 : 0.167 +state 11 + action 0 + 21 : 1 +state 12 + action 0 + 22 : 0.833 + 23 : 0.167 +state 13 + action 0 + 24 : 1 +state 14 + action 0 + 25 : 0.833 + 26 : 0.167 +state 15 + action 0 + 27 : 1 +state 16 + action 0 + 28 : 0.833 + 29 : 0.167 +state 17 + action 0 + 30 : 1 +state 18 + action 0 + 31 : 0.833 + 32 : 0.167 +state 19 + action 0 + 33 : 1 +state 20 + action 0 + 34 : 1 +state 21 + action 0 + 35 : 1 +state 22 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 23 + action 0 + 36 : 1 +state 24 + action 0 + 35 : 1 +state 25 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 26 + action 0 + 37 : 1 +state 27 + action 0 + 35 : 1 +state 28 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 29 + action 0 + 38 : 1 +state 30 + action 0 + 35 : 1 +state 31 + action 0 + 4 : 0.2 + 5 : 0.2 + 6 : 0.2 + 7 : 0.2 + 8 : 0.2 +state 32 + action 0 + 39 : 1 +state 33 + action 0 + 35 : 1 +state 34 + action 0 + 40 : 0.833 + 41 : 0.167 +state 35 + action 0 + 42 : 0.833 + 43 : 0.167 +state 36 + action 0 + 44 : 1 +state 37 + action 0 + 45 : 1 +state 38 + action 0 + 46 : 1 +state 39 + action 0 + 47 : 1 +state 40 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 41 + action 0 + 53 : 1 +state 42 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 43 + action 0 + 59 : 1 +state 44 + action 0 + 60 : 1 +state 45 + action 0 + 61 : 1 +state 46 + action 0 + 62 : 1 +state 47 + action 0 + 63 : 1 +state 48 + action 0 + 64 : 0.8 + 65 : 0.2 +state 49 + action 0 + 66 : 0.8 + 67 : 0.2 +state 50 + action 0 + 68 : 0.8 + 69 : 0.2 +state 51 + action 0 + 70 : 0.8 + 71 : 0.2 +state 52 + action 0 + 72 : 0.8 + 73 : 0.2 +state 53 observe0Greater1 observeOnlyTrueSender + action 0 + 74 : 1 +state 54 + action 0 + 35 : 0.8 + 75 : 0.2 +state 55 + action 0 + 76 : 0.8 + 77 : 0.2 +state 56 + action 0 + 78 : 0.8 + 79 : 0.2 +state 57 + action 0 + 80 : 0.8 + 81 : 0.2 +state 58 + action 0 + 82 : 0.8 + 83 : 0.2 +state 59 + action 0 + 84 : 1 +state 60 + action 0 + 85 : 0.833 + 86 : 0.167 +state 61 + action 0 + 87 : 0.833 + 88 : 0.167 +state 62 + action 0 + 89 : 0.833 + 90 : 0.167 +state 63 + action 0 + 91 : 0.833 + 92 : 0.167 +state 64 + action 0 + 40 : 0.833 + 41 : 0.167 +state 65 + action 0 + 93 : 1 +state 66 + action 0 + 94 : 0.833 + 95 : 0.167 +state 67 + action 0 + 96 : 1 +state 68 + action 0 + 97 : 0.833 + 98 : 0.167 +state 69 + action 0 + 99 : 1 +state 70 + action 0 + 100 : 0.833 + 101 : 0.167 +state 71 + action 0 + 102 : 1 +state 72 + action 0 + 103 : 0.833 + 104 : 0.167 +state 73 + action 0 + 105 : 1 +state 74 observe0Greater1 observeOnlyTrueSender + action 0 + 106 : 1 +state 75 + action 0 + 107 : 1 +state 76 + action 0 + 108 : 0.833 + 109 : 0.167 +state 77 + action 0 + 110 : 1 +state 78 + action 0 + 111 : 0.833 + 112 : 0.167 +state 79 + action 0 + 113 : 1 +state 80 + action 0 + 114 : 0.833 + 115 : 0.167 +state 81 + action 0 + 116 : 1 +state 82 + action 0 + 117 : 0.833 + 118 : 0.167 +state 83 + action 0 + 119 : 1 +state 84 + action 0 + 120 : 1 +state 85 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 86 + action 0 + 126 : 1 +state 87 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 88 + action 0 + 132 : 1 +state 89 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 90 + action 0 + 138 : 1 +state 91 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 92 + action 0 + 144 : 1 +state 93 + action 0 + 145 : 1 +state 94 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 95 + action 0 + 146 : 1 +state 96 + action 0 + 145 : 1 +state 97 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 98 + action 0 + 147 : 1 +state 99 + action 0 + 145 : 1 +state 100 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 101 + action 0 + 148 : 1 +state 102 + action 0 + 145 : 1 +state 103 + action 0 + 48 : 0.2 + 49 : 0.2 + 50 : 0.2 + 51 : 0.2 + 52 : 0.2 +state 104 + action 0 + 149 : 1 +state 105 + action 0 + 145 : 1 +state 106 observe0Greater1 observeOnlyTrueSender + action 0 + 150 : 0.833 + 151 : 0.167 +state 107 + action 0 + 152 : 1 +state 108 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 109 + action 0 + 153 : 1 +state 110 + action 0 + 152 : 1 +state 111 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 112 + action 0 + 154 : 1 +state 113 + action 0 + 152 : 1 +state 114 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 115 + action 0 + 155 : 1 +state 116 + action 0 + 152 : 1 +state 117 + action 0 + 54 : 0.2 + 55 : 0.2 + 56 : 0.2 + 57 : 0.2 + 58 : 0.2 +state 118 + action 0 + 156 : 1 +state 119 + action 0 + 152 : 1 +state 120 + action 0 + 157 : 0.833 + 158 : 0.167 +state 121 + action 0 + 159 : 0.8 + 160 : 0.2 +state 122 + action 0 + 161 : 0.8 + 162 : 0.2 +state 123 + action 0 + 163 : 0.8 + 164 : 0.2 +state 124 + action 0 + 165 : 0.8 + 166 : 0.2 +state 125 + action 0 + 167 : 0.8 + 168 : 0.2 +state 126 + action 0 + 169 : 1 +state 127 + action 0 + 170 : 0.8 + 171 : 0.2 +state 128 + action 0 + 172 : 0.8 + 173 : 0.2 +state 129 + action 0 + 174 : 0.8 + 175 : 0.2 +state 130 + action 0 + 176 : 0.8 + 177 : 0.2 +state 131 + action 0 + 178 : 0.8 + 179 : 0.2 +state 132 + action 0 + 180 : 1 +state 133 + action 0 + 181 : 0.8 + 182 : 0.2 +state 134 + action 0 + 183 : 0.8 + 184 : 0.2 +state 135 + action 0 + 185 : 0.8 + 186 : 0.2 +state 136 + action 0 + 187 : 0.8 + 188 : 0.2 +state 137 + action 0 + 189 : 0.8 + 190 : 0.2 +state 138 + action 0 + 191 : 1 +state 139 + action 0 + 192 : 0.8 + 193 : 0.2 +state 140 + action 0 + 194 : 0.8 + 195 : 0.2 +state 141 + action 0 + 196 : 0.8 + 197 : 0.2 +state 142 + action 0 + 198 : 0.8 + 199 : 0.2 +state 143 + action 0 + 200 : 0.8 + 201 : 0.2 +state 144 + action 0 + 202 : 1 +state 145 + action 0 + 157 : 0.833 + 158 : 0.167 +state 146 + action 0 + 203 : 1 +state 147 + action 0 + 204 : 1 +state 148 + action 0 + 205 : 1 +state 149 + action 0 + 206 : 1 +state 150 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 151 observe0Greater1 observeOnlyTrueSender + action 0 + 212 : 1 +state 152 + action 0 + 213 : 0.833 + 214 : 0.167 +state 153 + action 0 + 215 : 1 +state 154 + action 0 + 216 : 1 +state 155 + action 0 + 217 : 1 +state 156 + action 0 + 218 : 1 +state 157 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 158 + action 0 + 224 : 1 +state 159 + action 0 + 85 : 0.833 + 86 : 0.167 +state 160 + action 0 + 225 : 1 +state 161 + action 0 + 226 : 0.833 + 227 : 0.167 +state 162 + action 0 + 228 : 1 +state 163 + action 0 + 229 : 0.833 + 230 : 0.167 +state 164 + action 0 + 231 : 1 +state 165 + action 0 + 232 : 0.833 + 233 : 0.167 +state 166 + action 0 + 234 : 1 +state 167 + action 0 + 235 : 0.833 + 236 : 0.167 +state 168 + action 0 + 237 : 1 +state 169 + action 0 + 238 : 1 +state 170 + action 0 + 87 : 0.833 + 88 : 0.167 +state 171 + action 0 + 239 : 1 +state 172 + action 0 + 240 : 0.833 + 241 : 0.167 +state 173 + action 0 + 242 : 1 +state 174 + action 0 + 243 : 0.833 + 244 : 0.167 +state 175 + action 0 + 245 : 1 +state 176 + action 0 + 246 : 0.833 + 247 : 0.167 +state 177 + action 0 + 248 : 1 +state 178 + action 0 + 249 : 0.833 + 250 : 0.167 +state 179 + action 0 + 251 : 1 +state 180 + action 0 + 252 : 1 +state 181 + action 0 + 89 : 0.833 + 90 : 0.167 +state 182 + action 0 + 253 : 1 +state 183 + action 0 + 254 : 0.833 + 255 : 0.167 +state 184 + action 0 + 256 : 1 +state 185 + action 0 + 257 : 0.833 + 258 : 0.167 +state 186 + action 0 + 259 : 1 +state 187 + action 0 + 260 : 0.833 + 261 : 0.167 +state 188 + action 0 + 262 : 1 +state 189 + action 0 + 263 : 0.833 + 264 : 0.167 +state 190 + action 0 + 265 : 1 +state 191 + action 0 + 266 : 1 +state 192 + action 0 + 91 : 0.833 + 92 : 0.167 +state 193 + action 0 + 267 : 1 +state 194 + action 0 + 268 : 0.833 + 269 : 0.167 +state 195 + action 0 + 270 : 1 +state 196 + action 0 + 271 : 0.833 + 272 : 0.167 +state 197 + action 0 + 273 : 1 +state 198 + action 0 + 274 : 0.833 + 275 : 0.167 +state 199 + action 0 + 276 : 1 +state 200 + action 0 + 277 : 0.833 + 278 : 0.167 +state 201 + action 0 + 279 : 1 +state 202 + action 0 + 280 : 1 +state 203 + action 0 + 238 : 1 +state 204 + action 0 + 252 : 1 +state 205 + action 0 + 266 : 1 +state 206 + action 0 + 280 : 1 +state 207 observe0Greater1 observeOnlyTrueSender + action 0 + 281 : 0.8 + 282 : 0.2 +state 208 observe0Greater1 observeOnlyTrueSender + action 0 + 283 : 0.8 + 284 : 0.2 +state 209 observe0Greater1 observeOnlyTrueSender + action 0 + 285 : 0.8 + 286 : 0.2 +state 210 observe0Greater1 observeOnlyTrueSender + action 0 + 287 : 0.8 + 288 : 0.2 +state 211 observe0Greater1 observeOnlyTrueSender + action 0 + 289 : 0.8 + 290 : 0.2 +state 212 observe0Greater1 observeOnlyTrueSender + action 0 + 291 : 1 +state 213 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 214 + action 0 + 297 : 1 +state 215 + action 0 + 298 : 1 +state 216 + action 0 + 299 : 1 +state 217 + action 0 + 300 : 1 +state 218 + action 0 + 301 : 1 +state 219 + action 0 + 145 : 0.8 + 302 : 0.2 +state 220 + action 0 + 303 : 0.8 + 304 : 0.2 +state 221 + action 0 + 305 : 0.8 + 306 : 0.2 +state 222 + action 0 + 307 : 0.8 + 308 : 0.2 +state 223 + action 0 + 309 : 0.8 + 310 : 0.2 +state 224 observe0Greater1 observeOnlyTrueSender + action 0 + 311 : 1 +state 225 + action 0 + 312 : 1 +state 226 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 227 + action 0 + 313 : 1 +state 228 + action 0 + 312 : 1 +state 229 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 230 + action 0 + 314 : 1 +state 231 + action 0 + 312 : 1 +state 232 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 233 + action 0 + 315 : 1 +state 234 + action 0 + 312 : 1 +state 235 + action 0 + 121 : 0.2 + 122 : 0.2 + 123 : 0.2 + 124 : 0.2 + 125 : 0.2 +state 236 + action 0 + 316 : 1 +state 237 + action 0 + 312 : 1 +state 238 + action 0 + 317 : 0.833 + 318 : 0.167 +state 239 + action 0 + 319 : 1 +state 240 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 241 + action 0 + 320 : 1 +state 242 + action 0 + 319 : 1 +state 243 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 244 + action 0 + 321 : 1 +state 245 + action 0 + 319 : 1 +state 246 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 247 + action 0 + 322 : 1 +state 248 + action 0 + 319 : 1 +state 249 + action 0 + 127 : 0.2 + 128 : 0.2 + 129 : 0.2 + 130 : 0.2 + 131 : 0.2 +state 250 + action 0 + 323 : 1 +state 251 + action 0 + 319 : 1 +state 252 + action 0 + 324 : 0.833 + 325 : 0.167 +state 253 + action 0 + 326 : 1 +state 254 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 255 + action 0 + 327 : 1 +state 256 + action 0 + 326 : 1 +state 257 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 258 + action 0 + 328 : 1 +state 259 + action 0 + 326 : 1 +state 260 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 261 + action 0 + 329 : 1 +state 262 + action 0 + 326 : 1 +state 263 + action 0 + 133 : 0.2 + 134 : 0.2 + 135 : 0.2 + 136 : 0.2 + 137 : 0.2 +state 264 + action 0 + 330 : 1 +state 265 + action 0 + 326 : 1 +state 266 + action 0 + 331 : 0.833 + 332 : 0.167 +state 267 + action 0 + 333 : 1 +state 268 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 269 + action 0 + 334 : 1 +state 270 + action 0 + 333 : 1 +state 271 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 272 + action 0 + 335 : 1 +state 273 + action 0 + 333 : 1 +state 274 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 275 + action 0 + 336 : 1 +state 276 + action 0 + 333 : 1 +state 277 + action 0 + 139 : 0.2 + 140 : 0.2 + 141 : 0.2 + 142 : 0.2 + 143 : 0.2 +state 278 + action 0 + 337 : 1 +state 279 + action 0 + 333 : 1 +state 280 + action 0 + 338 : 0.833 + 339 : 0.167 +state 281 observe0Greater1 observeOnlyTrueSender + action 0 + 150 : 0.833 + 151 : 0.167 +state 282 observe0Greater1 observeOnlyTrueSender + action 0 + 340 : 1 +state 283 observe0Greater1 observeOnlyTrueSender + action 0 + 341 : 0.833 + 342 : 0.167 +state 284 observe0Greater1 observeOnlyTrueSender + action 0 + 343 : 1 +state 285 observe0Greater1 observeOnlyTrueSender + action 0 + 344 : 0.833 + 345 : 0.167 +state 286 observe0Greater1 observeOnlyTrueSender + action 0 + 346 : 1 +state 287 observe0Greater1 observeOnlyTrueSender + action 0 + 347 : 0.833 + 348 : 0.167 +state 288 observe0Greater1 observeOnlyTrueSender + action 0 + 349 : 1 +state 289 observe0Greater1 observeOnlyTrueSender + action 0 + 350 : 0.833 + 351 : 0.167 +state 290 observe0Greater1 observeOnlyTrueSender + action 0 + 352 : 1 +state 291 observe0Greater1 observeOnlyTrueSender + action 0 + 353 : 1 +state 292 + action 0 + 152 : 0.8 + 354 : 0.2 +state 293 + action 0 + 355 : 0.8 + 356 : 0.2 +state 294 + action 0 + 357 : 0.8 + 358 : 0.2 +state 295 + action 0 + 359 : 0.8 + 360 : 0.2 +state 296 + action 0 + 361 : 0.8 + 362 : 0.2 +state 297 + action 0 + 363 : 1 +state 298 + action 0 + 364 : 0.833 + 365 : 0.167 +state 299 + action 0 + 366 : 0.833 + 367 : 0.167 +state 300 + action 0 + 368 : 0.833 + 369 : 0.167 +state 301 + action 0 + 370 : 0.833 + 371 : 0.167 +state 302 + action 0 + 372 : 1 +state 303 + action 0 + 373 : 0.833 + 374 : 0.167 +state 304 + action 0 + 375 : 1 +state 305 + action 0 + 376 : 0.833 + 377 : 0.167 +state 306 + action 0 + 378 : 1 +state 307 + action 0 + 379 : 0.833 + 380 : 0.167 +state 308 + action 0 + 381 : 1 +state 309 + action 0 + 382 : 0.833 + 383 : 0.167 +state 310 + action 0 + 384 : 1 +state 311 observe0Greater1 observeOnlyTrueSender + action 0 + 385 : 1 +state 312 + action 0 + 364 : 0.833 + 365 : 0.167 +state 313 observe1Greater1 observeIGreater1 + action 0 + 386 : 1 +state 314 + action 0 + 387 : 1 +state 315 + action 0 + 388 : 1 +state 316 + action 0 + 389 : 1 +state 317 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 318 + action 0 + 395 : 1 +state 319 + action 0 + 366 : 0.833 + 367 : 0.167 +state 320 + action 0 + 396 : 1 +state 321 observe2Greater1 observeIGreater1 + action 0 + 397 : 1 +state 322 + action 0 + 398 : 1 +state 323 + action 0 + 399 : 1 +state 324 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 325 + action 0 + 405 : 1 +state 326 + action 0 + 368 : 0.833 + 369 : 0.167 +state 327 + action 0 + 406 : 1 +state 328 + action 0 + 407 : 1 +state 329 observe3Greater1 observeIGreater1 + action 0 + 408 : 1 +state 330 + action 0 + 409 : 1 +state 331 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 332 + action 0 + 415 : 1 +state 333 + action 0 + 370 : 0.833 + 371 : 0.167 +state 334 + action 0 + 416 : 1 +state 335 + action 0 + 417 : 1 +state 336 + action 0 + 418 : 1 +state 337 observe4Greater1 observeIGreater1 + action 0 + 419 : 1 +state 338 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 339 + action 0 + 425 : 1 +state 340 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 341 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 342 observe0Greater1 observeOnlyTrueSender + action 0 + 427 : 1 +state 343 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 344 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 345 observe0Greater1 observeOnlyTrueSender + action 0 + 428 : 1 +state 346 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 347 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 348 observe0Greater1 observeOnlyTrueSender + action 0 + 429 : 1 +state 349 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 350 observe0Greater1 observeOnlyTrueSender + action 0 + 207 : 0.2 + 208 : 0.2 + 209 : 0.2 + 210 : 0.2 + 211 : 0.2 +state 351 observe0Greater1 observeOnlyTrueSender + action 0 + 430 : 1 +state 352 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 1 +state 353 observe0Greater1 observeOnlyTrueSender + action 0 + 431 : 0.833 + 432 : 0.167 +state 354 + action 0 + 433 : 1 +state 355 + action 0 + 434 : 0.833 + 435 : 0.167 +state 356 + action 0 + 436 : 1 +state 357 + action 0 + 437 : 0.833 + 438 : 0.167 +state 358 + action 0 + 439 : 1 +state 359 + action 0 + 440 : 0.833 + 441 : 0.167 +state 360 + action 0 + 442 : 1 +state 361 + action 0 + 443 : 0.833 + 444 : 0.167 +state 362 + action 0 + 445 : 1 +state 363 + action 0 + 446 : 1 +state 364 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 365 + action 0 + 452 : 1 +state 366 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 367 + action 0 + 458 : 1 +state 368 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 369 + action 0 + 464 : 1 +state 370 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 371 + action 0 + 470 : 1 +state 372 + action 0 + 471 : 1 +state 373 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 374 + action 0 + 472 : 1 +state 375 + action 0 + 471 : 1 +state 376 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 377 + action 0 + 473 : 1 +state 378 + action 0 + 471 : 1 +state 379 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 380 + action 0 + 474 : 1 +state 381 + action 0 + 471 : 1 +state 382 + action 0 + 219 : 0.2 + 220 : 0.2 + 221 : 0.2 + 222 : 0.2 + 223 : 0.2 +state 383 + action 0 + 475 : 1 +state 384 + action 0 + 471 : 1 +state 385 observe0Greater1 observeOnlyTrueSender + action 0 + 476 : 0.833 + 477 : 0.167 +state 386 observe1Greater1 observeIGreater1 + action 0 + 478 : 1 +state 387 + action 0 + 479 : 1 +state 388 + action 0 + 480 : 1 +state 389 + action 0 + 481 : 1 +state 390 + action 0 + 482 : 0.8 + 483 : 0.2 +state 391 + action 0 + 484 : 0.8 + 485 : 0.2 +state 392 + action 0 + 486 : 0.8 + 487 : 0.2 +state 393 + action 0 + 488 : 0.8 + 489 : 0.2 +state 394 + action 0 + 490 : 0.8 + 491 : 0.2 +state 395 observe0Greater1 observeOnlyTrueSender + action 0 + 492 : 1 +state 396 + action 0 + 479 : 1 +state 397 observe2Greater1 observeIGreater1 + action 0 + 493 : 1 +state 398 + action 0 + 494 : 1 +state 399 + action 0 + 495 : 1 +state 400 + action 0 + 496 : 0.8 + 497 : 0.2 +state 401 + action 0 + 498 : 0.8 + 499 : 0.2 +state 402 + action 0 + 500 : 0.8 + 501 : 0.2 +state 403 + action 0 + 502 : 0.8 + 503 : 0.2 +state 404 + action 0 + 504 : 0.8 + 505 : 0.2 +state 405 observe0Greater1 observeOnlyTrueSender + action 0 + 506 : 1 +state 406 + action 0 + 480 : 1 +state 407 + action 0 + 494 : 1 +state 408 observe3Greater1 observeIGreater1 + action 0 + 507 : 1 +state 409 + action 0 + 508 : 1 +state 410 + action 0 + 509 : 0.8 + 510 : 0.2 +state 411 + action 0 + 511 : 0.8 + 512 : 0.2 +state 412 + action 0 + 513 : 0.8 + 514 : 0.2 +state 413 + action 0 + 515 : 0.8 + 516 : 0.2 +state 414 + action 0 + 517 : 0.8 + 518 : 0.2 +state 415 observe0Greater1 observeOnlyTrueSender + action 0 + 519 : 1 +state 416 + action 0 + 481 : 1 +state 417 + action 0 + 495 : 1 +state 418 + action 0 + 508 : 1 +state 419 observe4Greater1 observeIGreater1 + action 0 + 520 : 1 +state 420 + action 0 + 521 : 0.8 + 522 : 0.2 +state 421 + action 0 + 523 : 0.8 + 524 : 0.2 +state 422 + action 0 + 525 : 0.8 + 526 : 0.2 +state 423 + action 0 + 527 : 0.8 + 528 : 0.2 +state 424 + action 0 + 529 : 0.8 + 530 : 0.2 +state 425 observe0Greater1 observeOnlyTrueSender + action 0 + 531 : 1 +state 426 observe0Greater1 observeOnlyTrueSender + action 0 + 476 : 0.833 + 477 : 0.167 +state 427 observe0Greater1 observeOnlyTrueSender + action 0 + 532 : 1 +state 428 observe0Greater1 observeOnlyTrueSender + action 0 + 533 : 1 +state 429 observe0Greater1 observeOnlyTrueSender + action 0 + 534 : 1 +state 430 observe0Greater1 observeOnlyTrueSender + action 0 + 535 : 1 +state 431 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 432 observe0Greater1 observeOnlyTrueSender + action 0 + 541 : 1 +state 433 + action 0 + 542 : 1 +state 434 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 435 + action 0 + 543 : 1 +state 436 + action 0 + 542 : 1 +state 437 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 438 + action 0 + 544 : 1 +state 439 + action 0 + 542 : 1 +state 440 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 441 + action 0 + 545 : 1 +state 442 + action 0 + 542 : 1 +state 443 + action 0 + 292 : 0.2 + 293 : 0.2 + 294 : 0.2 + 295 : 0.2 + 296 : 0.2 +state 444 + action 0 + 546 : 1 +state 445 + action 0 + 542 : 1 +state 446 + action 0 + 547 : 0.833 + 548 : 0.167 +state 447 + action 0 + 312 : 0.8 + 549 : 0.2 +state 448 + action 0 + 550 : 0.8 + 551 : 0.2 +state 449 + action 0 + 552 : 0.8 + 553 : 0.2 +state 450 + action 0 + 554 : 0.8 + 555 : 0.2 +state 451 + action 0 + 556 : 0.8 + 557 : 0.2 +state 452 + action 0 + 558 : 1 +state 453 + action 0 + 319 : 0.8 + 559 : 0.2 +state 454 + action 0 + 560 : 0.8 + 561 : 0.2 +state 455 + action 0 + 562 : 0.8 + 563 : 0.2 +state 456 + action 0 + 564 : 0.8 + 565 : 0.2 +state 457 + action 0 + 566 : 0.8 + 567 : 0.2 +state 458 + action 0 + 568 : 1 +state 459 + action 0 + 326 : 0.8 + 569 : 0.2 +state 460 + action 0 + 570 : 0.8 + 571 : 0.2 +state 461 + action 0 + 572 : 0.8 + 573 : 0.2 +state 462 + action 0 + 574 : 0.8 + 575 : 0.2 +state 463 + action 0 + 576 : 0.8 + 577 : 0.2 +state 464 + action 0 + 578 : 1 +state 465 + action 0 + 333 : 0.8 + 579 : 0.2 +state 466 + action 0 + 580 : 0.8 + 581 : 0.2 +state 467 + action 0 + 582 : 0.8 + 583 : 0.2 +state 468 + action 0 + 584 : 0.8 + 585 : 0.2 +state 469 + action 0 + 586 : 0.8 + 587 : 0.2 +state 470 + action 0 + 588 : 1 +state 471 + action 0 + 547 : 0.833 + 548 : 0.167 +state 472 + action 0 + 589 : 1 +state 473 + action 0 + 590 : 1 +state 474 + action 0 + 591 : 1 +state 475 + action 0 + 592 : 1 +state 476 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 477 observe0Greater1 observeOnlyTrueSender + action 0 + 598 : 1 +state 478 observe1Greater1 observeIGreater1 + action 0 + 599 : 0.833 + 600 : 0.167 +state 479 + action 0 + 601 : 0.833 + 602 : 0.167 +state 480 + action 0 + 603 : 0.833 + 604 : 0.167 +state 481 + action 0 + 605 : 0.833 + 606 : 0.167 +state 482 + action 0 + 317 : 0.833 + 318 : 0.167 +state 483 + action 0 + 607 : 1 +state 484 + action 0 + 608 : 0.833 + 609 : 0.167 +state 485 + action 0 + 610 : 1 +state 486 + action 0 + 611 : 0.833 + 612 : 0.167 +state 487 + action 0 + 613 : 1 +state 488 + action 0 + 614 : 0.833 + 615 : 0.167 +state 489 + action 0 + 616 : 1 +state 490 + action 0 + 617 : 0.833 + 618 : 0.167 +state 491 + action 0 + 619 : 1 +state 492 observe0Greater1 observeOnlyTrueSender + action 0 + 620 : 1 +state 493 observe2Greater1 observeIGreater1 + action 0 + 621 : 0.833 + 622 : 0.167 +state 494 + action 0 + 623 : 0.833 + 624 : 0.167 +state 495 + action 0 + 625 : 0.833 + 626 : 0.167 +state 496 + action 0 + 324 : 0.833 + 325 : 0.167 +state 497 + action 0 + 627 : 1 +state 498 + action 0 + 628 : 0.833 + 629 : 0.167 +state 499 + action 0 + 630 : 1 +state 500 + action 0 + 631 : 0.833 + 632 : 0.167 +state 501 + action 0 + 633 : 1 +state 502 + action 0 + 634 : 0.833 + 635 : 0.167 +state 503 + action 0 + 636 : 1 +state 504 + action 0 + 637 : 0.833 + 638 : 0.167 +state 505 + action 0 + 639 : 1 +state 506 observe0Greater1 observeOnlyTrueSender + action 0 + 640 : 1 +state 507 observe3Greater1 observeIGreater1 + action 0 + 641 : 0.833 + 642 : 0.167 +state 508 + action 0 + 643 : 0.833 + 644 : 0.167 +state 509 + action 0 + 331 : 0.833 + 332 : 0.167 +state 510 + action 0 + 645 : 1 +state 511 + action 0 + 646 : 0.833 + 647 : 0.167 +state 512 + action 0 + 648 : 1 +state 513 + action 0 + 649 : 0.833 + 650 : 0.167 +state 514 + action 0 + 651 : 1 +state 515 + action 0 + 652 : 0.833 + 653 : 0.167 +state 516 + action 0 + 654 : 1 +state 517 + action 0 + 655 : 0.833 + 656 : 0.167 +state 518 + action 0 + 657 : 1 +state 519 observe0Greater1 observeOnlyTrueSender + action 0 + 658 : 1 +state 520 observe4Greater1 observeIGreater1 + action 0 + 659 : 0.833 + 660 : 0.167 +state 521 + action 0 + 338 : 0.833 + 339 : 0.167 +state 522 + action 0 + 661 : 1 +state 523 + action 0 + 662 : 0.833 + 663 : 0.167 +state 524 + action 0 + 664 : 1 +state 525 + action 0 + 665 : 0.833 + 666 : 0.167 +state 526 + action 0 + 667 : 1 +state 527 + action 0 + 668 : 0.833 + 669 : 0.167 +state 528 + action 0 + 670 : 1 +state 529 + action 0 + 671 : 0.833 + 672 : 0.167 +state 530 + action 0 + 673 : 1 +state 531 observe0Greater1 observeOnlyTrueSender + action 0 + 674 : 1 +state 532 observe0Greater1 observeOnlyTrueSender + action 0 + 620 : 1 +state 533 observe0Greater1 observeOnlyTrueSender + action 0 + 640 : 1 +state 534 observe0Greater1 observeOnlyTrueSender + action 0 + 658 : 1 +state 535 observe0Greater1 observeOnlyTrueSender + action 0 + 674 : 1 +state 536 observe0Greater1 observeOnlyTrueSender + action 0 + 675 : 0.8 + 676 : 0.2 +state 537 observe0Greater1 observeOnlyTrueSender + action 0 + 677 : 0.8 + 678 : 0.2 +state 538 observe0Greater1 observeOnlyTrueSender + action 0 + 679 : 0.8 + 680 : 0.2 +state 539 observe0Greater1 observeOnlyTrueSender + action 0 + 681 : 0.8 + 682 : 0.2 +state 540 observe0Greater1 observeOnlyTrueSender + action 0 + 683 : 0.8 + 684 : 0.2 +state 541 observe0Greater1 observeOnlyTrueSender + action 0 + 685 : 1 +state 542 + action 0 + 686 : 0.833 + 687 : 0.167 +state 543 + action 0 + 688 : 1 +state 544 + action 0 + 689 : 1 +state 545 + action 0 + 690 : 1 +state 546 + action 0 + 691 : 1 +state 547 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 548 + action 0 + 697 : 1 +state 549 + action 0 + 698 : 1 +state 550 + action 0 + 699 : 0.833 + 700 : 0.167 +state 551 + action 0 + 701 : 1 +state 552 + action 0 + 702 : 0.833 + 703 : 0.167 +state 553 + action 0 + 704 : 1 +state 554 + action 0 + 705 : 0.833 + 706 : 0.167 +state 555 + action 0 + 707 : 1 +state 556 + action 0 + 708 : 0.833 + 709 : 0.167 +state 557 + action 0 + 710 : 1 +state 558 + action 0 + 711 : 1 +state 559 + action 0 + 712 : 1 +state 560 + action 0 + 713 : 0.833 + 714 : 0.167 +state 561 + action 0 + 715 : 1 +state 562 + action 0 + 716 : 0.833 + 717 : 0.167 +state 563 + action 0 + 718 : 1 +state 564 + action 0 + 719 : 0.833 + 720 : 0.167 +state 565 + action 0 + 721 : 1 +state 566 + action 0 + 722 : 0.833 + 723 : 0.167 +state 567 + action 0 + 724 : 1 +state 568 + action 0 + 725 : 1 +state 569 + action 0 + 726 : 1 +state 570 + action 0 + 727 : 0.833 + 728 : 0.167 +state 571 + action 0 + 729 : 1 +state 572 + action 0 + 730 : 0.833 + 731 : 0.167 +state 573 + action 0 + 732 : 1 +state 574 + action 0 + 733 : 0.833 + 734 : 0.167 +state 575 + action 0 + 735 : 1 +state 576 + action 0 + 736 : 0.833 + 737 : 0.167 +state 577 + action 0 + 738 : 1 +state 578 + action 0 + 739 : 1 +state 579 + action 0 + 740 : 1 +state 580 + action 0 + 741 : 0.833 + 742 : 0.167 +state 581 + action 0 + 743 : 1 +state 582 + action 0 + 744 : 0.833 + 745 : 0.167 +state 583 + action 0 + 746 : 1 +state 584 + action 0 + 747 : 0.833 + 748 : 0.167 +state 585 + action 0 + 749 : 1 +state 586 + action 0 + 750 : 0.833 + 751 : 0.167 +state 587 + action 0 + 752 : 1 +state 588 + action 0 + 753 : 1 +state 589 + action 0 + 711 : 1 +state 590 + action 0 + 725 : 1 +state 591 + action 0 + 739 : 1 +state 592 + action 0 + 753 : 1 +state 593 observe0Greater1 observeOnlyTrueSender + action 0 + 426 : 0.8 + 754 : 0.2 +state 594 observe0Greater1 observeOnlyTrueSender + action 0 + 755 : 0.8 + 756 : 0.2 +state 595 observe0Greater1 observeOnlyTrueSender + action 0 + 757 : 0.8 + 758 : 0.2 +state 596 observe0Greater1 observeOnlyTrueSender + action 0 + 759 : 0.8 + 760 : 0.2 +state 597 observe0Greater1 observeOnlyTrueSender + action 0 + 761 : 0.8 + 762 : 0.2 +state 598 observe0Greater1 observeOnlyTrueSender + action 0 + 763 : 1 +state 599 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 600 observe1Greater1 observeIGreater1 + action 0 + 769 : 1 +state 601 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 602 + action 0 + 775 : 1 +state 603 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 604 + action 0 + 781 : 1 +state 605 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 606 + action 0 + 787 : 1 +state 607 + action 0 + 788 : 1 +state 608 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 609 + action 0 + 789 : 1 +state 610 + action 0 + 788 : 1 +state 611 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 612 + action 0 + 790 : 1 +state 613 + action 0 + 788 : 1 +state 614 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 615 + action 0 + 791 : 1 +state 616 + action 0 + 788 : 1 +state 617 + action 0 + 390 : 0.2 + 391 : 0.2 + 392 : 0.2 + 393 : 0.2 + 394 : 0.2 +state 618 + action 0 + 792 : 1 +state 619 + action 0 + 788 : 1 +state 620 observe0Greater1 observeOnlyTrueSender + action 0 + 793 : 0.833 + 794 : 0.167 +state 621 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 622 observe2Greater1 observeIGreater1 + action 0 + 800 : 1 +state 623 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 624 + action 0 + 806 : 1 +state 625 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 626 + action 0 + 812 : 1 +state 627 + action 0 + 813 : 1 +state 628 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 629 + action 0 + 814 : 1 +state 630 + action 0 + 813 : 1 +state 631 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 632 + action 0 + 815 : 1 +state 633 + action 0 + 813 : 1 +state 634 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 635 + action 0 + 816 : 1 +state 636 + action 0 + 813 : 1 +state 637 + action 0 + 400 : 0.2 + 401 : 0.2 + 402 : 0.2 + 403 : 0.2 + 404 : 0.2 +state 638 + action 0 + 817 : 1 +state 639 + action 0 + 813 : 1 +state 640 observe0Greater1 observeOnlyTrueSender + action 0 + 818 : 0.833 + 819 : 0.167 +state 641 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 642 observe3Greater1 observeIGreater1 + action 0 + 825 : 1 +state 643 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 644 + action 0 + 831 : 1 +state 645 + action 0 + 832 : 1 +state 646 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 647 + action 0 + 833 : 1 +state 648 + action 0 + 832 : 1 +state 649 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 650 + action 0 + 834 : 1 +state 651 + action 0 + 832 : 1 +state 652 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 653 + action 0 + 835 : 1 +state 654 + action 0 + 832 : 1 +state 655 + action 0 + 410 : 0.2 + 411 : 0.2 + 412 : 0.2 + 413 : 0.2 + 414 : 0.2 +state 656 + action 0 + 836 : 1 +state 657 + action 0 + 832 : 1 +state 658 observe0Greater1 observeOnlyTrueSender + action 0 + 837 : 0.833 + 838 : 0.167 +state 659 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 660 observe4Greater1 observeIGreater1 + action 0 + 844 : 1 +state 661 + action 0 + 845 : 1 +state 662 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 663 + action 0 + 846 : 1 +state 664 + action 0 + 845 : 1 +state 665 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 666 + action 0 + 847 : 1 +state 667 + action 0 + 845 : 1 +state 668 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 669 + action 0 + 848 : 1 +state 670 + action 0 + 845 : 1 +state 671 + action 0 + 420 : 0.2 + 421 : 0.2 + 422 : 0.2 + 423 : 0.2 + 424 : 0.2 +state 672 + action 0 + 849 : 1 +state 673 + action 0 + 845 : 1 +state 674 observe0Greater1 observeOnlyTrueSender + action 0 + 850 : 0.833 + 851 : 0.167 +state 675 observe0Greater1 observeOnlyTrueSender + action 0 + 431 : 0.833 + 432 : 0.167 +state 676 observe0Greater1 observeOnlyTrueSender + action 0 + 852 : 1 +state 677 observe0Greater1 observeOnlyTrueSender + action 0 + 853 : 0.833 + 854 : 0.167 +state 678 observe0Greater1 observeOnlyTrueSender + action 0 + 855 : 1 +state 679 observe0Greater1 observeOnlyTrueSender + action 0 + 856 : 0.833 + 857 : 0.167 +state 680 observe0Greater1 observeOnlyTrueSender + action 0 + 858 : 1 +state 681 observe0Greater1 observeOnlyTrueSender + action 0 + 859 : 0.833 + 860 : 0.167 +state 682 observe0Greater1 observeOnlyTrueSender + action 0 + 861 : 1 +state 683 observe0Greater1 observeOnlyTrueSender + action 0 + 862 : 0.833 + 863 : 0.167 +state 684 observe0Greater1 observeOnlyTrueSender + action 0 + 864 : 1 +state 685 observe0Greater1 observeOnlyTrueSender + action 0 + 865 : 1 +state 686 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 687 + action 0 + 871 : 1 +state 688 + action 0 + 872 : 1 +state 689 + action 0 + 873 : 1 +state 690 + action 0 + 874 : 1 +state 691 + action 0 + 875 : 1 +state 692 + action 0 + 471 : 0.8 + 876 : 0.2 +state 693 + action 0 + 877 : 0.8 + 878 : 0.2 +state 694 + action 0 + 879 : 0.8 + 880 : 0.2 +state 695 + action 0 + 881 : 0.8 + 882 : 0.2 +state 696 + action 0 + 883 : 0.8 + 884 : 0.2 +state 697 observe0Greater1 observeOnlyTrueSender + action 0 + 885 : 1 +state 698 + action 0 + 886 : 1 +state 699 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 700 + action 0 + 887 : 1 +state 701 + action 0 + 886 : 1 +state 702 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 703 + action 0 + 888 : 1 +state 704 + action 0 + 886 : 1 +state 705 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 706 + action 0 + 889 : 1 +state 707 + action 0 + 886 : 1 +state 708 + action 0 + 447 : 0.2 + 448 : 0.2 + 449 : 0.2 + 450 : 0.2 + 451 : 0.2 +state 709 + action 0 + 890 : 1 +state 710 + action 0 + 886 : 1 +state 711 + action 0 + 891 : 0.833 + 892 : 0.167 +state 712 + action 0 + 893 : 1 +state 713 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 714 + action 0 + 894 : 1 +state 715 + action 0 + 893 : 1 +state 716 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 717 + action 0 + 895 : 1 +state 718 + action 0 + 893 : 1 +state 719 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 720 + action 0 + 896 : 1 +state 721 + action 0 + 893 : 1 +state 722 + action 0 + 453 : 0.2 + 454 : 0.2 + 455 : 0.2 + 456 : 0.2 + 457 : 0.2 +state 723 + action 0 + 897 : 1 +state 724 + action 0 + 893 : 1 +state 725 + action 0 + 898 : 0.833 + 899 : 0.167 +state 726 + action 0 + 900 : 1 +state 727 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 728 + action 0 + 901 : 1 +state 729 + action 0 + 900 : 1 +state 730 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 731 + action 0 + 902 : 1 +state 732 + action 0 + 900 : 1 +state 733 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 734 + action 0 + 903 : 1 +state 735 + action 0 + 900 : 1 +state 736 + action 0 + 459 : 0.2 + 460 : 0.2 + 461 : 0.2 + 462 : 0.2 + 463 : 0.2 +state 737 + action 0 + 904 : 1 +state 738 + action 0 + 900 : 1 +state 739 + action 0 + 905 : 0.833 + 906 : 0.167 +state 740 + action 0 + 907 : 1 +state 741 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 742 + action 0 + 908 : 1 +state 743 + action 0 + 907 : 1 +state 744 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 745 + action 0 + 909 : 1 +state 746 + action 0 + 907 : 1 +state 747 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 748 + action 0 + 910 : 1 +state 749 + action 0 + 907 : 1 +state 750 + action 0 + 465 : 0.2 + 466 : 0.2 + 467 : 0.2 + 468 : 0.2 + 469 : 0.2 +state 751 + action 0 + 911 : 1 +state 752 + action 0 + 907 : 1 +state 753 + action 0 + 912 : 0.833 + 913 : 0.167 +state 754 observe0Greater1 observeOnlyTrueSender + action 0 + 914 : 1 +state 755 observe0Greater1 observeOnlyTrueSender + action 0 + 915 : 0.833 + 916 : 0.167 +state 756 observe0Greater1 observeOnlyTrueSender + action 0 + 917 : 1 +state 757 observe0Greater1 observeOnlyTrueSender + action 0 + 918 : 0.833 + 919 : 0.167 +state 758 observe0Greater1 observeOnlyTrueSender + action 0 + 920 : 1 +state 759 observe0Greater1 observeOnlyTrueSender + action 0 + 921 : 0.833 + 922 : 0.167 +state 760 observe0Greater1 observeOnlyTrueSender + action 0 + 923 : 1 +state 761 observe0Greater1 observeOnlyTrueSender + action 0 + 924 : 0.833 + 925 : 0.167 +state 762 observe0Greater1 observeOnlyTrueSender + action 0 + 926 : 1 +state 763 observe0Greater1 observeOnlyTrueSender + action 0 + 927 : 1 +state 764 observe1Greater1 observeIGreater1 + action 0 + 928 : 0.8 + 929 : 0.2 +state 765 observe1Greater1 observeIGreater1 + action 0 + 930 : 0.8 + 931 : 0.2 +state 766 observe1Greater1 observeIGreater1 + action 0 + 932 : 0.8 + 933 : 0.2 +state 767 observe1Greater1 observeIGreater1 + action 0 + 934 : 0.8 + 935 : 0.2 +state 768 observe1Greater1 observeIGreater1 + action 0 + 936 : 0.8 + 937 : 0.2 +state 769 observe1Greater1 observeIGreater1 + action 0 + 938 : 1 +state 770 + action 0 + 939 : 0.8 + 940 : 0.2 +state 771 + action 0 + 941 : 0.8 + 942 : 0.2 +state 772 + action 0 + 943 : 0.8 + 944 : 0.2 +state 773 + action 0 + 945 : 0.8 + 946 : 0.2 +state 774 + action 0 + 947 : 0.8 + 948 : 0.2 +state 775 + action 0 + 949 : 1 +state 776 + action 0 + 950 : 0.8 + 951 : 0.2 +state 777 + action 0 + 952 : 0.8 + 953 : 0.2 +state 778 + action 0 + 954 : 0.8 + 955 : 0.2 +state 779 + action 0 + 956 : 0.8 + 957 : 0.2 +state 780 + action 0 + 958 : 0.8 + 959 : 0.2 +state 781 + action 0 + 960 : 1 +state 782 + action 0 + 961 : 0.8 + 962 : 0.2 +state 783 + action 0 + 963 : 0.8 + 964 : 0.2 +state 784 + action 0 + 965 : 0.8 + 966 : 0.2 +state 785 + action 0 + 967 : 0.8 + 968 : 0.2 +state 786 + action 0 + 969 : 0.8 + 970 : 0.2 +state 787 + action 0 + 971 : 1 +state 788 + action 0 + 891 : 0.833 + 892 : 0.167 +state 789 observe1Greater1 observeIGreater1 + action 0 + 972 : 1 +state 790 + action 0 + 973 : 1 +state 791 + action 0 + 974 : 1 +state 792 + action 0 + 975 : 1 +state 793 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 794 observe0Greater1 observeOnlyTrueSender + action 0 + 981 : 1 +state 795 observe2Greater1 observeIGreater1 + action 0 + 982 : 0.8 + 983 : 0.2 +state 796 observe2Greater1 observeIGreater1 + action 0 + 984 : 0.8 + 985 : 0.2 +state 797 observe2Greater1 observeIGreater1 + action 0 + 986 : 0.8 + 987 : 0.2 +state 798 observe2Greater1 observeIGreater1 + action 0 + 988 : 0.8 + 989 : 0.2 +state 799 observe2Greater1 observeIGreater1 + action 0 + 990 : 0.8 + 991 : 0.2 +state 800 observe2Greater1 observeIGreater1 + action 0 + 992 : 1 +state 801 + action 0 + 993 : 0.8 + 994 : 0.2 +state 802 + action 0 + 995 : 0.8 + 996 : 0.2 +state 803 + action 0 + 997 : 0.8 + 998 : 0.2 +state 804 + action 0 + 999 : 0.8 + 1000 : 0.2 +state 805 + action 0 + 1001 : 0.8 + 1002 : 0.2 +state 806 + action 0 + 1003 : 1 +state 807 + action 0 + 1004 : 0.8 + 1005 : 0.2 +state 808 + action 0 + 1006 : 0.8 + 1007 : 0.2 +state 809 + action 0 + 1008 : 0.8 + 1009 : 0.2 +state 810 + action 0 + 1010 : 0.8 + 1011 : 0.2 +state 811 + action 0 + 1012 : 0.8 + 1013 : 0.2 +state 812 + action 0 + 1014 : 1 +state 813 + action 0 + 898 : 0.833 + 899 : 0.167 +state 814 + action 0 + 1015 : 1 +state 815 observe2Greater1 observeIGreater1 + action 0 + 1016 : 1 +state 816 + action 0 + 1017 : 1 +state 817 + action 0 + 1018 : 1 +state 818 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 819 observe0Greater1 observeOnlyTrueSender + action 0 + 1024 : 1 +state 820 observe3Greater1 observeIGreater1 + action 0 + 1025 : 0.8 + 1026 : 0.2 +state 821 observe3Greater1 observeIGreater1 + action 0 + 1027 : 0.8 + 1028 : 0.2 +state 822 observe3Greater1 observeIGreater1 + action 0 + 1029 : 0.8 + 1030 : 0.2 +state 823 observe3Greater1 observeIGreater1 + action 0 + 1031 : 0.8 + 1032 : 0.2 +state 824 observe3Greater1 observeIGreater1 + action 0 + 1033 : 0.8 + 1034 : 0.2 +state 825 observe3Greater1 observeIGreater1 + action 0 + 1035 : 1 +state 826 + action 0 + 1036 : 0.8 + 1037 : 0.2 +state 827 + action 0 + 1038 : 0.8 + 1039 : 0.2 +state 828 + action 0 + 1040 : 0.8 + 1041 : 0.2 +state 829 + action 0 + 1042 : 0.8 + 1043 : 0.2 +state 830 + action 0 + 1044 : 0.8 + 1045 : 0.2 +state 831 + action 0 + 1046 : 1 +state 832 + action 0 + 905 : 0.833 + 906 : 0.167 +state 833 + action 0 + 1047 : 1 +state 834 + action 0 + 1048 : 1 +state 835 observe3Greater1 observeIGreater1 + action 0 + 1049 : 1 +state 836 + action 0 + 1050 : 1 +state 837 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 838 observe0Greater1 observeOnlyTrueSender + action 0 + 1056 : 1 +state 839 observe4Greater1 observeIGreater1 + action 0 + 1057 : 0.8 + 1058 : 0.2 +state 840 observe4Greater1 observeIGreater1 + action 0 + 1059 : 0.8 + 1060 : 0.2 +state 841 observe4Greater1 observeIGreater1 + action 0 + 1061 : 0.8 + 1062 : 0.2 +state 842 observe4Greater1 observeIGreater1 + action 0 + 1063 : 0.8 + 1064 : 0.2 +state 843 observe4Greater1 observeIGreater1 + action 0 + 1065 : 0.8 + 1066 : 0.2 +state 844 observe4Greater1 observeIGreater1 + action 0 + 1067 : 1 +state 845 + action 0 + 912 : 0.833 + 913 : 0.167 +state 846 + action 0 + 1068 : 1 +state 847 + action 0 + 1069 : 1 +state 848 + action 0 + 1070 : 1 +state 849 observe4Greater1 observeIGreater1 + action 0 + 1071 : 1 +state 850 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 851 observe0Greater1 observeOnlyTrueSender + action 0 + 1077 : 1 +state 852 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 853 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 854 observe0Greater1 observeOnlyTrueSender + action 0 + 1079 : 1 +state 855 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 856 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 857 observe0Greater1 observeOnlyTrueSender + action 0 + 1080 : 1 +state 858 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 859 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 860 observe0Greater1 observeOnlyTrueSender + action 0 + 1081 : 1 +state 861 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 862 observe0Greater1 observeOnlyTrueSender + action 0 + 536 : 0.2 + 537 : 0.2 + 538 : 0.2 + 539 : 0.2 + 540 : 0.2 +state 863 observe0Greater1 observeOnlyTrueSender + action 0 + 1082 : 1 +state 864 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 1 +state 865 observe0Greater1 observeOnlyTrueSender + action 0 + 1083 : 0.833 + 1084 : 0.167 +state 866 + action 0 + 542 : 0.8 + 1085 : 0.2 +state 867 + action 0 + 1086 : 0.8 + 1087 : 0.2 +state 868 + action 0 + 1088 : 0.8 + 1089 : 0.2 +state 869 + action 0 + 1090 : 0.8 + 1091 : 0.2 +state 870 + action 0 + 1092 : 0.8 + 1093 : 0.2 +state 871 + action 0 + 1094 : 1 +state 872 + action 0 + 1095 : 0.833 + 1096 : 0.167 +state 873 + action 0 + 1097 : 0.833 + 1098 : 0.167 +state 874 + action 0 + 1099 : 0.833 + 1100 : 0.167 +state 875 + action 0 + 1101 : 0.833 + 1102 : 0.167 +state 876 + action 0 + 1103 : 1 +state 877 + action 0 + 1104 : 0.833 + 1105 : 0.167 +state 878 + action 0 + 1106 : 1 +state 879 + action 0 + 1107 : 0.833 + 1108 : 0.167 +state 880 + action 0 + 1109 : 1 +state 881 + action 0 + 1110 : 0.833 + 1111 : 0.167 +state 882 + action 0 + 1112 : 1 +state 883 + action 0 + 1113 : 0.833 + 1114 : 0.167 +state 884 + action 0 + 1115 : 1 +state 885 observe0Greater1 observeOnlyTrueSender + action 0 + 1116 : 1 +state 886 + action 0 + 1095 : 0.833 + 1096 : 0.167 +state 887 observe1Greater1 observeIGreater1 + action 0 + 1117 : 1 +state 888 + action 0 + 1118 : 1 +state 889 + action 0 + 1119 : 1 +state 890 + action 0 + 1120 : 1 +state 891 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 892 + action 0 + 1126 : 1 +state 893 + action 0 + 1097 : 0.833 + 1098 : 0.167 +state 894 + action 0 + 1127 : 1 +state 895 observe2Greater1 observeIGreater1 + action 0 + 1128 : 1 +state 896 + action 0 + 1129 : 1 +state 897 + action 0 + 1130 : 1 +state 898 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 899 + action 0 + 1136 : 1 +state 900 + action 0 + 1099 : 0.833 + 1100 : 0.167 +state 901 + action 0 + 1137 : 1 +state 902 + action 0 + 1138 : 1 +state 903 observe3Greater1 observeIGreater1 + action 0 + 1139 : 1 +state 904 + action 0 + 1140 : 1 +state 905 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 906 + action 0 + 1146 : 1 +state 907 + action 0 + 1101 : 0.833 + 1102 : 0.167 +state 908 + action 0 + 1147 : 1 +state 909 + action 0 + 1148 : 1 +state 910 + action 0 + 1149 : 1 +state 911 observe4Greater1 observeIGreater1 + action 0 + 1150 : 1 +state 912 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 913 + action 0 + 1156 : 1 +state 914 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 915 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 916 observe0Greater1 observeOnlyTrueSender + action 0 + 1158 : 1 +state 917 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 918 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 919 observe0Greater1 observeOnlyTrueSender + action 0 + 1159 : 1 +state 920 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 921 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 922 observe0Greater1 observeOnlyTrueSender + action 0 + 1160 : 1 +state 923 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 924 observe0Greater1 observeOnlyTrueSender + action 0 + 593 : 0.2 + 594 : 0.2 + 595 : 0.2 + 596 : 0.2 + 597 : 0.2 +state 925 observe0Greater1 observeOnlyTrueSender + action 0 + 1161 : 1 +state 926 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 1 +state 927 observe0Greater1 observeOnlyTrueSender + action 0 + 1162 : 0.833 + 1163 : 0.167 +state 928 observe1Greater1 observeIGreater1 + action 0 + 599 : 0.833 + 600 : 0.167 +state 929 observe1Greater1 observeIGreater1 + action 0 + 1164 : 1 +state 930 observe1Greater1 observeIGreater1 + action 0 + 1165 : 0.833 + 1166 : 0.167 +state 931 observe1Greater1 observeIGreater1 + action 0 + 1167 : 1 +state 932 observe1Greater1 observeIGreater1 + action 0 + 1168 : 0.833 + 1169 : 0.167 +state 933 observe1Greater1 observeIGreater1 + action 0 + 1170 : 1 +state 934 observe1Greater1 observeIGreater1 + action 0 + 1171 : 0.833 + 1172 : 0.167 +state 935 observe1Greater1 observeIGreater1 + action 0 + 1173 : 1 +state 936 observe1Greater1 observeIGreater1 + action 0 + 1174 : 0.833 + 1175 : 0.167 +state 937 observe1Greater1 observeIGreater1 + action 0 + 1176 : 1 +state 938 observe1Greater1 observeIGreater1 + action 0 + 1177 : 1 +state 939 + action 0 + 601 : 0.833 + 602 : 0.167 +state 940 + action 0 + 1178 : 1 +state 941 + action 0 + 1179 : 0.833 + 1180 : 0.167 +state 942 + action 0 + 1181 : 1 +state 943 + action 0 + 1182 : 0.833 + 1183 : 0.167 +state 944 + action 0 + 1184 : 1 +state 945 + action 0 + 1185 : 0.833 + 1186 : 0.167 +state 946 + action 0 + 1187 : 1 +state 947 + action 0 + 1188 : 0.833 + 1189 : 0.167 +state 948 + action 0 + 1190 : 1 +state 949 + action 0 + 1191 : 1 +state 950 + action 0 + 603 : 0.833 + 604 : 0.167 +state 951 + action 0 + 1192 : 1 +state 952 + action 0 + 1193 : 0.833 + 1194 : 0.167 +state 953 + action 0 + 1195 : 1 +state 954 + action 0 + 1196 : 0.833 + 1197 : 0.167 +state 955 + action 0 + 1198 : 1 +state 956 + action 0 + 1199 : 0.833 + 1200 : 0.167 +state 957 + action 0 + 1201 : 1 +state 958 + action 0 + 1202 : 0.833 + 1203 : 0.167 +state 959 + action 0 + 1204 : 1 +state 960 + action 0 + 1205 : 1 +state 961 + action 0 + 605 : 0.833 + 606 : 0.167 +state 962 + action 0 + 1206 : 1 +state 963 + action 0 + 1207 : 0.833 + 1208 : 0.167 +state 964 + action 0 + 1209 : 1 +state 965 + action 0 + 1210 : 0.833 + 1211 : 0.167 +state 966 + action 0 + 1212 : 1 +state 967 + action 0 + 1213 : 0.833 + 1214 : 0.167 +state 968 + action 0 + 1215 : 1 +state 969 + action 0 + 1216 : 0.833 + 1217 : 0.167 +state 970 + action 0 + 1218 : 1 +state 971 + action 0 + 1219 : 1 +state 972 observe1Greater1 observeIGreater1 + action 0 + 1177 : 1 +state 973 + action 0 + 1191 : 1 +state 974 + action 0 + 1205 : 1 +state 975 + action 0 + 1219 : 1 +state 976 observe0Greater1 observeOnlyTrueSender + action 0 + 1220 : 0.8 + 1221 : 0.2 +state 977 observe0Greater1 observeOnlyTrueSender + action 0 + 1222 : 0.8 + 1223 : 0.2 +state 978 observe0Greater1 observeOnlyTrueSender + action 0 + 1224 : 0.8 + 1225 : 0.2 +state 979 observe0Greater1 observeOnlyTrueSender + action 0 + 1226 : 0.8 + 1227 : 0.2 +state 980 observe0Greater1 observeOnlyTrueSender + action 0 + 1228 : 0.8 + 1229 : 0.2 +state 981 observe0Greater1 observeOnlyTrueSender + action 0 + 1230 : 1 +state 982 observe2Greater1 observeIGreater1 + action 0 + 621 : 0.833 + 622 : 0.167 +state 983 observe2Greater1 observeIGreater1 + action 0 + 1231 : 1 +state 984 observe2Greater1 observeIGreater1 + action 0 + 1232 : 0.833 + 1233 : 0.167 +state 985 observe2Greater1 observeIGreater1 + action 0 + 1234 : 1 +state 986 observe2Greater1 observeIGreater1 + action 0 + 1235 : 0.833 + 1236 : 0.167 +state 987 observe2Greater1 observeIGreater1 + action 0 + 1237 : 1 +state 988 observe2Greater1 observeIGreater1 + action 0 + 1238 : 0.833 + 1239 : 0.167 +state 989 observe2Greater1 observeIGreater1 + action 0 + 1240 : 1 +state 990 observe2Greater1 observeIGreater1 + action 0 + 1241 : 0.833 + 1242 : 0.167 +state 991 observe2Greater1 observeIGreater1 + action 0 + 1243 : 1 +state 992 observe2Greater1 observeIGreater1 + action 0 + 1244 : 1 +state 993 + action 0 + 623 : 0.833 + 624 : 0.167 +state 994 + action 0 + 1245 : 1 +state 995 + action 0 + 1246 : 0.833 + 1247 : 0.167 +state 996 + action 0 + 1248 : 1 +state 997 + action 0 + 1249 : 0.833 + 1250 : 0.167 +state 998 + action 0 + 1251 : 1 +state 999 + action 0 + 1252 : 0.833 + 1253 : 0.167 +state 1000 + action 0 + 1254 : 1 +state 1001 + action 0 + 1255 : 0.833 + 1256 : 0.167 +state 1002 + action 0 + 1257 : 1 +state 1003 + action 0 + 1258 : 1 +state 1004 + action 0 + 625 : 0.833 + 626 : 0.167 +state 1005 + action 0 + 1259 : 1 +state 1006 + action 0 + 1260 : 0.833 + 1261 : 0.167 +state 1007 + action 0 + 1262 : 1 +state 1008 + action 0 + 1263 : 0.833 + 1264 : 0.167 +state 1009 + action 0 + 1265 : 1 +state 1010 + action 0 + 1266 : 0.833 + 1267 : 0.167 +state 1011 + action 0 + 1268 : 1 +state 1012 + action 0 + 1269 : 0.833 + 1270 : 0.167 +state 1013 + action 0 + 1271 : 1 +state 1014 + action 0 + 1272 : 1 +state 1015 + action 0 + 1191 : 1 +state 1016 observe2Greater1 observeIGreater1 + action 0 + 1244 : 1 +state 1017 + action 0 + 1258 : 1 +state 1018 + action 0 + 1272 : 1 +state 1019 observe0Greater1 observeOnlyTrueSender + action 0 + 1273 : 0.8 + 1274 : 0.2 +state 1020 observe0Greater1 observeOnlyTrueSender + action 0 + 1275 : 0.8 + 1276 : 0.2 +state 1021 observe0Greater1 observeOnlyTrueSender + action 0 + 1277 : 0.8 + 1278 : 0.2 +state 1022 observe0Greater1 observeOnlyTrueSender + action 0 + 1279 : 0.8 + 1280 : 0.2 +state 1023 observe0Greater1 observeOnlyTrueSender + action 0 + 1281 : 0.8 + 1282 : 0.2 +state 1024 observe0Greater1 observeOnlyTrueSender + action 0 + 1283 : 1 +state 1025 observe3Greater1 observeIGreater1 + action 0 + 641 : 0.833 + 642 : 0.167 +state 1026 observe3Greater1 observeIGreater1 + action 0 + 1284 : 1 +state 1027 observe3Greater1 observeIGreater1 + action 0 + 1285 : 0.833 + 1286 : 0.167 +state 1028 observe3Greater1 observeIGreater1 + action 0 + 1287 : 1 +state 1029 observe3Greater1 observeIGreater1 + action 0 + 1288 : 0.833 + 1289 : 0.167 +state 1030 observe3Greater1 observeIGreater1 + action 0 + 1290 : 1 +state 1031 observe3Greater1 observeIGreater1 + action 0 + 1291 : 0.833 + 1292 : 0.167 +state 1032 observe3Greater1 observeIGreater1 + action 0 + 1293 : 1 +state 1033 observe3Greater1 observeIGreater1 + action 0 + 1294 : 0.833 + 1295 : 0.167 +state 1034 observe3Greater1 observeIGreater1 + action 0 + 1296 : 1 +state 1035 observe3Greater1 observeIGreater1 + action 0 + 1297 : 1 +state 1036 + action 0 + 643 : 0.833 + 644 : 0.167 +state 1037 + action 0 + 1298 : 1 +state 1038 + action 0 + 1299 : 0.833 + 1300 : 0.167 +state 1039 + action 0 + 1301 : 1 +state 1040 + action 0 + 1302 : 0.833 + 1303 : 0.167 +state 1041 + action 0 + 1304 : 1 +state 1042 + action 0 + 1305 : 0.833 + 1306 : 0.167 +state 1043 + action 0 + 1307 : 1 +state 1044 + action 0 + 1308 : 0.833 + 1309 : 0.167 +state 1045 + action 0 + 1310 : 1 +state 1046 + action 0 + 1311 : 1 +state 1047 + action 0 + 1205 : 1 +state 1048 + action 0 + 1258 : 1 +state 1049 observe3Greater1 observeIGreater1 + action 0 + 1297 : 1 +state 1050 + action 0 + 1311 : 1 +state 1051 observe0Greater1 observeOnlyTrueSender + action 0 + 1312 : 0.8 + 1313 : 0.2 +state 1052 observe0Greater1 observeOnlyTrueSender + action 0 + 1314 : 0.8 + 1315 : 0.2 +state 1053 observe0Greater1 observeOnlyTrueSender + action 0 + 1316 : 0.8 + 1317 : 0.2 +state 1054 observe0Greater1 observeOnlyTrueSender + action 0 + 1318 : 0.8 + 1319 : 0.2 +state 1055 observe0Greater1 observeOnlyTrueSender + action 0 + 1320 : 0.8 + 1321 : 0.2 +state 1056 observe0Greater1 observeOnlyTrueSender + action 0 + 1322 : 1 +state 1057 observe4Greater1 observeIGreater1 + action 0 + 659 : 0.833 + 660 : 0.167 +state 1058 observe4Greater1 observeIGreater1 + action 0 + 1323 : 1 +state 1059 observe4Greater1 observeIGreater1 + action 0 + 1324 : 0.833 + 1325 : 0.167 +state 1060 observe4Greater1 observeIGreater1 + action 0 + 1326 : 1 +state 1061 observe4Greater1 observeIGreater1 + action 0 + 1327 : 0.833 + 1328 : 0.167 +state 1062 observe4Greater1 observeIGreater1 + action 0 + 1329 : 1 +state 1063 observe4Greater1 observeIGreater1 + action 0 + 1330 : 0.833 + 1331 : 0.167 +state 1064 observe4Greater1 observeIGreater1 + action 0 + 1332 : 1 +state 1065 observe4Greater1 observeIGreater1 + action 0 + 1333 : 0.833 + 1334 : 0.167 +state 1066 observe4Greater1 observeIGreater1 + action 0 + 1335 : 1 +state 1067 observe4Greater1 observeIGreater1 + action 0 + 1336 : 1 +state 1068 + action 0 + 1219 : 1 +state 1069 + action 0 + 1272 : 1 +state 1070 + action 0 + 1311 : 1 +state 1071 observe4Greater1 observeIGreater1 + action 0 + 1336 : 1 +state 1072 observe0Greater1 observeOnlyTrueSender + action 0 + 1337 : 0.8 + 1338 : 0.2 +state 1073 observe0Greater1 observeOnlyTrueSender + action 0 + 1339 : 0.8 + 1340 : 0.2 +state 1074 observe0Greater1 observeOnlyTrueSender + action 0 + 1341 : 0.8 + 1342 : 0.2 +state 1075 observe0Greater1 observeOnlyTrueSender + action 0 + 1343 : 0.8 + 1344 : 0.2 +state 1076 observe0Greater1 observeOnlyTrueSender + action 0 + 1345 : 0.8 + 1346 : 0.2 +state 1077 observe0Greater1 observeOnlyTrueSender + action 0 + 1347 : 1 +state 1078 observe0Greater1 observeOnlyTrueSender + action 0 + 1162 : 0.833 + 1163 : 0.167 +state 1079 observe0Greater1 observeOnlyTrueSender + action 0 + 1348 : 1 +state 1080 observe0Greater1 observeOnlyTrueSender + action 0 + 1349 : 1 +state 1081 observe0Greater1 observeOnlyTrueSender + action 0 + 1350 : 1 +state 1082 observe0Greater1 observeOnlyTrueSender + action 0 + 1351 : 1 +state 1083 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1084 observe0Greater1 observeOnlyTrueSender + action 0 + 1357 : 1 +state 1085 + action 0 + 1358 : 1 +state 1086 + action 0 + 1359 : 0.833 + 1360 : 0.167 +state 1087 + action 0 + 1361 : 1 +state 1088 + action 0 + 1362 : 0.833 + 1363 : 0.167 +state 1089 + action 0 + 1364 : 1 +state 1090 + action 0 + 1365 : 0.833 + 1366 : 0.167 +state 1091 + action 0 + 1367 : 1 +state 1092 + action 0 + 1368 : 0.833 + 1369 : 0.167 +state 1093 + action 0 + 1370 : 1 +state 1094 + action 0 + 1371 : 1 +state 1095 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1096 + action 0 + 1377 : 1 +state 1097 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1098 + action 0 + 1383 : 1 +state 1099 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1100 + action 0 + 1389 : 1 +state 1101 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1102 + action 0 + 1395 : 1 +state 1103 + action 0 + 1396 : 1 +state 1104 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1105 + action 0 + 1397 : 1 +state 1106 + action 0 + 1396 : 1 +state 1107 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1108 + action 0 + 1398 : 1 +state 1109 + action 0 + 1396 : 1 +state 1110 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1111 + action 0 + 1399 : 1 +state 1112 + action 0 + 1396 : 1 +state 1113 + action 0 + 692 : 0.2 + 693 : 0.2 + 694 : 0.2 + 695 : 0.2 + 696 : 0.2 +state 1114 + action 0 + 1400 : 1 +state 1115 + action 0 + 1396 : 1 +state 1116 observe0Greater1 observeOnlyTrueSender + action 0 + 1401 : 0.833 + 1402 : 0.167 +state 1117 observe1Greater1 observeIGreater1 + action 0 + 1403 : 1 +state 1118 + action 0 + 1404 : 1 +state 1119 + action 0 + 1405 : 1 +state 1120 + action 0 + 1406 : 1 +state 1121 + action 0 + 788 : 0.8 + 1407 : 0.2 +state 1122 + action 0 + 1408 : 0.8 + 1409 : 0.2 +state 1123 + action 0 + 1410 : 0.8 + 1411 : 0.2 +state 1124 + action 0 + 1412 : 0.8 + 1413 : 0.2 +state 1125 + action 0 + 1414 : 0.8 + 1415 : 0.2 +state 1126 observe0Greater1 observeOnlyTrueSender + action 0 + 1416 : 1 +state 1127 + action 0 + 1404 : 1 +state 1128 observe2Greater1 observeIGreater1 + action 0 + 1417 : 1 +state 1129 + action 0 + 1418 : 1 +state 1130 + action 0 + 1419 : 1 +state 1131 + action 0 + 813 : 0.8 + 1420 : 0.2 +state 1132 + action 0 + 1421 : 0.8 + 1422 : 0.2 +state 1133 + action 0 + 1423 : 0.8 + 1424 : 0.2 +state 1134 + action 0 + 1425 : 0.8 + 1426 : 0.2 +state 1135 + action 0 + 1427 : 0.8 + 1428 : 0.2 +state 1136 observe0Greater1 observeOnlyTrueSender + action 0 + 1429 : 1 +state 1137 + action 0 + 1405 : 1 +state 1138 + action 0 + 1418 : 1 +state 1139 observe3Greater1 observeIGreater1 + action 0 + 1430 : 1 +state 1140 + action 0 + 1431 : 1 +state 1141 + action 0 + 832 : 0.8 + 1432 : 0.2 +state 1142 + action 0 + 1433 : 0.8 + 1434 : 0.2 +state 1143 + action 0 + 1435 : 0.8 + 1436 : 0.2 +state 1144 + action 0 + 1437 : 0.8 + 1438 : 0.2 +state 1145 + action 0 + 1439 : 0.8 + 1440 : 0.2 +state 1146 observe0Greater1 observeOnlyTrueSender + action 0 + 1441 : 1 +state 1147 + action 0 + 1406 : 1 +state 1148 + action 0 + 1419 : 1 +state 1149 + action 0 + 1431 : 1 +state 1150 observe4Greater1 observeIGreater1 + action 0 + 1442 : 1 +state 1151 + action 0 + 845 : 0.8 + 1443 : 0.2 +state 1152 + action 0 + 1444 : 0.8 + 1445 : 0.2 +state 1153 + action 0 + 1446 : 0.8 + 1447 : 0.2 +state 1154 + action 0 + 1448 : 0.8 + 1449 : 0.2 +state 1155 + action 0 + 1450 : 0.8 + 1451 : 0.2 +state 1156 observe0Greater1 observeOnlyTrueSender + action 0 + 1452 : 1 +state 1157 observe0Greater1 observeOnlyTrueSender + action 0 + 1401 : 0.833 + 1402 : 0.167 +state 1158 observe0Greater1 observeOnlyTrueSender + action 0 + 1453 : 1 +state 1159 observe0Greater1 observeOnlyTrueSender + action 0 + 1454 : 1 +state 1160 observe0Greater1 observeOnlyTrueSender + action 0 + 1455 : 1 +state 1161 observe0Greater1 observeOnlyTrueSender + action 0 + 1456 : 1 +state 1162 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 1163 observe0Greater1 observeOnlyTrueSender + action 0 + 1462 : 1 +state 1164 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1165 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1166 observe1Greater1 observeIGreater1 + action 0 + 1464 : 1 +state 1167 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1168 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1169 observe1Greater1 observeIGreater1 + action 0 + 1465 : 1 +state 1170 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1171 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1172 observe1Greater1 observeIGreater1 + action 0 + 1466 : 1 +state 1173 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1174 observe1Greater1 observeIGreater1 + action 0 + 764 : 0.2 + 765 : 0.2 + 766 : 0.2 + 767 : 0.2 + 768 : 0.2 +state 1175 observe1Greater1 observeIGreater1 + action 0 + 1467 : 1 +state 1176 observe1Greater1 observeIGreater1 + action 0 + 1463 : 1 +state 1177 observe1Greater1 observeIGreater1 + action 0 + 1468 : 0.833 + 1469 : 0.167 +state 1178 + action 0 + 1470 : 1 +state 1179 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1180 + action 0 + 1471 : 1 +state 1181 + action 0 + 1470 : 1 +state 1182 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1183 + action 0 + 1472 : 1 +state 1184 + action 0 + 1470 : 1 +state 1185 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1186 + action 0 + 1473 : 1 +state 1187 + action 0 + 1470 : 1 +state 1188 + action 0 + 770 : 0.2 + 771 : 0.2 + 772 : 0.2 + 773 : 0.2 + 774 : 0.2 +state 1189 + action 0 + 1474 : 1 +state 1190 + action 0 + 1470 : 1 +state 1191 + action 0 + 1475 : 0.833 + 1476 : 0.167 +state 1192 + action 0 + 1477 : 1 +state 1193 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1194 + action 0 + 1478 : 1 +state 1195 + action 0 + 1477 : 1 +state 1196 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1197 + action 0 + 1479 : 1 +state 1198 + action 0 + 1477 : 1 +state 1199 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1200 + action 0 + 1480 : 1 +state 1201 + action 0 + 1477 : 1 +state 1202 + action 0 + 776 : 0.2 + 777 : 0.2 + 778 : 0.2 + 779 : 0.2 + 780 : 0.2 +state 1203 + action 0 + 1481 : 1 +state 1204 + action 0 + 1477 : 1 +state 1205 + action 0 + 1482 : 0.833 + 1483 : 0.167 +state 1206 + action 0 + 1484 : 1 +state 1207 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1208 + action 0 + 1485 : 1 +state 1209 + action 0 + 1484 : 1 +state 1210 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1211 + action 0 + 1486 : 1 +state 1212 + action 0 + 1484 : 1 +state 1213 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1214 + action 0 + 1487 : 1 +state 1215 + action 0 + 1484 : 1 +state 1216 + action 0 + 782 : 0.2 + 783 : 0.2 + 784 : 0.2 + 785 : 0.2 + 786 : 0.2 +state 1217 + action 0 + 1488 : 1 +state 1218 + action 0 + 1484 : 1 +state 1219 + action 0 + 1489 : 0.833 + 1490 : 0.167 +state 1220 observe0Greater1 observeOnlyTrueSender + action 0 + 793 : 0.833 + 794 : 0.167 +state 1221 observe0Greater1 observeOnlyTrueSender + action 0 + 1491 : 1 +state 1222 observe0Greater1 observeOnlyTrueSender + action 0 + 1492 : 0.833 + 1493 : 0.167 +state 1223 observe0Greater1 observeOnlyTrueSender + action 0 + 1494 : 1 +state 1224 observe0Greater1 observeOnlyTrueSender + action 0 + 1495 : 0.833 + 1496 : 0.167 +state 1225 observe0Greater1 observeOnlyTrueSender + action 0 + 1497 : 1 +state 1226 observe0Greater1 observeOnlyTrueSender + action 0 + 1498 : 0.833 + 1499 : 0.167 +state 1227 observe0Greater1 observeOnlyTrueSender + action 0 + 1500 : 1 +state 1228 observe0Greater1 observeOnlyTrueSender + action 0 + 1501 : 0.833 + 1502 : 0.167 +state 1229 observe0Greater1 observeOnlyTrueSender + action 0 + 1503 : 1 +state 1230 observe0Greater1 observeOnlyTrueSender + action 0 + 1504 : 1 +state 1231 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1232 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1233 observe2Greater1 observeIGreater1 + action 0 + 1506 : 1 +state 1234 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1235 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1236 observe2Greater1 observeIGreater1 + action 0 + 1507 : 1 +state 1237 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1238 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1239 observe2Greater1 observeIGreater1 + action 0 + 1508 : 1 +state 1240 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1241 observe2Greater1 observeIGreater1 + action 0 + 795 : 0.2 + 796 : 0.2 + 797 : 0.2 + 798 : 0.2 + 799 : 0.2 +state 1242 observe2Greater1 observeIGreater1 + action 0 + 1509 : 1 +state 1243 observe2Greater1 observeIGreater1 + action 0 + 1505 : 1 +state 1244 observe2Greater1 observeIGreater1 + action 0 + 1510 : 0.833 + 1511 : 0.167 +state 1245 + action 0 + 1512 : 1 +state 1246 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1247 + action 0 + 1513 : 1 +state 1248 + action 0 + 1512 : 1 +state 1249 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1250 + action 0 + 1514 : 1 +state 1251 + action 0 + 1512 : 1 +state 1252 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1253 + action 0 + 1515 : 1 +state 1254 + action 0 + 1512 : 1 +state 1255 + action 0 + 801 : 0.2 + 802 : 0.2 + 803 : 0.2 + 804 : 0.2 + 805 : 0.2 +state 1256 + action 0 + 1516 : 1 +state 1257 + action 0 + 1512 : 1 +state 1258 + action 0 + 1517 : 0.833 + 1518 : 0.167 +state 1259 + action 0 + 1519 : 1 +state 1260 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1261 + action 0 + 1520 : 1 +state 1262 + action 0 + 1519 : 1 +state 1263 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1264 + action 0 + 1521 : 1 +state 1265 + action 0 + 1519 : 1 +state 1266 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1267 + action 0 + 1522 : 1 +state 1268 + action 0 + 1519 : 1 +state 1269 + action 0 + 807 : 0.2 + 808 : 0.2 + 809 : 0.2 + 810 : 0.2 + 811 : 0.2 +state 1270 + action 0 + 1523 : 1 +state 1271 + action 0 + 1519 : 1 +state 1272 + action 0 + 1524 : 0.833 + 1525 : 0.167 +state 1273 observe0Greater1 observeOnlyTrueSender + action 0 + 818 : 0.833 + 819 : 0.167 +state 1274 observe0Greater1 observeOnlyTrueSender + action 0 + 1526 : 1 +state 1275 observe0Greater1 observeOnlyTrueSender + action 0 + 1527 : 0.833 + 1528 : 0.167 +state 1276 observe0Greater1 observeOnlyTrueSender + action 0 + 1529 : 1 +state 1277 observe0Greater1 observeOnlyTrueSender + action 0 + 1530 : 0.833 + 1531 : 0.167 +state 1278 observe0Greater1 observeOnlyTrueSender + action 0 + 1532 : 1 +state 1279 observe0Greater1 observeOnlyTrueSender + action 0 + 1533 : 0.833 + 1534 : 0.167 +state 1280 observe0Greater1 observeOnlyTrueSender + action 0 + 1535 : 1 +state 1281 observe0Greater1 observeOnlyTrueSender + action 0 + 1536 : 0.833 + 1537 : 0.167 +state 1282 observe0Greater1 observeOnlyTrueSender + action 0 + 1538 : 1 +state 1283 observe0Greater1 observeOnlyTrueSender + action 0 + 1539 : 1 +state 1284 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1285 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1286 observe3Greater1 observeIGreater1 + action 0 + 1541 : 1 +state 1287 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1288 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1289 observe3Greater1 observeIGreater1 + action 0 + 1542 : 1 +state 1290 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1291 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1292 observe3Greater1 observeIGreater1 + action 0 + 1543 : 1 +state 1293 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1294 observe3Greater1 observeIGreater1 + action 0 + 820 : 0.2 + 821 : 0.2 + 822 : 0.2 + 823 : 0.2 + 824 : 0.2 +state 1295 observe3Greater1 observeIGreater1 + action 0 + 1544 : 1 +state 1296 observe3Greater1 observeIGreater1 + action 0 + 1540 : 1 +state 1297 observe3Greater1 observeIGreater1 + action 0 + 1545 : 0.833 + 1546 : 0.167 +state 1298 + action 0 + 1547 : 1 +state 1299 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1300 + action 0 + 1548 : 1 +state 1301 + action 0 + 1547 : 1 +state 1302 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1303 + action 0 + 1549 : 1 +state 1304 + action 0 + 1547 : 1 +state 1305 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1306 + action 0 + 1550 : 1 +state 1307 + action 0 + 1547 : 1 +state 1308 + action 0 + 826 : 0.2 + 827 : 0.2 + 828 : 0.2 + 829 : 0.2 + 830 : 0.2 +state 1309 + action 0 + 1551 : 1 +state 1310 + action 0 + 1547 : 1 +state 1311 + action 0 + 1552 : 0.833 + 1553 : 0.167 +state 1312 observe0Greater1 observeOnlyTrueSender + action 0 + 837 : 0.833 + 838 : 0.167 +state 1313 observe0Greater1 observeOnlyTrueSender + action 0 + 1554 : 1 +state 1314 observe0Greater1 observeOnlyTrueSender + action 0 + 1555 : 0.833 + 1556 : 0.167 +state 1315 observe0Greater1 observeOnlyTrueSender + action 0 + 1557 : 1 +state 1316 observe0Greater1 observeOnlyTrueSender + action 0 + 1558 : 0.833 + 1559 : 0.167 +state 1317 observe0Greater1 observeOnlyTrueSender + action 0 + 1560 : 1 +state 1318 observe0Greater1 observeOnlyTrueSender + action 0 + 1561 : 0.833 + 1562 : 0.167 +state 1319 observe0Greater1 observeOnlyTrueSender + action 0 + 1563 : 1 +state 1320 observe0Greater1 observeOnlyTrueSender + action 0 + 1564 : 0.833 + 1565 : 0.167 +state 1321 observe0Greater1 observeOnlyTrueSender + action 0 + 1566 : 1 +state 1322 observe0Greater1 observeOnlyTrueSender + action 0 + 1567 : 1 +state 1323 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1324 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1325 observe4Greater1 observeIGreater1 + action 0 + 1569 : 1 +state 1326 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1327 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1328 observe4Greater1 observeIGreater1 + action 0 + 1570 : 1 +state 1329 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1330 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1331 observe4Greater1 observeIGreater1 + action 0 + 1571 : 1 +state 1332 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1333 observe4Greater1 observeIGreater1 + action 0 + 839 : 0.2 + 840 : 0.2 + 841 : 0.2 + 842 : 0.2 + 843 : 0.2 +state 1334 observe4Greater1 observeIGreater1 + action 0 + 1572 : 1 +state 1335 observe4Greater1 observeIGreater1 + action 0 + 1568 : 1 +state 1336 observe4Greater1 observeIGreater1 + action 0 + 1573 : 0.833 + 1574 : 0.167 +state 1337 observe0Greater1 observeOnlyTrueSender + action 0 + 850 : 0.833 + 851 : 0.167 +state 1338 observe0Greater1 observeOnlyTrueSender + action 0 + 1575 : 1 +state 1339 observe0Greater1 observeOnlyTrueSender + action 0 + 1576 : 0.833 + 1577 : 0.167 +state 1340 observe0Greater1 observeOnlyTrueSender + action 0 + 1578 : 1 +state 1341 observe0Greater1 observeOnlyTrueSender + action 0 + 1579 : 0.833 + 1580 : 0.167 +state 1342 observe0Greater1 observeOnlyTrueSender + action 0 + 1581 : 1 +state 1343 observe0Greater1 observeOnlyTrueSender + action 0 + 1582 : 0.833 + 1583 : 0.167 +state 1344 observe0Greater1 observeOnlyTrueSender + action 0 + 1584 : 1 +state 1345 observe0Greater1 observeOnlyTrueSender + action 0 + 1585 : 0.833 + 1586 : 0.167 +state 1346 observe0Greater1 observeOnlyTrueSender + action 0 + 1587 : 1 +state 1347 observe0Greater1 observeOnlyTrueSender + action 0 + 1588 : 1 +state 1348 observe0Greater1 observeOnlyTrueSender + action 0 + 1504 : 1 +state 1349 observe0Greater1 observeOnlyTrueSender + action 0 + 1539 : 1 +state 1350 observe0Greater1 observeOnlyTrueSender + action 0 + 1567 : 1 +state 1351 observe0Greater1 observeOnlyTrueSender + action 0 + 1588 : 1 +state 1352 observe0Greater1 observeOnlyTrueSender + action 0 + 1589 : 0.8 + 1590 : 0.2 +state 1353 observe0Greater1 observeOnlyTrueSender + action 0 + 1591 : 0.8 + 1592 : 0.2 +state 1354 observe0Greater1 observeOnlyTrueSender + action 0 + 1593 : 0.8 + 1594 : 0.2 +state 1355 observe0Greater1 observeOnlyTrueSender + action 0 + 1595 : 0.8 + 1596 : 0.2 +state 1356 observe0Greater1 observeOnlyTrueSender + action 0 + 1597 : 0.8 + 1598 : 0.2 +state 1357 observe0Greater1 observeOnlyTrueSender + action 0 + 1599 : 1 +state 1358 + action 0 + 1600 : 1 +state 1359 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1360 + action 0 + 1601 : 1 +state 1361 + action 0 + 1600 : 1 +state 1362 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1363 + action 0 + 1602 : 1 +state 1364 + action 0 + 1600 : 1 +state 1365 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1366 + action 0 + 1603 : 1 +state 1367 + action 0 + 1600 : 1 +state 1368 + action 0 + 866 : 0.2 + 867 : 0.2 + 868 : 0.2 + 869 : 0.2 + 870 : 0.2 +state 1369 + action 0 + 1604 : 1 +state 1370 + action 0 + 1600 : 1 +state 1371 + action 0 + 1605 : 0.833 + 1606 : 0.167 +state 1372 + action 0 + 886 : 0.8 + 1607 : 0.2 +state 1373 + action 0 + 1608 : 0.8 + 1609 : 0.2 +state 1374 + action 0 + 1610 : 0.8 + 1611 : 0.2 +state 1375 + action 0 + 1612 : 0.8 + 1613 : 0.2 +state 1376 + action 0 + 1614 : 0.8 + 1615 : 0.2 +state 1377 + action 0 + 1616 : 1 +state 1378 + action 0 + 893 : 0.8 + 1617 : 0.2 +state 1379 + action 0 + 1618 : 0.8 + 1619 : 0.2 +state 1380 + action 0 + 1620 : 0.8 + 1621 : 0.2 +state 1381 + action 0 + 1622 : 0.8 + 1623 : 0.2 +state 1382 + action 0 + 1624 : 0.8 + 1625 : 0.2 +state 1383 + action 0 + 1626 : 1 +state 1384 + action 0 + 900 : 0.8 + 1627 : 0.2 +state 1385 + action 0 + 1628 : 0.8 + 1629 : 0.2 +state 1386 + action 0 + 1630 : 0.8 + 1631 : 0.2 +state 1387 + action 0 + 1632 : 0.8 + 1633 : 0.2 +state 1388 + action 0 + 1634 : 0.8 + 1635 : 0.2 +state 1389 + action 0 + 1636 : 1 +state 1390 + action 0 + 907 : 0.8 + 1637 : 0.2 +state 1391 + action 0 + 1638 : 0.8 + 1639 : 0.2 +state 1392 + action 0 + 1640 : 0.8 + 1641 : 0.2 +state 1393 + action 0 + 1642 : 0.8 + 1643 : 0.2 +state 1394 + action 0 + 1644 : 0.8 + 1645 : 0.2 +state 1395 + action 0 + 1646 : 1 +state 1396 + action 0 + 1605 : 0.833 + 1606 : 0.167 +state 1397 + action 0 + 1647 : 1 +state 1398 + action 0 + 1648 : 1 +state 1399 + action 0 + 1649 : 1 +state 1400 + action 0 + 1650 : 1 +state 1401 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 1402 observe0Greater1 observeOnlyTrueSender + action 0 + 1656 : 1 +state 1403 observe1Greater1 observeIGreater1 + action 0 + 1657 : 0.833 + 1658 : 0.167 +state 1404 + action 0 + 1659 : 0.833 + 1660 : 0.167 +state 1405 + action 0 + 1661 : 0.833 + 1662 : 0.167 +state 1406 + action 0 + 1663 : 0.833 + 1664 : 0.167 +state 1407 + action 0 + 1665 : 1 +state 1408 + action 0 + 1666 : 0.833 + 1667 : 0.167 +state 1409 + action 0 + 1668 : 1 +state 1410 + action 0 + 1669 : 0.833 + 1670 : 0.167 +state 1411 + action 0 + 1671 : 1 +state 1412 + action 0 + 1672 : 0.833 + 1673 : 0.167 +state 1413 + action 0 + 1674 : 1 +state 1414 + action 0 + 1675 : 0.833 + 1676 : 0.167 +state 1415 + action 0 + 1677 : 1 +state 1416 observe0Greater1 observeOnlyTrueSender + action 0 + 1678 : 1 +state 1417 observe2Greater1 observeIGreater1 + action 0 + 1679 : 0.833 + 1680 : 0.167 +state 1418 + action 0 + 1681 : 0.833 + 1682 : 0.167 +state 1419 + action 0 + 1683 : 0.833 + 1684 : 0.167 +state 1420 + action 0 + 1685 : 1 +state 1421 + action 0 + 1686 : 0.833 + 1687 : 0.167 +state 1422 + action 0 + 1688 : 1 +state 1423 + action 0 + 1689 : 0.833 + 1690 : 0.167 +state 1424 + action 0 + 1691 : 1 +state 1425 + action 0 + 1692 : 0.833 + 1693 : 0.167 +state 1426 + action 0 + 1694 : 1 +state 1427 + action 0 + 1695 : 0.833 + 1696 : 0.167 +state 1428 + action 0 + 1697 : 1 +state 1429 observe0Greater1 observeOnlyTrueSender + action 0 + 1698 : 1 +state 1430 observe3Greater1 observeIGreater1 + action 0 + 1699 : 0.833 + 1700 : 0.167 +state 1431 + action 0 + 1701 : 0.833 + 1702 : 0.167 +state 1432 + action 0 + 1703 : 1 +state 1433 + action 0 + 1704 : 0.833 + 1705 : 0.167 +state 1434 + action 0 + 1706 : 1 +state 1435 + action 0 + 1707 : 0.833 + 1708 : 0.167 +state 1436 + action 0 + 1709 : 1 +state 1437 + action 0 + 1710 : 0.833 + 1711 : 0.167 +state 1438 + action 0 + 1712 : 1 +state 1439 + action 0 + 1713 : 0.833 + 1714 : 0.167 +state 1440 + action 0 + 1715 : 1 +state 1441 observe0Greater1 observeOnlyTrueSender + action 0 + 1716 : 1 +state 1442 observe4Greater1 observeIGreater1 + action 0 + 1717 : 0.833 + 1718 : 0.167 +state 1443 + action 0 + 1719 : 1 +state 1444 + action 0 + 1720 : 0.833 + 1721 : 0.167 +state 1445 + action 0 + 1722 : 1 +state 1446 + action 0 + 1723 : 0.833 + 1724 : 0.167 +state 1447 + action 0 + 1725 : 1 +state 1448 + action 0 + 1726 : 0.833 + 1727 : 0.167 +state 1449 + action 0 + 1728 : 1 +state 1450 + action 0 + 1729 : 0.833 + 1730 : 0.167 +state 1451 + action 0 + 1731 : 1 +state 1452 observe0Greater1 observeOnlyTrueSender + action 0 + 1732 : 1 +state 1453 observe0Greater1 observeOnlyTrueSender + action 0 + 1678 : 1 +state 1454 observe0Greater1 observeOnlyTrueSender + action 0 + 1698 : 1 +state 1455 observe0Greater1 observeOnlyTrueSender + action 0 + 1716 : 1 +state 1456 observe0Greater1 observeOnlyTrueSender + action 0 + 1732 : 1 +state 1457 observe0Greater1 observeOnlyTrueSender + action 0 + 1078 : 0.8 + 1733 : 0.2 +state 1458 observe0Greater1 observeOnlyTrueSender + action 0 + 1734 : 0.8 + 1735 : 0.2 +state 1459 observe0Greater1 observeOnlyTrueSender + action 0 + 1736 : 0.8 + 1737 : 0.2 +state 1460 observe0Greater1 observeOnlyTrueSender + action 0 + 1738 : 0.8 + 1739 : 0.2 +state 1461 observe0Greater1 observeOnlyTrueSender + action 0 + 1740 : 0.8 + 1741 : 0.2 +state 1462 observe0Greater1 observeOnlyTrueSender + action 0 + 1742 : 1 +state 1463 observe1Greater1 observeIGreater1 + action 0 + 1657 : 0.833 + 1658 : 0.167 +state 1464 observe1Greater1 observeIGreater1 + action 0 + 1743 : 1 +state 1465 observe1Greater1 observeIGreater1 + action 0 + 1744 : 1 +state 1466 observe1Greater1 observeIGreater1 + action 0 + 1745 : 1 +state 1467 observe1Greater1 observeIGreater1 + action 0 + 1746 : 1 +state 1468 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 1469 observe1Greater1 observeIGreater1 + action 0 + 1752 : 1 +state 1470 + action 0 + 1659 : 0.833 + 1660 : 0.167 +state 1471 observe1Greater1 observeIGreater1 + action 0 + 1753 : 1 +state 1472 observe2Greater1 observeIGreater1 + action 0 + 1754 : 1 +state 1473 + action 0 + 1755 : 1 +state 1474 + action 0 + 1756 : 1 +state 1475 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 1476 + action 0 + 1762 : 1 +state 1477 + action 0 + 1661 : 0.833 + 1662 : 0.167 +state 1478 observe1Greater1 observeIGreater1 + action 0 + 1763 : 1 +state 1479 + action 0 + 1764 : 1 +state 1480 observe3Greater1 observeIGreater1 + action 0 + 1765 : 1 +state 1481 + action 0 + 1766 : 1 +state 1482 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 1483 + action 0 + 1772 : 1 +state 1484 + action 0 + 1663 : 0.833 + 1664 : 0.167 +state 1485 observe1Greater1 observeIGreater1 + action 0 + 1773 : 1 +state 1486 + action 0 + 1774 : 1 +state 1487 + action 0 + 1775 : 1 +state 1488 observe4Greater1 observeIGreater1 + action 0 + 1776 : 1 +state 1489 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 1490 + action 0 + 1782 : 1 +state 1491 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1492 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1493 observe0Greater1 observeOnlyTrueSender + action 0 + 1784 : 1 +state 1494 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1495 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1496 observe0Greater1 observeOnlyTrueSender + action 0 + 1785 : 1 +state 1497 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1498 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1499 observe0Greater1 observeOnlyTrueSender + action 0 + 1786 : 1 +state 1500 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1501 observe0Greater1 observeOnlyTrueSender + action 0 + 976 : 0.2 + 977 : 0.2 + 978 : 0.2 + 979 : 0.2 + 980 : 0.2 +state 1502 observe0Greater1 observeOnlyTrueSender + action 0 + 1787 : 1 +state 1503 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 1 +state 1504 observe0Greater1 observeOnlyTrueSender + action 0 + 1788 : 0.833 + 1789 : 0.167 +state 1505 observe2Greater1 observeIGreater1 + action 0 + 1679 : 0.833 + 1680 : 0.167 +state 1506 observe2Greater1 observeIGreater1 + action 0 + 1790 : 1 +state 1507 observe2Greater1 observeIGreater1 + action 0 + 1791 : 1 +state 1508 observe2Greater1 observeIGreater1 + action 0 + 1792 : 1 +state 1509 observe2Greater1 observeIGreater1 + action 0 + 1793 : 1 +state 1510 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 1511 observe2Greater1 observeIGreater1 + action 0 + 1799 : 1 +state 1512 + action 0 + 1681 : 0.833 + 1682 : 0.167 +state 1513 + action 0 + 1800 : 1 +state 1514 observe2Greater1 observeIGreater1 + action 0 + 1801 : 1 +state 1515 observe3Greater1 observeIGreater1 + action 0 + 1802 : 1 +state 1516 + action 0 + 1803 : 1 +state 1517 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 1518 + action 0 + 1809 : 1 +state 1519 + action 0 + 1683 : 0.833 + 1684 : 0.167 +state 1520 + action 0 + 1810 : 1 +state 1521 observe2Greater1 observeIGreater1 + action 0 + 1811 : 1 +state 1522 + action 0 + 1812 : 1 +state 1523 observe4Greater1 observeIGreater1 + action 0 + 1813 : 1 +state 1524 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 1525 + action 0 + 1819 : 1 +state 1526 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1527 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1528 observe0Greater1 observeOnlyTrueSender + action 0 + 1821 : 1 +state 1529 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1530 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1531 observe0Greater1 observeOnlyTrueSender + action 0 + 1822 : 1 +state 1532 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1533 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1534 observe0Greater1 observeOnlyTrueSender + action 0 + 1823 : 1 +state 1535 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1536 observe0Greater1 observeOnlyTrueSender + action 0 + 1019 : 0.2 + 1020 : 0.2 + 1021 : 0.2 + 1022 : 0.2 + 1023 : 0.2 +state 1537 observe0Greater1 observeOnlyTrueSender + action 0 + 1824 : 1 +state 1538 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 1 +state 1539 observe0Greater1 observeOnlyTrueSender + action 0 + 1825 : 0.833 + 1826 : 0.167 +state 1540 observe3Greater1 observeIGreater1 + action 0 + 1699 : 0.833 + 1700 : 0.167 +state 1541 observe3Greater1 observeIGreater1 + action 0 + 1827 : 1 +state 1542 observe3Greater1 observeIGreater1 + action 0 + 1828 : 1 +state 1543 observe3Greater1 observeIGreater1 + action 0 + 1829 : 1 +state 1544 observe3Greater1 observeIGreater1 + action 0 + 1830 : 1 +state 1545 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 1546 observe3Greater1 observeIGreater1 + action 0 + 1836 : 1 +state 1547 + action 0 + 1701 : 0.833 + 1702 : 0.167 +state 1548 + action 0 + 1837 : 1 +state 1549 + action 0 + 1838 : 1 +state 1550 observe3Greater1 observeIGreater1 + action 0 + 1839 : 1 +state 1551 observe4Greater1 observeIGreater1 + action 0 + 1840 : 1 +state 1552 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 1553 + action 0 + 1846 : 1 +state 1554 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1555 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1556 observe0Greater1 observeOnlyTrueSender + action 0 + 1848 : 1 +state 1557 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1558 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1559 observe0Greater1 observeOnlyTrueSender + action 0 + 1849 : 1 +state 1560 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1561 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1562 observe0Greater1 observeOnlyTrueSender + action 0 + 1850 : 1 +state 1563 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1564 observe0Greater1 observeOnlyTrueSender + action 0 + 1051 : 0.2 + 1052 : 0.2 + 1053 : 0.2 + 1054 : 0.2 + 1055 : 0.2 +state 1565 observe0Greater1 observeOnlyTrueSender + action 0 + 1851 : 1 +state 1566 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 1 +state 1567 observe0Greater1 observeOnlyTrueSender + action 0 + 1852 : 0.833 + 1853 : 0.167 +state 1568 observe4Greater1 observeIGreater1 + action 0 + 1717 : 0.833 + 1718 : 0.167 +state 1569 observe4Greater1 observeIGreater1 + action 0 + 1854 : 1 +state 1570 observe4Greater1 observeIGreater1 + action 0 + 1855 : 1 +state 1571 observe4Greater1 observeIGreater1 + action 0 + 1856 : 1 +state 1572 observe4Greater1 observeIGreater1 + action 0 + 1857 : 1 +state 1573 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 1574 observe4Greater1 observeIGreater1 + action 0 + 1863 : 1 +state 1575 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1576 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1577 observe0Greater1 observeOnlyTrueSender + action 0 + 1865 : 1 +state 1578 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1579 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1580 observe0Greater1 observeOnlyTrueSender + action 0 + 1866 : 1 +state 1581 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1582 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1583 observe0Greater1 observeOnlyTrueSender + action 0 + 1867 : 1 +state 1584 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1585 observe0Greater1 observeOnlyTrueSender + action 0 + 1072 : 0.2 + 1073 : 0.2 + 1074 : 0.2 + 1075 : 0.2 + 1076 : 0.2 +state 1586 observe0Greater1 observeOnlyTrueSender + action 0 + 1868 : 1 +state 1587 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 1 +state 1588 observe0Greater1 observeOnlyTrueSender + action 0 + 1869 : 0.833 + 1870 : 0.167 +state 1589 observe0Greater1 observeOnlyTrueSender + action 0 + 1083 : 0.833 + 1084 : 0.167 +state 1590 observe0Greater1 observeOnlyTrueSender + action 0 + 1871 : 1 +state 1591 observe0Greater1 observeOnlyTrueSender + action 0 + 1872 : 0.833 + 1873 : 0.167 +state 1592 observe0Greater1 observeOnlyTrueSender + action 0 + 1874 : 1 +state 1593 observe0Greater1 observeOnlyTrueSender + action 0 + 1875 : 0.833 + 1876 : 0.167 +state 1594 observe0Greater1 observeOnlyTrueSender + action 0 + 1877 : 1 +state 1595 observe0Greater1 observeOnlyTrueSender + action 0 + 1878 : 0.833 + 1879 : 0.167 +state 1596 observe0Greater1 observeOnlyTrueSender + action 0 + 1880 : 1 +state 1597 observe0Greater1 observeOnlyTrueSender + action 0 + 1881 : 0.833 + 1882 : 0.167 +state 1598 observe0Greater1 observeOnlyTrueSender + action 0 + 1883 : 1 +state 1599 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1599 : 1 +state 1600 + action 0 + 1884 : 0.833 + 1885 : 0.167 +state 1601 + action 0 + 1886 : 1 +state 1602 + action 0 + 1887 : 1 +state 1603 + action 0 + 1888 : 1 +state 1604 + action 0 + 1889 : 1 +state 1605 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 1606 + action 0 + 1895 : 1 +state 1607 + action 0 + 1896 : 1 +state 1608 + action 0 + 1897 : 0.833 + 1898 : 0.167 +state 1609 + action 0 + 1899 : 1 +state 1610 + action 0 + 1900 : 0.833 + 1901 : 0.167 +state 1611 + action 0 + 1902 : 1 +state 1612 + action 0 + 1903 : 0.833 + 1904 : 0.167 +state 1613 + action 0 + 1905 : 1 +state 1614 + action 0 + 1906 : 0.833 + 1907 : 0.167 +state 1615 + action 0 + 1908 : 1 +state 1616 + action 0 + 1909 : 1 +state 1617 + action 0 + 1910 : 1 +state 1618 + action 0 + 1911 : 0.833 + 1912 : 0.167 +state 1619 + action 0 + 1913 : 1 +state 1620 + action 0 + 1914 : 0.833 + 1915 : 0.167 +state 1621 + action 0 + 1916 : 1 +state 1622 + action 0 + 1917 : 0.833 + 1918 : 0.167 +state 1623 + action 0 + 1919 : 1 +state 1624 + action 0 + 1920 : 0.833 + 1921 : 0.167 +state 1625 + action 0 + 1922 : 1 +state 1626 + action 0 + 1923 : 1 +state 1627 + action 0 + 1924 : 1 +state 1628 + action 0 + 1925 : 0.833 + 1926 : 0.167 +state 1629 + action 0 + 1927 : 1 +state 1630 + action 0 + 1928 : 0.833 + 1929 : 0.167 +state 1631 + action 0 + 1930 : 1 +state 1632 + action 0 + 1931 : 0.833 + 1932 : 0.167 +state 1633 + action 0 + 1933 : 1 +state 1634 + action 0 + 1934 : 0.833 + 1935 : 0.167 +state 1635 + action 0 + 1936 : 1 +state 1636 + action 0 + 1937 : 1 +state 1637 + action 0 + 1938 : 1 +state 1638 + action 0 + 1939 : 0.833 + 1940 : 0.167 +state 1639 + action 0 + 1941 : 1 +state 1640 + action 0 + 1942 : 0.833 + 1943 : 0.167 +state 1641 + action 0 + 1944 : 1 +state 1642 + action 0 + 1945 : 0.833 + 1946 : 0.167 +state 1643 + action 0 + 1947 : 1 +state 1644 + action 0 + 1948 : 0.833 + 1949 : 0.167 +state 1645 + action 0 + 1950 : 1 +state 1646 + action 0 + 1951 : 1 +state 1647 + action 0 + 1909 : 1 +state 1648 + action 0 + 1923 : 1 +state 1649 + action 0 + 1937 : 1 +state 1650 + action 0 + 1951 : 1 +state 1651 observe0Greater1 observeOnlyTrueSender + action 0 + 1157 : 0.8 + 1952 : 0.2 +state 1652 observe0Greater1 observeOnlyTrueSender + action 0 + 1953 : 0.8 + 1954 : 0.2 +state 1653 observe0Greater1 observeOnlyTrueSender + action 0 + 1955 : 0.8 + 1956 : 0.2 +state 1654 observe0Greater1 observeOnlyTrueSender + action 0 + 1957 : 0.8 + 1958 : 0.2 +state 1655 observe0Greater1 observeOnlyTrueSender + action 0 + 1959 : 0.8 + 1960 : 0.2 +state 1656 observe0Greater1 observeOnlyTrueSender + action 0 + 1961 : 1 +state 1657 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 1658 observe1Greater1 observeIGreater1 + action 0 + 1967 : 1 +state 1659 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 1660 + action 0 + 1973 : 1 +state 1661 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 1662 + action 0 + 1979 : 1 +state 1663 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 1664 + action 0 + 1985 : 1 +state 1665 + action 0 + 1986 : 1 +state 1666 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1667 + action 0 + 1987 : 1 +state 1668 + action 0 + 1986 : 1 +state 1669 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1670 + action 0 + 1988 : 1 +state 1671 + action 0 + 1986 : 1 +state 1672 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1673 + action 0 + 1989 : 1 +state 1674 + action 0 + 1986 : 1 +state 1675 + action 0 + 1121 : 0.2 + 1122 : 0.2 + 1123 : 0.2 + 1124 : 0.2 + 1125 : 0.2 +state 1676 + action 0 + 1990 : 1 +state 1677 + action 0 + 1986 : 1 +state 1678 observe0Greater1 observeOnlyTrueSender + action 0 + 1991 : 0.833 + 1992 : 0.167 +state 1679 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 1680 observe2Greater1 observeIGreater1 + action 0 + 1998 : 1 +state 1681 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 1682 + action 0 + 2004 : 1 +state 1683 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 1684 + action 0 + 2010 : 1 +state 1685 + action 0 + 2011 : 1 +state 1686 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1687 + action 0 + 2012 : 1 +state 1688 + action 0 + 2011 : 1 +state 1689 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1690 + action 0 + 2013 : 1 +state 1691 + action 0 + 2011 : 1 +state 1692 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1693 + action 0 + 2014 : 1 +state 1694 + action 0 + 2011 : 1 +state 1695 + action 0 + 1131 : 0.2 + 1132 : 0.2 + 1133 : 0.2 + 1134 : 0.2 + 1135 : 0.2 +state 1696 + action 0 + 2015 : 1 +state 1697 + action 0 + 2011 : 1 +state 1698 observe0Greater1 observeOnlyTrueSender + action 0 + 2016 : 0.833 + 2017 : 0.167 +state 1699 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 1700 observe3Greater1 observeIGreater1 + action 0 + 2023 : 1 +state 1701 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 1702 + action 0 + 2029 : 1 +state 1703 + action 0 + 2030 : 1 +state 1704 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1705 + action 0 + 2031 : 1 +state 1706 + action 0 + 2030 : 1 +state 1707 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1708 + action 0 + 2032 : 1 +state 1709 + action 0 + 2030 : 1 +state 1710 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1711 + action 0 + 2033 : 1 +state 1712 + action 0 + 2030 : 1 +state 1713 + action 0 + 1141 : 0.2 + 1142 : 0.2 + 1143 : 0.2 + 1144 : 0.2 + 1145 : 0.2 +state 1714 + action 0 + 2034 : 1 +state 1715 + action 0 + 2030 : 1 +state 1716 observe0Greater1 observeOnlyTrueSender + action 0 + 2035 : 0.833 + 2036 : 0.167 +state 1717 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 1718 observe4Greater1 observeIGreater1 + action 0 + 2042 : 1 +state 1719 + action 0 + 2043 : 1 +state 1720 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1721 + action 0 + 2044 : 1 +state 1722 + action 0 + 2043 : 1 +state 1723 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1724 + action 0 + 2045 : 1 +state 1725 + action 0 + 2043 : 1 +state 1726 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1727 + action 0 + 2046 : 1 +state 1728 + action 0 + 2043 : 1 +state 1729 + action 0 + 1151 : 0.2 + 1152 : 0.2 + 1153 : 0.2 + 1154 : 0.2 + 1155 : 0.2 +state 1730 + action 0 + 2047 : 1 +state 1731 + action 0 + 2043 : 1 +state 1732 observe0Greater1 observeOnlyTrueSender + action 0 + 2048 : 0.833 + 2049 : 0.167 +state 1733 observe0Greater1 observeOnlyTrueSender + action 0 + 2050 : 1 +state 1734 observe0Greater1 observeOnlyTrueSender + action 0 + 2051 : 0.833 + 2052 : 0.167 +state 1735 observe0Greater1 observeOnlyTrueSender + action 0 + 2053 : 1 +state 1736 observe0Greater1 observeOnlyTrueSender + action 0 + 2054 : 0.833 + 2055 : 0.167 +state 1737 observe0Greater1 observeOnlyTrueSender + action 0 + 2056 : 1 +state 1738 observe0Greater1 observeOnlyTrueSender + action 0 + 2057 : 0.833 + 2058 : 0.167 +state 1739 observe0Greater1 observeOnlyTrueSender + action 0 + 2059 : 1 +state 1740 observe0Greater1 observeOnlyTrueSender + action 0 + 2060 : 0.833 + 2061 : 0.167 +state 1741 observe0Greater1 observeOnlyTrueSender + action 0 + 2062 : 1 +state 1742 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1742 : 1 +state 1743 observe1Greater1 observeIGreater1 + action 0 + 2063 : 1 +state 1744 observe1Greater1 observeIGreater1 + action 0 + 2064 : 1 +state 1745 observe1Greater1 observeIGreater1 + action 0 + 2065 : 1 +state 1746 observe1Greater1 observeIGreater1 + action 0 + 2066 : 1 +state 1747 observe1Greater1 observeIGreater1 + action 0 + 2067 : 0.8 + 2068 : 0.2 +state 1748 observe1Greater1 observeIGreater1 + action 0 + 2069 : 0.8 + 2070 : 0.2 +state 1749 observe1Greater1 observeIGreater1 + action 0 + 2071 : 0.8 + 2072 : 0.2 +state 1750 observe1Greater1 observeIGreater1 + action 0 + 2073 : 0.8 + 2074 : 0.2 +state 1751 observe1Greater1 observeIGreater1 + action 0 + 2075 : 0.8 + 2076 : 0.2 +state 1752 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2077 : 1 +state 1753 observe1Greater1 observeIGreater1 + action 0 + 2064 : 1 +state 1754 observe2Greater1 observeIGreater1 + action 0 + 2078 : 1 +state 1755 + action 0 + 2079 : 1 +state 1756 + action 0 + 2080 : 1 +state 1757 + action 0 + 2081 : 0.8 + 2082 : 0.2 +state 1758 + action 0 + 2083 : 0.8 + 2084 : 0.2 +state 1759 + action 0 + 2085 : 0.8 + 2086 : 0.2 +state 1760 + action 0 + 2087 : 0.8 + 2088 : 0.2 +state 1761 + action 0 + 2089 : 0.8 + 2090 : 0.2 +state 1762 observe0Greater1 observeOnlyTrueSender + action 0 + 2091 : 1 +state 1763 observe1Greater1 observeIGreater1 + action 0 + 2065 : 1 +state 1764 + action 0 + 2079 : 1 +state 1765 observe3Greater1 observeIGreater1 + action 0 + 2092 : 1 +state 1766 + action 0 + 2093 : 1 +state 1767 + action 0 + 2094 : 0.8 + 2095 : 0.2 +state 1768 + action 0 + 2096 : 0.8 + 2097 : 0.2 +state 1769 + action 0 + 2098 : 0.8 + 2099 : 0.2 +state 1770 + action 0 + 2100 : 0.8 + 2101 : 0.2 +state 1771 + action 0 + 2102 : 0.8 + 2103 : 0.2 +state 1772 observe0Greater1 observeOnlyTrueSender + action 0 + 2104 : 1 +state 1773 observe1Greater1 observeIGreater1 + action 0 + 2066 : 1 +state 1774 + action 0 + 2080 : 1 +state 1775 + action 0 + 2093 : 1 +state 1776 observe4Greater1 observeIGreater1 + action 0 + 2105 : 1 +state 1777 + action 0 + 2106 : 0.8 + 2107 : 0.2 +state 1778 + action 0 + 2108 : 0.8 + 2109 : 0.2 +state 1779 + action 0 + 2110 : 0.8 + 2111 : 0.2 +state 1780 + action 0 + 2112 : 0.8 + 2113 : 0.2 +state 1781 + action 0 + 2114 : 0.8 + 2115 : 0.2 +state 1782 observe0Greater1 observeOnlyTrueSender + action 0 + 2116 : 1 +state 1783 observe0Greater1 observeOnlyTrueSender + action 0 + 1991 : 0.833 + 1992 : 0.167 +state 1784 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2117 : 1 +state 1785 observe0Greater1 observeOnlyTrueSender + action 0 + 2118 : 1 +state 1786 observe0Greater1 observeOnlyTrueSender + action 0 + 2119 : 1 +state 1787 observe0Greater1 observeOnlyTrueSender + action 0 + 2120 : 1 +state 1788 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 1789 observe0Greater1 observeOnlyTrueSender + action 0 + 2126 : 1 +state 1790 observe2Greater1 observeIGreater1 + action 0 + 2078 : 1 +state 1791 observe2Greater1 observeIGreater1 + action 0 + 2127 : 1 +state 1792 observe2Greater1 observeIGreater1 + action 0 + 2128 : 1 +state 1793 observe2Greater1 observeIGreater1 + action 0 + 2129 : 1 +state 1794 observe2Greater1 observeIGreater1 + action 0 + 2130 : 0.8 + 2131 : 0.2 +state 1795 observe2Greater1 observeIGreater1 + action 0 + 2132 : 0.8 + 2133 : 0.2 +state 1796 observe2Greater1 observeIGreater1 + action 0 + 2134 : 0.8 + 2135 : 0.2 +state 1797 observe2Greater1 observeIGreater1 + action 0 + 2136 : 0.8 + 2137 : 0.2 +state 1798 observe2Greater1 observeIGreater1 + action 0 + 2138 : 0.8 + 2139 : 0.2 +state 1799 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2140 : 1 +state 1800 + action 0 + 2079 : 1 +state 1801 observe2Greater1 observeIGreater1 + action 0 + 2128 : 1 +state 1802 observe3Greater1 observeIGreater1 + action 0 + 2141 : 1 +state 1803 + action 0 + 2142 : 1 +state 1804 + action 0 + 2143 : 0.8 + 2144 : 0.2 +state 1805 + action 0 + 2145 : 0.8 + 2146 : 0.2 +state 1806 + action 0 + 2147 : 0.8 + 2148 : 0.2 +state 1807 + action 0 + 2149 : 0.8 + 2150 : 0.2 +state 1808 + action 0 + 2151 : 0.8 + 2152 : 0.2 +state 1809 observe0Greater1 observeOnlyTrueSender + action 0 + 2153 : 1 +state 1810 + action 0 + 2080 : 1 +state 1811 observe2Greater1 observeIGreater1 + action 0 + 2129 : 1 +state 1812 + action 0 + 2142 : 1 +state 1813 observe4Greater1 observeIGreater1 + action 0 + 2154 : 1 +state 1814 + action 0 + 2155 : 0.8 + 2156 : 0.2 +state 1815 + action 0 + 2157 : 0.8 + 2158 : 0.2 +state 1816 + action 0 + 2159 : 0.8 + 2160 : 0.2 +state 1817 + action 0 + 2161 : 0.8 + 2162 : 0.2 +state 1818 + action 0 + 2163 : 0.8 + 2164 : 0.2 +state 1819 observe0Greater1 observeOnlyTrueSender + action 0 + 2165 : 1 +state 1820 observe0Greater1 observeOnlyTrueSender + action 0 + 2016 : 0.833 + 2017 : 0.167 +state 1821 observe0Greater1 observeOnlyTrueSender + action 0 + 2166 : 1 +state 1822 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2167 : 1 +state 1823 observe0Greater1 observeOnlyTrueSender + action 0 + 2168 : 1 +state 1824 observe0Greater1 observeOnlyTrueSender + action 0 + 2169 : 1 +state 1825 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 1826 observe0Greater1 observeOnlyTrueSender + action 0 + 2175 : 1 +state 1827 observe3Greater1 observeIGreater1 + action 0 + 2092 : 1 +state 1828 observe3Greater1 observeIGreater1 + action 0 + 2141 : 1 +state 1829 observe3Greater1 observeIGreater1 + action 0 + 2176 : 1 +state 1830 observe3Greater1 observeIGreater1 + action 0 + 2177 : 1 +state 1831 observe3Greater1 observeIGreater1 + action 0 + 2178 : 0.8 + 2179 : 0.2 +state 1832 observe3Greater1 observeIGreater1 + action 0 + 2180 : 0.8 + 2181 : 0.2 +state 1833 observe3Greater1 observeIGreater1 + action 0 + 2182 : 0.8 + 2183 : 0.2 +state 1834 observe3Greater1 observeIGreater1 + action 0 + 2184 : 0.8 + 2185 : 0.2 +state 1835 observe3Greater1 observeIGreater1 + action 0 + 2186 : 0.8 + 2187 : 0.2 +state 1836 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2188 : 1 +state 1837 + action 0 + 2093 : 1 +state 1838 + action 0 + 2142 : 1 +state 1839 observe3Greater1 observeIGreater1 + action 0 + 2177 : 1 +state 1840 observe4Greater1 observeIGreater1 + action 0 + 2189 : 1 +state 1841 + action 0 + 2190 : 0.8 + 2191 : 0.2 +state 1842 + action 0 + 2192 : 0.8 + 2193 : 0.2 +state 1843 + action 0 + 2194 : 0.8 + 2195 : 0.2 +state 1844 + action 0 + 2196 : 0.8 + 2197 : 0.2 +state 1845 + action 0 + 2198 : 0.8 + 2199 : 0.2 +state 1846 observe0Greater1 observeOnlyTrueSender + action 0 + 2200 : 1 +state 1847 observe0Greater1 observeOnlyTrueSender + action 0 + 2035 : 0.833 + 2036 : 0.167 +state 1848 observe0Greater1 observeOnlyTrueSender + action 0 + 2201 : 1 +state 1849 observe0Greater1 observeOnlyTrueSender + action 0 + 2202 : 1 +state 1850 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2203 : 1 +state 1851 observe0Greater1 observeOnlyTrueSender + action 0 + 2204 : 1 +state 1852 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 1853 observe0Greater1 observeOnlyTrueSender + action 0 + 2210 : 1 +state 1854 observe4Greater1 observeIGreater1 + action 0 + 2105 : 1 +state 1855 observe4Greater1 observeIGreater1 + action 0 + 2154 : 1 +state 1856 observe4Greater1 observeIGreater1 + action 0 + 2189 : 1 +state 1857 observe4Greater1 observeIGreater1 + action 0 + 2211 : 1 +state 1858 observe4Greater1 observeIGreater1 + action 0 + 2212 : 0.8 + 2213 : 0.2 +state 1859 observe4Greater1 observeIGreater1 + action 0 + 2214 : 0.8 + 2215 : 0.2 +state 1860 observe4Greater1 observeIGreater1 + action 0 + 2216 : 0.8 + 2217 : 0.2 +state 1861 observe4Greater1 observeIGreater1 + action 0 + 2218 : 0.8 + 2219 : 0.2 +state 1862 observe4Greater1 observeIGreater1 + action 0 + 2220 : 0.8 + 2221 : 0.2 +state 1863 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2222 : 1 +state 1864 observe0Greater1 observeOnlyTrueSender + action 0 + 2048 : 0.833 + 2049 : 0.167 +state 1865 observe0Greater1 observeOnlyTrueSender + action 0 + 2223 : 1 +state 1866 observe0Greater1 observeOnlyTrueSender + action 0 + 2224 : 1 +state 1867 observe0Greater1 observeOnlyTrueSender + action 0 + 2225 : 1 +state 1868 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2226 : 1 +state 1869 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 1870 observe0Greater1 observeOnlyTrueSender + action 0 + 2232 : 1 +state 1871 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1871 : 1 +state 1872 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1873 observe0Greater1 observeOnlyTrueSender + action 0 + 2233 : 1 +state 1874 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1874 : 1 +state 1875 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1876 observe0Greater1 observeOnlyTrueSender + action 0 + 2234 : 1 +state 1877 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1877 : 1 +state 1878 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1879 observe0Greater1 observeOnlyTrueSender + action 0 + 2235 : 1 +state 1880 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1880 : 1 +state 1881 observe0Greater1 observeOnlyTrueSender + action 0 + 1352 : 0.2 + 1353 : 0.2 + 1354 : 0.2 + 1355 : 0.2 + 1356 : 0.2 +state 1882 observe0Greater1 observeOnlyTrueSender + action 0 + 2236 : 1 +state 1883 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1883 : 1 +state 1884 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 1885 + action 0 + 2242 : 1 +state 1886 + action 0 + 2243 : 1 +state 1887 + action 0 + 2244 : 1 +state 1888 + action 0 + 2245 : 1 +state 1889 + action 0 + 2246 : 1 +state 1890 + action 0 + 1396 : 0.8 + 2247 : 0.2 +state 1891 + action 0 + 2248 : 0.8 + 2249 : 0.2 +state 1892 + action 0 + 2250 : 0.8 + 2251 : 0.2 +state 1893 + action 0 + 2252 : 0.8 + 2253 : 0.2 +state 1894 + action 0 + 2254 : 0.8 + 2255 : 0.2 +state 1895 observe0Greater1 observeOnlyTrueSender + action 0 + 2256 : 1 +state 1896 + action 0 + 2257 : 1 +state 1897 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1898 + action 0 + 2258 : 1 +state 1899 + action 0 + 2257 : 1 +state 1900 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1901 + action 0 + 2259 : 1 +state 1902 + action 0 + 2257 : 1 +state 1903 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1904 + action 0 + 2260 : 1 +state 1905 + action 0 + 2257 : 1 +state 1906 + action 0 + 1372 : 0.2 + 1373 : 0.2 + 1374 : 0.2 + 1375 : 0.2 + 1376 : 0.2 +state 1907 + action 0 + 2261 : 1 +state 1908 + action 0 + 2257 : 1 +state 1909 + action 0 + 2262 : 0.833 + 2263 : 0.167 +state 1910 + action 0 + 2264 : 1 +state 1911 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1912 + action 0 + 2265 : 1 +state 1913 + action 0 + 2264 : 1 +state 1914 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1915 + action 0 + 2266 : 1 +state 1916 + action 0 + 2264 : 1 +state 1917 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1918 + action 0 + 2267 : 1 +state 1919 + action 0 + 2264 : 1 +state 1920 + action 0 + 1378 : 0.2 + 1379 : 0.2 + 1380 : 0.2 + 1381 : 0.2 + 1382 : 0.2 +state 1921 + action 0 + 2268 : 1 +state 1922 + action 0 + 2264 : 1 +state 1923 + action 0 + 2269 : 0.833 + 2270 : 0.167 +state 1924 + action 0 + 2271 : 1 +state 1925 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1926 + action 0 + 2272 : 1 +state 1927 + action 0 + 2271 : 1 +state 1928 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1929 + action 0 + 2273 : 1 +state 1930 + action 0 + 2271 : 1 +state 1931 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1932 + action 0 + 2274 : 1 +state 1933 + action 0 + 2271 : 1 +state 1934 + action 0 + 1384 : 0.2 + 1385 : 0.2 + 1386 : 0.2 + 1387 : 0.2 + 1388 : 0.2 +state 1935 + action 0 + 2275 : 1 +state 1936 + action 0 + 2271 : 1 +state 1937 + action 0 + 2276 : 0.833 + 2277 : 0.167 +state 1938 + action 0 + 2278 : 1 +state 1939 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1940 + action 0 + 2279 : 1 +state 1941 + action 0 + 2278 : 1 +state 1942 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1943 + action 0 + 2280 : 1 +state 1944 + action 0 + 2278 : 1 +state 1945 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1946 + action 0 + 2281 : 1 +state 1947 + action 0 + 2278 : 1 +state 1948 + action 0 + 1390 : 0.2 + 1391 : 0.2 + 1392 : 0.2 + 1393 : 0.2 + 1394 : 0.2 +state 1949 + action 0 + 2282 : 1 +state 1950 + action 0 + 2278 : 1 +state 1951 + action 0 + 2283 : 0.833 + 2284 : 0.167 +state 1952 observe0Greater1 observeOnlyTrueSender + action 0 + 2285 : 1 +state 1953 observe0Greater1 observeOnlyTrueSender + action 0 + 2286 : 0.833 + 2287 : 0.167 +state 1954 observe0Greater1 observeOnlyTrueSender + action 0 + 2288 : 1 +state 1955 observe0Greater1 observeOnlyTrueSender + action 0 + 2289 : 0.833 + 2290 : 0.167 +state 1956 observe0Greater1 observeOnlyTrueSender + action 0 + 2291 : 1 +state 1957 observe0Greater1 observeOnlyTrueSender + action 0 + 2292 : 0.833 + 2293 : 0.167 +state 1958 observe0Greater1 observeOnlyTrueSender + action 0 + 2294 : 1 +state 1959 observe0Greater1 observeOnlyTrueSender + action 0 + 2295 : 0.833 + 2296 : 0.167 +state 1960 observe0Greater1 observeOnlyTrueSender + action 0 + 2297 : 1 +state 1961 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 1961 : 1 +state 1962 observe1Greater1 observeIGreater1 + action 0 + 1463 : 0.8 + 2298 : 0.2 +state 1963 observe1Greater1 observeIGreater1 + action 0 + 2299 : 0.8 + 2300 : 0.2 +state 1964 observe1Greater1 observeIGreater1 + action 0 + 2301 : 0.8 + 2302 : 0.2 +state 1965 observe1Greater1 observeIGreater1 + action 0 + 2303 : 0.8 + 2304 : 0.2 +state 1966 observe1Greater1 observeIGreater1 + action 0 + 2305 : 0.8 + 2306 : 0.2 +state 1967 observe1Greater1 observeIGreater1 + action 0 + 2307 : 1 +state 1968 + action 0 + 1470 : 0.8 + 2308 : 0.2 +state 1969 + action 0 + 2309 : 0.8 + 2310 : 0.2 +state 1970 + action 0 + 2311 : 0.8 + 2312 : 0.2 +state 1971 + action 0 + 2313 : 0.8 + 2314 : 0.2 +state 1972 + action 0 + 2315 : 0.8 + 2316 : 0.2 +state 1973 + action 0 + 2317 : 1 +state 1974 + action 0 + 1477 : 0.8 + 2318 : 0.2 +state 1975 + action 0 + 2319 : 0.8 + 2320 : 0.2 +state 1976 + action 0 + 2321 : 0.8 + 2322 : 0.2 +state 1977 + action 0 + 2323 : 0.8 + 2324 : 0.2 +state 1978 + action 0 + 2325 : 0.8 + 2326 : 0.2 +state 1979 + action 0 + 2327 : 1 +state 1980 + action 0 + 1484 : 0.8 + 2328 : 0.2 +state 1981 + action 0 + 2329 : 0.8 + 2330 : 0.2 +state 1982 + action 0 + 2331 : 0.8 + 2332 : 0.2 +state 1983 + action 0 + 2333 : 0.8 + 2334 : 0.2 +state 1984 + action 0 + 2335 : 0.8 + 2336 : 0.2 +state 1985 + action 0 + 2337 : 1 +state 1986 + action 0 + 2262 : 0.833 + 2263 : 0.167 +state 1987 observe1Greater1 observeIGreater1 + action 0 + 2338 : 1 +state 1988 + action 0 + 2339 : 1 +state 1989 + action 0 + 2340 : 1 +state 1990 + action 0 + 2341 : 1 +state 1991 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 1992 observe0Greater1 observeOnlyTrueSender + action 0 + 2347 : 1 +state 1993 observe2Greater1 observeIGreater1 + action 0 + 1505 : 0.8 + 2348 : 0.2 +state 1994 observe2Greater1 observeIGreater1 + action 0 + 2349 : 0.8 + 2350 : 0.2 +state 1995 observe2Greater1 observeIGreater1 + action 0 + 2351 : 0.8 + 2352 : 0.2 +state 1996 observe2Greater1 observeIGreater1 + action 0 + 2353 : 0.8 + 2354 : 0.2 +state 1997 observe2Greater1 observeIGreater1 + action 0 + 2355 : 0.8 + 2356 : 0.2 +state 1998 observe2Greater1 observeIGreater1 + action 0 + 2357 : 1 +state 1999 + action 0 + 1512 : 0.8 + 2358 : 0.2 +state 2000 + action 0 + 2359 : 0.8 + 2360 : 0.2 +state 2001 + action 0 + 2361 : 0.8 + 2362 : 0.2 +state 2002 + action 0 + 2363 : 0.8 + 2364 : 0.2 +state 2003 + action 0 + 2365 : 0.8 + 2366 : 0.2 +state 2004 + action 0 + 2367 : 1 +state 2005 + action 0 + 1519 : 0.8 + 2368 : 0.2 +state 2006 + action 0 + 2369 : 0.8 + 2370 : 0.2 +state 2007 + action 0 + 2371 : 0.8 + 2372 : 0.2 +state 2008 + action 0 + 2373 : 0.8 + 2374 : 0.2 +state 2009 + action 0 + 2375 : 0.8 + 2376 : 0.2 +state 2010 + action 0 + 2377 : 1 +state 2011 + action 0 + 2269 : 0.833 + 2270 : 0.167 +state 2012 + action 0 + 2378 : 1 +state 2013 observe2Greater1 observeIGreater1 + action 0 + 2379 : 1 +state 2014 + action 0 + 2380 : 1 +state 2015 + action 0 + 2381 : 1 +state 2016 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 2017 observe0Greater1 observeOnlyTrueSender + action 0 + 2387 : 1 +state 2018 observe3Greater1 observeIGreater1 + action 0 + 1540 : 0.8 + 2388 : 0.2 +state 2019 observe3Greater1 observeIGreater1 + action 0 + 2389 : 0.8 + 2390 : 0.2 +state 2020 observe3Greater1 observeIGreater1 + action 0 + 2391 : 0.8 + 2392 : 0.2 +state 2021 observe3Greater1 observeIGreater1 + action 0 + 2393 : 0.8 + 2394 : 0.2 +state 2022 observe3Greater1 observeIGreater1 + action 0 + 2395 : 0.8 + 2396 : 0.2 +state 2023 observe3Greater1 observeIGreater1 + action 0 + 2397 : 1 +state 2024 + action 0 + 1547 : 0.8 + 2398 : 0.2 +state 2025 + action 0 + 2399 : 0.8 + 2400 : 0.2 +state 2026 + action 0 + 2401 : 0.8 + 2402 : 0.2 +state 2027 + action 0 + 2403 : 0.8 + 2404 : 0.2 +state 2028 + action 0 + 2405 : 0.8 + 2406 : 0.2 +state 2029 + action 0 + 2407 : 1 +state 2030 + action 0 + 2276 : 0.833 + 2277 : 0.167 +state 2031 + action 0 + 2408 : 1 +state 2032 + action 0 + 2409 : 1 +state 2033 observe3Greater1 observeIGreater1 + action 0 + 2410 : 1 +state 2034 + action 0 + 2411 : 1 +state 2035 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 2036 observe0Greater1 observeOnlyTrueSender + action 0 + 2417 : 1 +state 2037 observe4Greater1 observeIGreater1 + action 0 + 1568 : 0.8 + 2418 : 0.2 +state 2038 observe4Greater1 observeIGreater1 + action 0 + 2419 : 0.8 + 2420 : 0.2 +state 2039 observe4Greater1 observeIGreater1 + action 0 + 2421 : 0.8 + 2422 : 0.2 +state 2040 observe4Greater1 observeIGreater1 + action 0 + 2423 : 0.8 + 2424 : 0.2 +state 2041 observe4Greater1 observeIGreater1 + action 0 + 2425 : 0.8 + 2426 : 0.2 +state 2042 observe4Greater1 observeIGreater1 + action 0 + 2427 : 1 +state 2043 + action 0 + 2283 : 0.833 + 2284 : 0.167 +state 2044 + action 0 + 2428 : 1 +state 2045 + action 0 + 2429 : 1 +state 2046 + action 0 + 2430 : 1 +state 2047 observe4Greater1 observeIGreater1 + action 0 + 2431 : 1 +state 2048 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 2049 observe0Greater1 observeOnlyTrueSender + action 0 + 2437 : 1 +state 2050 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2050 : 1 +state 2051 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2052 observe0Greater1 observeOnlyTrueSender + action 0 + 2438 : 1 +state 2053 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2053 : 1 +state 2054 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2055 observe0Greater1 observeOnlyTrueSender + action 0 + 2439 : 1 +state 2056 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2056 : 1 +state 2057 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2058 observe0Greater1 observeOnlyTrueSender + action 0 + 2440 : 1 +state 2059 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2059 : 1 +state 2060 observe0Greater1 observeOnlyTrueSender + action 0 + 1457 : 0.2 + 1458 : 0.2 + 1459 : 0.2 + 1460 : 0.2 + 1461 : 0.2 +state 2061 observe0Greater1 observeOnlyTrueSender + action 0 + 2441 : 1 +state 2062 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2062 : 1 +state 2063 observe1Greater1 observeIGreater1 + action 0 + 2442 : 0.833 + 2443 : 0.167 +state 2064 observe1Greater1 observeIGreater1 + action 0 + 2444 : 0.833 + 2445 : 0.167 +state 2065 observe1Greater1 observeIGreater1 + action 0 + 2446 : 0.833 + 2447 : 0.167 +state 2066 observe1Greater1 observeIGreater1 + action 0 + 2448 : 0.833 + 2449 : 0.167 +state 2067 observe1Greater1 observeIGreater1 + action 0 + 1468 : 0.833 + 1469 : 0.167 +state 2068 observe1Greater1 observeIGreater1 + action 0 + 2450 : 1 +state 2069 observe1Greater1 observeIGreater1 + action 0 + 2451 : 0.833 + 2452 : 0.167 +state 2070 observe1Greater1 observeIGreater1 + action 0 + 2453 : 1 +state 2071 observe1Greater1 observeIGreater1 + action 0 + 2454 : 0.833 + 2455 : 0.167 +state 2072 observe1Greater1 observeIGreater1 + action 0 + 2456 : 1 +state 2073 observe1Greater1 observeIGreater1 + action 0 + 2457 : 0.833 + 2458 : 0.167 +state 2074 observe1Greater1 observeIGreater1 + action 0 + 2459 : 1 +state 2075 observe1Greater1 observeIGreater1 + action 0 + 2460 : 0.833 + 2461 : 0.167 +state 2076 observe1Greater1 observeIGreater1 + action 0 + 2462 : 1 +state 2077 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2463 : 1 +state 2078 observe2Greater1 observeIGreater1 + action 0 + 2464 : 0.833 + 2465 : 0.167 +state 2079 + action 0 + 2466 : 0.833 + 2467 : 0.167 +state 2080 + action 0 + 2468 : 0.833 + 2469 : 0.167 +state 2081 + action 0 + 1475 : 0.833 + 1476 : 0.167 +state 2082 + action 0 + 2470 : 1 +state 2083 + action 0 + 2471 : 0.833 + 2472 : 0.167 +state 2084 + action 0 + 2473 : 1 +state 2085 + action 0 + 2474 : 0.833 + 2475 : 0.167 +state 2086 + action 0 + 2476 : 1 +state 2087 + action 0 + 2477 : 0.833 + 2478 : 0.167 +state 2088 + action 0 + 2479 : 1 +state 2089 + action 0 + 2480 : 0.833 + 2481 : 0.167 +state 2090 + action 0 + 2482 : 1 +state 2091 observe0Greater1 observeOnlyTrueSender + action 0 + 2483 : 1 +state 2092 observe3Greater1 observeIGreater1 + action 0 + 2484 : 0.833 + 2485 : 0.167 +state 2093 + action 0 + 2486 : 0.833 + 2487 : 0.167 +state 2094 + action 0 + 1482 : 0.833 + 1483 : 0.167 +state 2095 + action 0 + 2488 : 1 +state 2096 + action 0 + 2489 : 0.833 + 2490 : 0.167 +state 2097 + action 0 + 2491 : 1 +state 2098 + action 0 + 2492 : 0.833 + 2493 : 0.167 +state 2099 + action 0 + 2494 : 1 +state 2100 + action 0 + 2495 : 0.833 + 2496 : 0.167 +state 2101 + action 0 + 2497 : 1 +state 2102 + action 0 + 2498 : 0.833 + 2499 : 0.167 +state 2103 + action 0 + 2500 : 1 +state 2104 observe0Greater1 observeOnlyTrueSender + action 0 + 2501 : 1 +state 2105 observe4Greater1 observeIGreater1 + action 0 + 2502 : 0.833 + 2503 : 0.167 +state 2106 + action 0 + 1489 : 0.833 + 1490 : 0.167 +state 2107 + action 0 + 2504 : 1 +state 2108 + action 0 + 2505 : 0.833 + 2506 : 0.167 +state 2109 + action 0 + 2507 : 1 +state 2110 + action 0 + 2508 : 0.833 + 2509 : 0.167 +state 2111 + action 0 + 2510 : 1 +state 2112 + action 0 + 2511 : 0.833 + 2512 : 0.167 +state 2113 + action 0 + 2513 : 1 +state 2114 + action 0 + 2514 : 0.833 + 2515 : 0.167 +state 2115 + action 0 + 2516 : 1 +state 2116 observe0Greater1 observeOnlyTrueSender + action 0 + 2517 : 1 +state 2117 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2463 : 1 +state 2118 observe0Greater1 observeOnlyTrueSender + action 0 + 2483 : 1 +state 2119 observe0Greater1 observeOnlyTrueSender + action 0 + 2501 : 1 +state 2120 observe0Greater1 observeOnlyTrueSender + action 0 + 2517 : 1 +state 2121 observe0Greater1 observeOnlyTrueSender + action 0 + 2518 : 0.8 + 2519 : 0.2 +state 2122 observe0Greater1 observeOnlyTrueSender + action 0 + 2520 : 0.8 + 2521 : 0.2 +state 2123 observe0Greater1 observeOnlyTrueSender + action 0 + 2522 : 0.8 + 2523 : 0.2 +state 2124 observe0Greater1 observeOnlyTrueSender + action 0 + 2524 : 0.8 + 2525 : 0.2 +state 2125 observe0Greater1 observeOnlyTrueSender + action 0 + 2526 : 0.8 + 2527 : 0.2 +state 2126 observe0Greater1 observeOnlyTrueSender + action 0 + 2528 : 1 +state 2127 observe2Greater1 observeIGreater1 + action 0 + 2529 : 0.833 + 2530 : 0.167 +state 2128 observe2Greater1 observeIGreater1 + action 0 + 2531 : 0.833 + 2532 : 0.167 +state 2129 observe2Greater1 observeIGreater1 + action 0 + 2533 : 0.833 + 2534 : 0.167 +state 2130 observe2Greater1 observeIGreater1 + action 0 + 1510 : 0.833 + 1511 : 0.167 +state 2131 observe2Greater1 observeIGreater1 + action 0 + 2535 : 1 +state 2132 observe2Greater1 observeIGreater1 + action 0 + 2536 : 0.833 + 2537 : 0.167 +state 2133 observe2Greater1 observeIGreater1 + action 0 + 2538 : 1 +state 2134 observe2Greater1 observeIGreater1 + action 0 + 2539 : 0.833 + 2540 : 0.167 +state 2135 observe2Greater1 observeIGreater1 + action 0 + 2541 : 1 +state 2136 observe2Greater1 observeIGreater1 + action 0 + 2542 : 0.833 + 2543 : 0.167 +state 2137 observe2Greater1 observeIGreater1 + action 0 + 2544 : 1 +state 2138 observe2Greater1 observeIGreater1 + action 0 + 2545 : 0.833 + 2546 : 0.167 +state 2139 observe2Greater1 observeIGreater1 + action 0 + 2547 : 1 +state 2140 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2548 : 1 +state 2141 observe3Greater1 observeIGreater1 + action 0 + 2549 : 0.833 + 2550 : 0.167 +state 2142 + action 0 + 2551 : 0.833 + 2552 : 0.167 +state 2143 + action 0 + 1517 : 0.833 + 1518 : 0.167 +state 2144 + action 0 + 2553 : 1 +state 2145 + action 0 + 2554 : 0.833 + 2555 : 0.167 +state 2146 + action 0 + 2556 : 1 +state 2147 + action 0 + 2557 : 0.833 + 2558 : 0.167 +state 2148 + action 0 + 2559 : 1 +state 2149 + action 0 + 2560 : 0.833 + 2561 : 0.167 +state 2150 + action 0 + 2562 : 1 +state 2151 + action 0 + 2563 : 0.833 + 2564 : 0.167 +state 2152 + action 0 + 2565 : 1 +state 2153 observe0Greater1 observeOnlyTrueSender + action 0 + 2566 : 1 +state 2154 observe4Greater1 observeIGreater1 + action 0 + 2567 : 0.833 + 2568 : 0.167 +state 2155 + action 0 + 1524 : 0.833 + 1525 : 0.167 +state 2156 + action 0 + 2569 : 1 +state 2157 + action 0 + 2570 : 0.833 + 2571 : 0.167 +state 2158 + action 0 + 2572 : 1 +state 2159 + action 0 + 2573 : 0.833 + 2574 : 0.167 +state 2160 + action 0 + 2575 : 1 +state 2161 + action 0 + 2576 : 0.833 + 2577 : 0.167 +state 2162 + action 0 + 2578 : 1 +state 2163 + action 0 + 2579 : 0.833 + 2580 : 0.167 +state 2164 + action 0 + 2581 : 1 +state 2165 observe0Greater1 observeOnlyTrueSender + action 0 + 2582 : 1 +state 2166 observe0Greater1 observeOnlyTrueSender + action 0 + 2483 : 1 +state 2167 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 2548 : 1 +state 2168 observe0Greater1 observeOnlyTrueSender + action 0 + 2566 : 1 +state 2169 observe0Greater1 observeOnlyTrueSender + action 0 + 2582 : 1 +state 2170 observe0Greater1 observeOnlyTrueSender + action 0 + 2583 : 0.8 + 2584 : 0.2 +state 2171 observe0Greater1 observeOnlyTrueSender + action 0 + 2585 : 0.8 + 2586 : 0.2 +state 2172 observe0Greater1 observeOnlyTrueSender + action 0 + 2587 : 0.8 + 2588 : 0.2 +state 2173 observe0Greater1 observeOnlyTrueSender + action 0 + 2589 : 0.8 + 2590 : 0.2 +state 2174 observe0Greater1 observeOnlyTrueSender + action 0 + 2591 : 0.8 + 2592 : 0.2 +state 2175 observe0Greater1 observeOnlyTrueSender + action 0 + 2593 : 1 +state 2176 observe3Greater1 observeIGreater1 + action 0 + 2594 : 0.833 + 2595 : 0.167 +state 2177 observe3Greater1 observeIGreater1 + action 0 + 2596 : 0.833 + 2597 : 0.167 +state 2178 observe3Greater1 observeIGreater1 + action 0 + 1545 : 0.833 + 1546 : 0.167 +state 2179 observe3Greater1 observeIGreater1 + action 0 + 2598 : 1 +state 2180 observe3Greater1 observeIGreater1 + action 0 + 2599 : 0.833 + 2600 : 0.167 +state 2181 observe3Greater1 observeIGreater1 + action 0 + 2601 : 1 +state 2182 observe3Greater1 observeIGreater1 + action 0 + 2602 : 0.833 + 2603 : 0.167 +state 2183 observe3Greater1 observeIGreater1 + action 0 + 2604 : 1 +state 2184 observe3Greater1 observeIGreater1 + action 0 + 2605 : 0.833 + 2606 : 0.167 +state 2185 observe3Greater1 observeIGreater1 + action 0 + 2607 : 1 +state 2186 observe3Greater1 observeIGreater1 + action 0 + 2608 : 0.833 + 2609 : 0.167 +state 2187 observe3Greater1 observeIGreater1 + action 0 + 2610 : 1 +state 2188 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2611 : 1 +state 2189 observe4Greater1 observeIGreater1 + action 0 + 2612 : 0.833 + 2613 : 0.167 +state 2190 + action 0 + 1552 : 0.833 + 1553 : 0.167 +state 2191 + action 0 + 2614 : 1 +state 2192 + action 0 + 2615 : 0.833 + 2616 : 0.167 +state 2193 + action 0 + 2617 : 1 +state 2194 + action 0 + 2618 : 0.833 + 2619 : 0.167 +state 2195 + action 0 + 2620 : 1 +state 2196 + action 0 + 2621 : 0.833 + 2622 : 0.167 +state 2197 + action 0 + 2623 : 1 +state 2198 + action 0 + 2624 : 0.833 + 2625 : 0.167 +state 2199 + action 0 + 2626 : 1 +state 2200 observe0Greater1 observeOnlyTrueSender + action 0 + 2627 : 1 +state 2201 observe0Greater1 observeOnlyTrueSender + action 0 + 2501 : 1 +state 2202 observe0Greater1 observeOnlyTrueSender + action 0 + 2566 : 1 +state 2203 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 2611 : 1 +state 2204 observe0Greater1 observeOnlyTrueSender + action 0 + 2627 : 1 +state 2205 observe0Greater1 observeOnlyTrueSender + action 0 + 2628 : 0.8 + 2629 : 0.2 +state 2206 observe0Greater1 observeOnlyTrueSender + action 0 + 2630 : 0.8 + 2631 : 0.2 +state 2207 observe0Greater1 observeOnlyTrueSender + action 0 + 2632 : 0.8 + 2633 : 0.2 +state 2208 observe0Greater1 observeOnlyTrueSender + action 0 + 2634 : 0.8 + 2635 : 0.2 +state 2209 observe0Greater1 observeOnlyTrueSender + action 0 + 2636 : 0.8 + 2637 : 0.2 +state 2210 observe0Greater1 observeOnlyTrueSender + action 0 + 2638 : 1 +state 2211 observe4Greater1 observeIGreater1 + action 0 + 2639 : 0.833 + 2640 : 0.167 +state 2212 observe4Greater1 observeIGreater1 + action 0 + 1573 : 0.833 + 1574 : 0.167 +state 2213 observe4Greater1 observeIGreater1 + action 0 + 2641 : 1 +state 2214 observe4Greater1 observeIGreater1 + action 0 + 2642 : 0.833 + 2643 : 0.167 +state 2215 observe4Greater1 observeIGreater1 + action 0 + 2644 : 1 +state 2216 observe4Greater1 observeIGreater1 + action 0 + 2645 : 0.833 + 2646 : 0.167 +state 2217 observe4Greater1 observeIGreater1 + action 0 + 2647 : 1 +state 2218 observe4Greater1 observeIGreater1 + action 0 + 2648 : 0.833 + 2649 : 0.167 +state 2219 observe4Greater1 observeIGreater1 + action 0 + 2650 : 1 +state 2220 observe4Greater1 observeIGreater1 + action 0 + 2651 : 0.833 + 2652 : 0.167 +state 2221 observe4Greater1 observeIGreater1 + action 0 + 2653 : 1 +state 2222 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2654 : 1 +state 2223 observe0Greater1 observeOnlyTrueSender + action 0 + 2517 : 1 +state 2224 observe0Greater1 observeOnlyTrueSender + action 0 + 2582 : 1 +state 2225 observe0Greater1 observeOnlyTrueSender + action 0 + 2627 : 1 +state 2226 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 2654 : 1 +state 2227 observe0Greater1 observeOnlyTrueSender + action 0 + 2655 : 0.8 + 2656 : 0.2 +state 2228 observe0Greater1 observeOnlyTrueSender + action 0 + 2657 : 0.8 + 2658 : 0.2 +state 2229 observe0Greater1 observeOnlyTrueSender + action 0 + 2659 : 0.8 + 2660 : 0.2 +state 2230 observe0Greater1 observeOnlyTrueSender + action 0 + 2661 : 0.8 + 2662 : 0.2 +state 2231 observe0Greater1 observeOnlyTrueSender + action 0 + 2663 : 0.8 + 2664 : 0.2 +state 2232 observe0Greater1 observeOnlyTrueSender + action 0 + 2665 : 1 +state 2233 observe0Greater1 observeOnlyTrueSender + action 0 + 2666 : 1 +state 2234 observe0Greater1 observeOnlyTrueSender + action 0 + 2667 : 1 +state 2235 observe0Greater1 observeOnlyTrueSender + action 0 + 2668 : 1 +state 2236 observe0Greater1 observeOnlyTrueSender + action 0 + 2669 : 1 +state 2237 + action 0 + 1600 : 0.8 + 2670 : 0.2 +state 2238 + action 0 + 2671 : 0.8 + 2672 : 0.2 +state 2239 + action 0 + 2673 : 0.8 + 2674 : 0.2 +state 2240 + action 0 + 2675 : 0.8 + 2676 : 0.2 +state 2241 + action 0 + 2677 : 0.8 + 2678 : 0.2 +state 2242 + action 0 + 2679 : 1 +state 2243 + action 0 + 2680 : 0.833 + 2681 : 0.167 +state 2244 + action 0 + 2682 : 0.833 + 2683 : 0.167 +state 2245 + action 0 + 2684 : 0.833 + 2685 : 0.167 +state 2246 + action 0 + 2686 : 0.833 + 2687 : 0.167 +state 2247 + action 0 + 2688 : 1 +state 2248 + action 0 + 2689 : 0.833 + 2690 : 0.167 +state 2249 + action 0 + 2691 : 1 +state 2250 + action 0 + 2692 : 0.833 + 2693 : 0.167 +state 2251 + action 0 + 2694 : 1 +state 2252 + action 0 + 2695 : 0.833 + 2696 : 0.167 +state 2253 + action 0 + 2697 : 1 +state 2254 + action 0 + 2698 : 0.833 + 2699 : 0.167 +state 2255 + action 0 + 2700 : 1 +state 2256 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2256 : 1 +state 2257 + action 0 + 2680 : 0.833 + 2681 : 0.167 +state 2258 observe1Greater1 observeIGreater1 + action 0 + 2701 : 1 +state 2259 + action 0 + 2702 : 1 +state 2260 + action 0 + 2703 : 1 +state 2261 + action 0 + 2704 : 1 +state 2262 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 2263 + action 0 + 2710 : 1 +state 2264 + action 0 + 2682 : 0.833 + 2683 : 0.167 +state 2265 + action 0 + 2711 : 1 +state 2266 observe2Greater1 observeIGreater1 + action 0 + 2712 : 1 +state 2267 + action 0 + 2713 : 1 +state 2268 + action 0 + 2714 : 1 +state 2269 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 2270 + action 0 + 2720 : 1 +state 2271 + action 0 + 2684 : 0.833 + 2685 : 0.167 +state 2272 + action 0 + 2721 : 1 +state 2273 + action 0 + 2722 : 1 +state 2274 observe3Greater1 observeIGreater1 + action 0 + 2723 : 1 +state 2275 + action 0 + 2724 : 1 +state 2276 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 2277 + action 0 + 2730 : 1 +state 2278 + action 0 + 2686 : 0.833 + 2687 : 0.167 +state 2279 + action 0 + 2731 : 1 +state 2280 + action 0 + 2732 : 1 +state 2281 + action 0 + 2733 : 1 +state 2282 observe4Greater1 observeIGreater1 + action 0 + 2734 : 1 +state 2283 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 2284 + action 0 + 2740 : 1 +state 2285 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2285 : 1 +state 2286 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2287 observe0Greater1 observeOnlyTrueSender + action 0 + 2741 : 1 +state 2288 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2288 : 1 +state 2289 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2290 observe0Greater1 observeOnlyTrueSender + action 0 + 2742 : 1 +state 2291 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2291 : 1 +state 2292 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2293 observe0Greater1 observeOnlyTrueSender + action 0 + 2743 : 1 +state 2294 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2294 : 1 +state 2295 observe0Greater1 observeOnlyTrueSender + action 0 + 1651 : 0.2 + 1652 : 0.2 + 1653 : 0.2 + 1654 : 0.2 + 1655 : 0.2 +state 2296 observe0Greater1 observeOnlyTrueSender + action 0 + 2744 : 1 +state 2297 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2297 : 1 +state 2298 observe1Greater1 observeIGreater1 + action 0 + 2745 : 1 +state 2299 observe1Greater1 observeIGreater1 + action 0 + 2746 : 0.833 + 2747 : 0.167 +state 2300 observe1Greater1 observeIGreater1 + action 0 + 2748 : 1 +state 2301 observe1Greater1 observeIGreater1 + action 0 + 2749 : 0.833 + 2750 : 0.167 +state 2302 observe1Greater1 observeIGreater1 + action 0 + 2751 : 1 +state 2303 observe1Greater1 observeIGreater1 + action 0 + 2752 : 0.833 + 2753 : 0.167 +state 2304 observe1Greater1 observeIGreater1 + action 0 + 2754 : 1 +state 2305 observe1Greater1 observeIGreater1 + action 0 + 2755 : 0.833 + 2756 : 0.167 +state 2306 observe1Greater1 observeIGreater1 + action 0 + 2757 : 1 +state 2307 observe1Greater1 observeIGreater1 + action 0 + 2758 : 1 +state 2308 + action 0 + 2759 : 1 +state 2309 + action 0 + 2760 : 0.833 + 2761 : 0.167 +state 2310 + action 0 + 2762 : 1 +state 2311 + action 0 + 2763 : 0.833 + 2764 : 0.167 +state 2312 + action 0 + 2765 : 1 +state 2313 + action 0 + 2766 : 0.833 + 2767 : 0.167 +state 2314 + action 0 + 2768 : 1 +state 2315 + action 0 + 2769 : 0.833 + 2770 : 0.167 +state 2316 + action 0 + 2771 : 1 +state 2317 + action 0 + 2772 : 1 +state 2318 + action 0 + 2773 : 1 +state 2319 + action 0 + 2774 : 0.833 + 2775 : 0.167 +state 2320 + action 0 + 2776 : 1 +state 2321 + action 0 + 2777 : 0.833 + 2778 : 0.167 +state 2322 + action 0 + 2779 : 1 +state 2323 + action 0 + 2780 : 0.833 + 2781 : 0.167 +state 2324 + action 0 + 2782 : 1 +state 2325 + action 0 + 2783 : 0.833 + 2784 : 0.167 +state 2326 + action 0 + 2785 : 1 +state 2327 + action 0 + 2786 : 1 +state 2328 + action 0 + 2787 : 1 +state 2329 + action 0 + 2788 : 0.833 + 2789 : 0.167 +state 2330 + action 0 + 2790 : 1 +state 2331 + action 0 + 2791 : 0.833 + 2792 : 0.167 +state 2332 + action 0 + 2793 : 1 +state 2333 + action 0 + 2794 : 0.833 + 2795 : 0.167 +state 2334 + action 0 + 2796 : 1 +state 2335 + action 0 + 2797 : 0.833 + 2798 : 0.167 +state 2336 + action 0 + 2799 : 1 +state 2337 + action 0 + 2800 : 1 +state 2338 observe1Greater1 observeIGreater1 + action 0 + 2758 : 1 +state 2339 + action 0 + 2772 : 1 +state 2340 + action 0 + 2786 : 1 +state 2341 + action 0 + 2800 : 1 +state 2342 observe0Greater1 observeOnlyTrueSender + action 0 + 1783 : 0.8 + 2801 : 0.2 +state 2343 observe0Greater1 observeOnlyTrueSender + action 0 + 2802 : 0.8 + 2803 : 0.2 +state 2344 observe0Greater1 observeOnlyTrueSender + action 0 + 2804 : 0.8 + 2805 : 0.2 +state 2345 observe0Greater1 observeOnlyTrueSender + action 0 + 2806 : 0.8 + 2807 : 0.2 +state 2346 observe0Greater1 observeOnlyTrueSender + action 0 + 2808 : 0.8 + 2809 : 0.2 +state 2347 observe0Greater1 observeOnlyTrueSender + action 0 + 2810 : 1 +state 2348 observe2Greater1 observeIGreater1 + action 0 + 2811 : 1 +state 2349 observe2Greater1 observeIGreater1 + action 0 + 2812 : 0.833 + 2813 : 0.167 +state 2350 observe2Greater1 observeIGreater1 + action 0 + 2814 : 1 +state 2351 observe2Greater1 observeIGreater1 + action 0 + 2815 : 0.833 + 2816 : 0.167 +state 2352 observe2Greater1 observeIGreater1 + action 0 + 2817 : 1 +state 2353 observe2Greater1 observeIGreater1 + action 0 + 2818 : 0.833 + 2819 : 0.167 +state 2354 observe2Greater1 observeIGreater1 + action 0 + 2820 : 1 +state 2355 observe2Greater1 observeIGreater1 + action 0 + 2821 : 0.833 + 2822 : 0.167 +state 2356 observe2Greater1 observeIGreater1 + action 0 + 2823 : 1 +state 2357 observe2Greater1 observeIGreater1 + action 0 + 2824 : 1 +state 2358 + action 0 + 2825 : 1 +state 2359 + action 0 + 2826 : 0.833 + 2827 : 0.167 +state 2360 + action 0 + 2828 : 1 +state 2361 + action 0 + 2829 : 0.833 + 2830 : 0.167 +state 2362 + action 0 + 2831 : 1 +state 2363 + action 0 + 2832 : 0.833 + 2833 : 0.167 +state 2364 + action 0 + 2834 : 1 +state 2365 + action 0 + 2835 : 0.833 + 2836 : 0.167 +state 2366 + action 0 + 2837 : 1 +state 2367 + action 0 + 2838 : 1 +state 2368 + action 0 + 2839 : 1 +state 2369 + action 0 + 2840 : 0.833 + 2841 : 0.167 +state 2370 + action 0 + 2842 : 1 +state 2371 + action 0 + 2843 : 0.833 + 2844 : 0.167 +state 2372 + action 0 + 2845 : 1 +state 2373 + action 0 + 2846 : 0.833 + 2847 : 0.167 +state 2374 + action 0 + 2848 : 1 +state 2375 + action 0 + 2849 : 0.833 + 2850 : 0.167 +state 2376 + action 0 + 2851 : 1 +state 2377 + action 0 + 2852 : 1 +state 2378 + action 0 + 2772 : 1 +state 2379 observe2Greater1 observeIGreater1 + action 0 + 2824 : 1 +state 2380 + action 0 + 2838 : 1 +state 2381 + action 0 + 2852 : 1 +state 2382 observe0Greater1 observeOnlyTrueSender + action 0 + 1820 : 0.8 + 2853 : 0.2 +state 2383 observe0Greater1 observeOnlyTrueSender + action 0 + 2854 : 0.8 + 2855 : 0.2 +state 2384 observe0Greater1 observeOnlyTrueSender + action 0 + 2856 : 0.8 + 2857 : 0.2 +state 2385 observe0Greater1 observeOnlyTrueSender + action 0 + 2858 : 0.8 + 2859 : 0.2 +state 2386 observe0Greater1 observeOnlyTrueSender + action 0 + 2860 : 0.8 + 2861 : 0.2 +state 2387 observe0Greater1 observeOnlyTrueSender + action 0 + 2862 : 1 +state 2388 observe3Greater1 observeIGreater1 + action 0 + 2863 : 1 +state 2389 observe3Greater1 observeIGreater1 + action 0 + 2864 : 0.833 + 2865 : 0.167 +state 2390 observe3Greater1 observeIGreater1 + action 0 + 2866 : 1 +state 2391 observe3Greater1 observeIGreater1 + action 0 + 2867 : 0.833 + 2868 : 0.167 +state 2392 observe3Greater1 observeIGreater1 + action 0 + 2869 : 1 +state 2393 observe3Greater1 observeIGreater1 + action 0 + 2870 : 0.833 + 2871 : 0.167 +state 2394 observe3Greater1 observeIGreater1 + action 0 + 2872 : 1 +state 2395 observe3Greater1 observeIGreater1 + action 0 + 2873 : 0.833 + 2874 : 0.167 +state 2396 observe3Greater1 observeIGreater1 + action 0 + 2875 : 1 +state 2397 observe3Greater1 observeIGreater1 + action 0 + 2876 : 1 +state 2398 + action 0 + 2877 : 1 +state 2399 + action 0 + 2878 : 0.833 + 2879 : 0.167 +state 2400 + action 0 + 2880 : 1 +state 2401 + action 0 + 2881 : 0.833 + 2882 : 0.167 +state 2402 + action 0 + 2883 : 1 +state 2403 + action 0 + 2884 : 0.833 + 2885 : 0.167 +state 2404 + action 0 + 2886 : 1 +state 2405 + action 0 + 2887 : 0.833 + 2888 : 0.167 +state 2406 + action 0 + 2889 : 1 +state 2407 + action 0 + 2890 : 1 +state 2408 + action 0 + 2786 : 1 +state 2409 + action 0 + 2838 : 1 +state 2410 observe3Greater1 observeIGreater1 + action 0 + 2876 : 1 +state 2411 + action 0 + 2890 : 1 +state 2412 observe0Greater1 observeOnlyTrueSender + action 0 + 1847 : 0.8 + 2891 : 0.2 +state 2413 observe0Greater1 observeOnlyTrueSender + action 0 + 2892 : 0.8 + 2893 : 0.2 +state 2414 observe0Greater1 observeOnlyTrueSender + action 0 + 2894 : 0.8 + 2895 : 0.2 +state 2415 observe0Greater1 observeOnlyTrueSender + action 0 + 2896 : 0.8 + 2897 : 0.2 +state 2416 observe0Greater1 observeOnlyTrueSender + action 0 + 2898 : 0.8 + 2899 : 0.2 +state 2417 observe0Greater1 observeOnlyTrueSender + action 0 + 2900 : 1 +state 2418 observe4Greater1 observeIGreater1 + action 0 + 2901 : 1 +state 2419 observe4Greater1 observeIGreater1 + action 0 + 2902 : 0.833 + 2903 : 0.167 +state 2420 observe4Greater1 observeIGreater1 + action 0 + 2904 : 1 +state 2421 observe4Greater1 observeIGreater1 + action 0 + 2905 : 0.833 + 2906 : 0.167 +state 2422 observe4Greater1 observeIGreater1 + action 0 + 2907 : 1 +state 2423 observe4Greater1 observeIGreater1 + action 0 + 2908 : 0.833 + 2909 : 0.167 +state 2424 observe4Greater1 observeIGreater1 + action 0 + 2910 : 1 +state 2425 observe4Greater1 observeIGreater1 + action 0 + 2911 : 0.833 + 2912 : 0.167 +state 2426 observe4Greater1 observeIGreater1 + action 0 + 2913 : 1 +state 2427 observe4Greater1 observeIGreater1 + action 0 + 2914 : 1 +state 2428 + action 0 + 2800 : 1 +state 2429 + action 0 + 2852 : 1 +state 2430 + action 0 + 2890 : 1 +state 2431 observe4Greater1 observeIGreater1 + action 0 + 2914 : 1 +state 2432 observe0Greater1 observeOnlyTrueSender + action 0 + 1864 : 0.8 + 2915 : 0.2 +state 2433 observe0Greater1 observeOnlyTrueSender + action 0 + 2916 : 0.8 + 2917 : 0.2 +state 2434 observe0Greater1 observeOnlyTrueSender + action 0 + 2918 : 0.8 + 2919 : 0.2 +state 2435 observe0Greater1 observeOnlyTrueSender + action 0 + 2920 : 0.8 + 2921 : 0.2 +state 2436 observe0Greater1 observeOnlyTrueSender + action 0 + 2922 : 0.8 + 2923 : 0.2 +state 2437 observe0Greater1 observeOnlyTrueSender + action 0 + 2924 : 1 +state 2438 observe0Greater1 observeOnlyTrueSender + action 0 + 2925 : 1 +state 2439 observe0Greater1 observeOnlyTrueSender + action 0 + 2926 : 1 +state 2440 observe0Greater1 observeOnlyTrueSender + action 0 + 2927 : 1 +state 2441 observe0Greater1 observeOnlyTrueSender + action 0 + 2928 : 1 +state 2442 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 2443 observe1Greater1 observeIGreater1 + action 0 + 2934 : 1 +state 2444 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 2445 observe1Greater1 observeIGreater1 + action 0 + 2940 : 1 +state 2446 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 2447 observe1Greater1 observeIGreater1 + action 0 + 2946 : 1 +state 2448 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 2449 observe1Greater1 observeIGreater1 + action 0 + 2952 : 1 +state 2450 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2451 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2452 observe1Greater1 observeIGreater1 + action 0 + 2954 : 1 +state 2453 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2454 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2455 observe1Greater1 observeIGreater1 + action 0 + 2955 : 1 +state 2456 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2457 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2458 observe1Greater1 observeIGreater1 + action 0 + 2956 : 1 +state 2459 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2460 observe1Greater1 observeIGreater1 + action 0 + 1747 : 0.2 + 1748 : 0.2 + 1749 : 0.2 + 1750 : 0.2 + 1751 : 0.2 +state 2461 observe1Greater1 observeIGreater1 + action 0 + 2957 : 1 +state 2462 observe1Greater1 observeIGreater1 + action 0 + 2953 : 1 +state 2463 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2958 : 0.833 + 2959 : 0.167 +state 2464 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 2465 observe2Greater1 observeIGreater1 + action 0 + 2965 : 1 +state 2466 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 2467 + action 0 + 2971 : 1 +state 2468 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 2469 + action 0 + 2977 : 1 +state 2470 + action 0 + 2978 : 1 +state 2471 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2472 + action 0 + 2979 : 1 +state 2473 + action 0 + 2978 : 1 +state 2474 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2475 + action 0 + 2980 : 1 +state 2476 + action 0 + 2978 : 1 +state 2477 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2478 + action 0 + 2981 : 1 +state 2479 + action 0 + 2978 : 1 +state 2480 + action 0 + 1757 : 0.2 + 1758 : 0.2 + 1759 : 0.2 + 1760 : 0.2 + 1761 : 0.2 +state 2481 + action 0 + 2982 : 1 +state 2482 + action 0 + 2978 : 1 +state 2483 observe0Greater1 observeOnlyTrueSender + action 0 + 2983 : 0.833 + 2984 : 0.167 +state 2484 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 2485 observe3Greater1 observeIGreater1 + action 0 + 2990 : 1 +state 2486 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 2487 + action 0 + 2996 : 1 +state 2488 + action 0 + 2997 : 1 +state 2489 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2490 + action 0 + 2998 : 1 +state 2491 + action 0 + 2997 : 1 +state 2492 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2493 + action 0 + 2999 : 1 +state 2494 + action 0 + 2997 : 1 +state 2495 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2496 + action 0 + 3000 : 1 +state 2497 + action 0 + 2997 : 1 +state 2498 + action 0 + 1767 : 0.2 + 1768 : 0.2 + 1769 : 0.2 + 1770 : 0.2 + 1771 : 0.2 +state 2499 + action 0 + 3001 : 1 +state 2500 + action 0 + 2997 : 1 +state 2501 observe0Greater1 observeOnlyTrueSender + action 0 + 3002 : 0.833 + 3003 : 0.167 +state 2502 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 2503 observe4Greater1 observeIGreater1 + action 0 + 3009 : 1 +state 2504 + action 0 + 3010 : 1 +state 2505 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2506 + action 0 + 3011 : 1 +state 2507 + action 0 + 3010 : 1 +state 2508 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2509 + action 0 + 3012 : 1 +state 2510 + action 0 + 3010 : 1 +state 2511 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2512 + action 0 + 3013 : 1 +state 2513 + action 0 + 3010 : 1 +state 2514 + action 0 + 1777 : 0.2 + 1778 : 0.2 + 1779 : 0.2 + 1780 : 0.2 + 1781 : 0.2 +state 2515 + action 0 + 3014 : 1 +state 2516 + action 0 + 3010 : 1 +state 2517 observe0Greater1 observeOnlyTrueSender + action 0 + 3015 : 0.833 + 3016 : 0.167 +state 2518 observe0Greater1 observeOnlyTrueSender + action 0 + 1788 : 0.833 + 1789 : 0.167 +state 2519 observe0Greater1 observeOnlyTrueSender + action 0 + 3017 : 1 +state 2520 observe0Greater1 observeOnlyTrueSender + action 0 + 3018 : 0.833 + 3019 : 0.167 +state 2521 observe0Greater1 observeOnlyTrueSender + action 0 + 3020 : 1 +state 2522 observe0Greater1 observeOnlyTrueSender + action 0 + 3021 : 0.833 + 3022 : 0.167 +state 2523 observe0Greater1 observeOnlyTrueSender + action 0 + 3023 : 1 +state 2524 observe0Greater1 observeOnlyTrueSender + action 0 + 3024 : 0.833 + 3025 : 0.167 +state 2525 observe0Greater1 observeOnlyTrueSender + action 0 + 3026 : 1 +state 2526 observe0Greater1 observeOnlyTrueSender + action 0 + 3027 : 0.833 + 3028 : 0.167 +state 2527 observe0Greater1 observeOnlyTrueSender + action 0 + 3029 : 1 +state 2528 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2528 : 1 +state 2529 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 2530 observe2Greater1 observeIGreater1 + action 0 + 3035 : 1 +state 2531 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 2532 observe2Greater1 observeIGreater1 + action 0 + 3041 : 1 +state 2533 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 2534 observe2Greater1 observeIGreater1 + action 0 + 3047 : 1 +state 2535 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2536 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2537 observe2Greater1 observeIGreater1 + action 0 + 3049 : 1 +state 2538 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2539 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2540 observe2Greater1 observeIGreater1 + action 0 + 3050 : 1 +state 2541 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2542 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2543 observe2Greater1 observeIGreater1 + action 0 + 3051 : 1 +state 2544 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2545 observe2Greater1 observeIGreater1 + action 0 + 1794 : 0.2 + 1795 : 0.2 + 1796 : 0.2 + 1797 : 0.2 + 1798 : 0.2 +state 2546 observe2Greater1 observeIGreater1 + action 0 + 3052 : 1 +state 2547 observe2Greater1 observeIGreater1 + action 0 + 3048 : 1 +state 2548 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3053 : 0.833 + 3054 : 0.167 +state 2549 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 2550 observe3Greater1 observeIGreater1 + action 0 + 3060 : 1 +state 2551 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 2552 + action 0 + 3066 : 1 +state 2553 + action 0 + 3067 : 1 +state 2554 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2555 + action 0 + 3068 : 1 +state 2556 + action 0 + 3067 : 1 +state 2557 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2558 + action 0 + 3069 : 1 +state 2559 + action 0 + 3067 : 1 +state 2560 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2561 + action 0 + 3070 : 1 +state 2562 + action 0 + 3067 : 1 +state 2563 + action 0 + 1804 : 0.2 + 1805 : 0.2 + 1806 : 0.2 + 1807 : 0.2 + 1808 : 0.2 +state 2564 + action 0 + 3071 : 1 +state 2565 + action 0 + 3067 : 1 +state 2566 observe0Greater1 observeOnlyTrueSender + action 0 + 3072 : 0.833 + 3073 : 0.167 +state 2567 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 2568 observe4Greater1 observeIGreater1 + action 0 + 3079 : 1 +state 2569 + action 0 + 3080 : 1 +state 2570 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2571 + action 0 + 3081 : 1 +state 2572 + action 0 + 3080 : 1 +state 2573 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2574 + action 0 + 3082 : 1 +state 2575 + action 0 + 3080 : 1 +state 2576 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2577 + action 0 + 3083 : 1 +state 2578 + action 0 + 3080 : 1 +state 2579 + action 0 + 1814 : 0.2 + 1815 : 0.2 + 1816 : 0.2 + 1817 : 0.2 + 1818 : 0.2 +state 2580 + action 0 + 3084 : 1 +state 2581 + action 0 + 3080 : 1 +state 2582 observe0Greater1 observeOnlyTrueSender + action 0 + 3085 : 0.833 + 3086 : 0.167 +state 2583 observe0Greater1 observeOnlyTrueSender + action 0 + 1825 : 0.833 + 1826 : 0.167 +state 2584 observe0Greater1 observeOnlyTrueSender + action 0 + 3087 : 1 +state 2585 observe0Greater1 observeOnlyTrueSender + action 0 + 3088 : 0.833 + 3089 : 0.167 +state 2586 observe0Greater1 observeOnlyTrueSender + action 0 + 3090 : 1 +state 2587 observe0Greater1 observeOnlyTrueSender + action 0 + 3091 : 0.833 + 3092 : 0.167 +state 2588 observe0Greater1 observeOnlyTrueSender + action 0 + 3093 : 1 +state 2589 observe0Greater1 observeOnlyTrueSender + action 0 + 3094 : 0.833 + 3095 : 0.167 +state 2590 observe0Greater1 observeOnlyTrueSender + action 0 + 3096 : 1 +state 2591 observe0Greater1 observeOnlyTrueSender + action 0 + 3097 : 0.833 + 3098 : 0.167 +state 2592 observe0Greater1 observeOnlyTrueSender + action 0 + 3099 : 1 +state 2593 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2593 : 1 +state 2594 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 2595 observe3Greater1 observeIGreater1 + action 0 + 3105 : 1 +state 2596 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 2597 observe3Greater1 observeIGreater1 + action 0 + 3111 : 1 +state 2598 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2599 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2600 observe3Greater1 observeIGreater1 + action 0 + 3113 : 1 +state 2601 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2602 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2603 observe3Greater1 observeIGreater1 + action 0 + 3114 : 1 +state 2604 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2605 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2606 observe3Greater1 observeIGreater1 + action 0 + 3115 : 1 +state 2607 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2608 observe3Greater1 observeIGreater1 + action 0 + 1831 : 0.2 + 1832 : 0.2 + 1833 : 0.2 + 1834 : 0.2 + 1835 : 0.2 +state 2609 observe3Greater1 observeIGreater1 + action 0 + 3116 : 1 +state 2610 observe3Greater1 observeIGreater1 + action 0 + 3112 : 1 +state 2611 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3117 : 0.833 + 3118 : 0.167 +state 2612 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 2613 observe4Greater1 observeIGreater1 + action 0 + 3124 : 1 +state 2614 + action 0 + 3125 : 1 +state 2615 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2616 + action 0 + 3126 : 1 +state 2617 + action 0 + 3125 : 1 +state 2618 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2619 + action 0 + 3127 : 1 +state 2620 + action 0 + 3125 : 1 +state 2621 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2622 + action 0 + 3128 : 1 +state 2623 + action 0 + 3125 : 1 +state 2624 + action 0 + 1841 : 0.2 + 1842 : 0.2 + 1843 : 0.2 + 1844 : 0.2 + 1845 : 0.2 +state 2625 + action 0 + 3129 : 1 +state 2626 + action 0 + 3125 : 1 +state 2627 observe0Greater1 observeOnlyTrueSender + action 0 + 3130 : 0.833 + 3131 : 0.167 +state 2628 observe0Greater1 observeOnlyTrueSender + action 0 + 1852 : 0.833 + 1853 : 0.167 +state 2629 observe0Greater1 observeOnlyTrueSender + action 0 + 3132 : 1 +state 2630 observe0Greater1 observeOnlyTrueSender + action 0 + 3133 : 0.833 + 3134 : 0.167 +state 2631 observe0Greater1 observeOnlyTrueSender + action 0 + 3135 : 1 +state 2632 observe0Greater1 observeOnlyTrueSender + action 0 + 3136 : 0.833 + 3137 : 0.167 +state 2633 observe0Greater1 observeOnlyTrueSender + action 0 + 3138 : 1 +state 2634 observe0Greater1 observeOnlyTrueSender + action 0 + 3139 : 0.833 + 3140 : 0.167 +state 2635 observe0Greater1 observeOnlyTrueSender + action 0 + 3141 : 1 +state 2636 observe0Greater1 observeOnlyTrueSender + action 0 + 3142 : 0.833 + 3143 : 0.167 +state 2637 observe0Greater1 observeOnlyTrueSender + action 0 + 3144 : 1 +state 2638 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2638 : 1 +state 2639 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 2640 observe4Greater1 observeIGreater1 + action 0 + 3150 : 1 +state 2641 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2642 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2643 observe4Greater1 observeIGreater1 + action 0 + 3152 : 1 +state 2644 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2645 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2646 observe4Greater1 observeIGreater1 + action 0 + 3153 : 1 +state 2647 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2648 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2649 observe4Greater1 observeIGreater1 + action 0 + 3154 : 1 +state 2650 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2651 observe4Greater1 observeIGreater1 + action 0 + 1858 : 0.2 + 1859 : 0.2 + 1860 : 0.2 + 1861 : 0.2 + 1862 : 0.2 +state 2652 observe4Greater1 observeIGreater1 + action 0 + 3155 : 1 +state 2653 observe4Greater1 observeIGreater1 + action 0 + 3151 : 1 +state 2654 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3156 : 0.833 + 3157 : 0.167 +state 2655 observe0Greater1 observeOnlyTrueSender + action 0 + 1869 : 0.833 + 1870 : 0.167 +state 2656 observe0Greater1 observeOnlyTrueSender + action 0 + 3158 : 1 +state 2657 observe0Greater1 observeOnlyTrueSender + action 0 + 3159 : 0.833 + 3160 : 0.167 +state 2658 observe0Greater1 observeOnlyTrueSender + action 0 + 3161 : 1 +state 2659 observe0Greater1 observeOnlyTrueSender + action 0 + 3162 : 0.833 + 3163 : 0.167 +state 2660 observe0Greater1 observeOnlyTrueSender + action 0 + 3164 : 1 +state 2661 observe0Greater1 observeOnlyTrueSender + action 0 + 3165 : 0.833 + 3166 : 0.167 +state 2662 observe0Greater1 observeOnlyTrueSender + action 0 + 3167 : 1 +state 2663 observe0Greater1 observeOnlyTrueSender + action 0 + 3168 : 0.833 + 3169 : 0.167 +state 2664 observe0Greater1 observeOnlyTrueSender + action 0 + 3170 : 1 +state 2665 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2665 : 1 +state 2666 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2666 : 1 +state 2667 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2667 : 1 +state 2668 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2668 : 1 +state 2669 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2669 : 1 +state 2670 + action 0 + 3171 : 1 +state 2671 + action 0 + 3172 : 0.833 + 3173 : 0.167 +state 2672 + action 0 + 3174 : 1 +state 2673 + action 0 + 3175 : 0.833 + 3176 : 0.167 +state 2674 + action 0 + 3177 : 1 +state 2675 + action 0 + 3178 : 0.833 + 3179 : 0.167 +state 2676 + action 0 + 3180 : 1 +state 2677 + action 0 + 3181 : 0.833 + 3182 : 0.167 +state 2678 + action 0 + 3183 : 1 +state 2679 deadlock + action 0 + 2679 : 1 +state 2680 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 2681 + action 0 + 3189 : 1 +state 2682 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 2683 + action 0 + 3195 : 1 +state 2684 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 2685 + action 0 + 3201 : 1 +state 2686 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 2687 + action 0 + 3207 : 1 +state 2688 deadlock + action 0 + 2688 : 1 +state 2689 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2690 + action 0 + 3208 : 1 +state 2691 deadlock + action 0 + 2691 : 1 +state 2692 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2693 + action 0 + 3209 : 1 +state 2694 deadlock + action 0 + 2694 : 1 +state 2695 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2696 + action 0 + 3210 : 1 +state 2697 deadlock + action 0 + 2697 : 1 +state 2698 + action 0 + 1890 : 0.2 + 1891 : 0.2 + 1892 : 0.2 + 1893 : 0.2 + 1894 : 0.2 +state 2699 + action 0 + 3211 : 1 +state 2700 deadlock + action 0 + 2700 : 1 +state 2701 observe1Greater1 observeIGreater1 + action 0 + 3212 : 1 +state 2702 + action 0 + 3213 : 1 +state 2703 + action 0 + 3214 : 1 +state 2704 + action 0 + 3215 : 1 +state 2705 + action 0 + 1986 : 0.8 + 3216 : 0.2 +state 2706 + action 0 + 3217 : 0.8 + 3218 : 0.2 +state 2707 + action 0 + 3219 : 0.8 + 3220 : 0.2 +state 2708 + action 0 + 3221 : 0.8 + 3222 : 0.2 +state 2709 + action 0 + 3223 : 0.8 + 3224 : 0.2 +state 2710 observe0Greater1 observeOnlyTrueSender + action 0 + 3225 : 1 +state 2711 + action 0 + 3213 : 1 +state 2712 observe2Greater1 observeIGreater1 + action 0 + 3226 : 1 +state 2713 + action 0 + 3227 : 1 +state 2714 + action 0 + 3228 : 1 +state 2715 + action 0 + 2011 : 0.8 + 3229 : 0.2 +state 2716 + action 0 + 3230 : 0.8 + 3231 : 0.2 +state 2717 + action 0 + 3232 : 0.8 + 3233 : 0.2 +state 2718 + action 0 + 3234 : 0.8 + 3235 : 0.2 +state 2719 + action 0 + 3236 : 0.8 + 3237 : 0.2 +state 2720 observe0Greater1 observeOnlyTrueSender + action 0 + 3238 : 1 +state 2721 + action 0 + 3214 : 1 +state 2722 + action 0 + 3227 : 1 +state 2723 observe3Greater1 observeIGreater1 + action 0 + 3239 : 1 +state 2724 + action 0 + 3240 : 1 +state 2725 + action 0 + 2030 : 0.8 + 3241 : 0.2 +state 2726 + action 0 + 3242 : 0.8 + 3243 : 0.2 +state 2727 + action 0 + 3244 : 0.8 + 3245 : 0.2 +state 2728 + action 0 + 3246 : 0.8 + 3247 : 0.2 +state 2729 + action 0 + 3248 : 0.8 + 3249 : 0.2 +state 2730 observe0Greater1 observeOnlyTrueSender + action 0 + 3250 : 1 +state 2731 + action 0 + 3215 : 1 +state 2732 + action 0 + 3228 : 1 +state 2733 + action 0 + 3240 : 1 +state 2734 observe4Greater1 observeIGreater1 + action 0 + 3251 : 1 +state 2735 + action 0 + 2043 : 0.8 + 3252 : 0.2 +state 2736 + action 0 + 3253 : 0.8 + 3254 : 0.2 +state 2737 + action 0 + 3255 : 0.8 + 3256 : 0.2 +state 2738 + action 0 + 3257 : 0.8 + 3258 : 0.2 +state 2739 + action 0 + 3259 : 0.8 + 3260 : 0.2 +state 2740 observe0Greater1 observeOnlyTrueSender + action 0 + 3261 : 1 +state 2741 observe0Greater1 observeOnlyTrueSender + action 0 + 3262 : 1 +state 2742 observe0Greater1 observeOnlyTrueSender + action 0 + 3263 : 1 +state 2743 observe0Greater1 observeOnlyTrueSender + action 0 + 3264 : 1 +state 2744 observe0Greater1 observeOnlyTrueSender + action 0 + 3265 : 1 +state 2745 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2746 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2747 observe1Greater1 observeIGreater1 + action 0 + 3267 : 1 +state 2748 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2749 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2750 observe1Greater1 observeIGreater1 + action 0 + 3268 : 1 +state 2751 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2752 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2753 observe1Greater1 observeIGreater1 + action 0 + 3269 : 1 +state 2754 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2755 observe1Greater1 observeIGreater1 + action 0 + 1962 : 0.2 + 1963 : 0.2 + 1964 : 0.2 + 1965 : 0.2 + 1966 : 0.2 +state 2756 observe1Greater1 observeIGreater1 + action 0 + 3270 : 1 +state 2757 observe1Greater1 observeIGreater1 + action 0 + 3266 : 1 +state 2758 observe1Greater1 observeIGreater1 + action 0 + 3271 : 0.833 + 3272 : 0.167 +state 2759 + action 0 + 3273 : 1 +state 2760 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2761 + action 0 + 3274 : 1 +state 2762 + action 0 + 3273 : 1 +state 2763 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2764 + action 0 + 3275 : 1 +state 2765 + action 0 + 3273 : 1 +state 2766 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2767 + action 0 + 3276 : 1 +state 2768 + action 0 + 3273 : 1 +state 2769 + action 0 + 1968 : 0.2 + 1969 : 0.2 + 1970 : 0.2 + 1971 : 0.2 + 1972 : 0.2 +state 2770 + action 0 + 3277 : 1 +state 2771 + action 0 + 3273 : 1 +state 2772 + action 0 + 3278 : 0.833 + 3279 : 0.167 +state 2773 + action 0 + 3280 : 1 +state 2774 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2775 + action 0 + 3281 : 1 +state 2776 + action 0 + 3280 : 1 +state 2777 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2778 + action 0 + 3282 : 1 +state 2779 + action 0 + 3280 : 1 +state 2780 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2781 + action 0 + 3283 : 1 +state 2782 + action 0 + 3280 : 1 +state 2783 + action 0 + 1974 : 0.2 + 1975 : 0.2 + 1976 : 0.2 + 1977 : 0.2 + 1978 : 0.2 +state 2784 + action 0 + 3284 : 1 +state 2785 + action 0 + 3280 : 1 +state 2786 + action 0 + 3285 : 0.833 + 3286 : 0.167 +state 2787 + action 0 + 3287 : 1 +state 2788 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2789 + action 0 + 3288 : 1 +state 2790 + action 0 + 3287 : 1 +state 2791 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2792 + action 0 + 3289 : 1 +state 2793 + action 0 + 3287 : 1 +state 2794 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2795 + action 0 + 3290 : 1 +state 2796 + action 0 + 3287 : 1 +state 2797 + action 0 + 1980 : 0.2 + 1981 : 0.2 + 1982 : 0.2 + 1983 : 0.2 + 1984 : 0.2 +state 2798 + action 0 + 3291 : 1 +state 2799 + action 0 + 3287 : 1 +state 2800 + action 0 + 3292 : 0.833 + 3293 : 0.167 +state 2801 observe0Greater1 observeOnlyTrueSender + action 0 + 3294 : 1 +state 2802 observe0Greater1 observeOnlyTrueSender + action 0 + 3295 : 0.833 + 3296 : 0.167 +state 2803 observe0Greater1 observeOnlyTrueSender + action 0 + 3297 : 1 +state 2804 observe0Greater1 observeOnlyTrueSender + action 0 + 3298 : 0.833 + 3299 : 0.167 +state 2805 observe0Greater1 observeOnlyTrueSender + action 0 + 3300 : 1 +state 2806 observe0Greater1 observeOnlyTrueSender + action 0 + 3301 : 0.833 + 3302 : 0.167 +state 2807 observe0Greater1 observeOnlyTrueSender + action 0 + 3303 : 1 +state 2808 observe0Greater1 observeOnlyTrueSender + action 0 + 3304 : 0.833 + 3305 : 0.167 +state 2809 observe0Greater1 observeOnlyTrueSender + action 0 + 3306 : 1 +state 2810 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2810 : 1 +state 2811 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2812 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2813 observe2Greater1 observeIGreater1 + action 0 + 3308 : 1 +state 2814 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2815 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2816 observe2Greater1 observeIGreater1 + action 0 + 3309 : 1 +state 2817 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2818 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2819 observe2Greater1 observeIGreater1 + action 0 + 3310 : 1 +state 2820 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2821 observe2Greater1 observeIGreater1 + action 0 + 1993 : 0.2 + 1994 : 0.2 + 1995 : 0.2 + 1996 : 0.2 + 1997 : 0.2 +state 2822 observe2Greater1 observeIGreater1 + action 0 + 3311 : 1 +state 2823 observe2Greater1 observeIGreater1 + action 0 + 3307 : 1 +state 2824 observe2Greater1 observeIGreater1 + action 0 + 3312 : 0.833 + 3313 : 0.167 +state 2825 + action 0 + 3314 : 1 +state 2826 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2827 + action 0 + 3315 : 1 +state 2828 + action 0 + 3314 : 1 +state 2829 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2830 + action 0 + 3316 : 1 +state 2831 + action 0 + 3314 : 1 +state 2832 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2833 + action 0 + 3317 : 1 +state 2834 + action 0 + 3314 : 1 +state 2835 + action 0 + 1999 : 0.2 + 2000 : 0.2 + 2001 : 0.2 + 2002 : 0.2 + 2003 : 0.2 +state 2836 + action 0 + 3318 : 1 +state 2837 + action 0 + 3314 : 1 +state 2838 + action 0 + 3319 : 0.833 + 3320 : 0.167 +state 2839 + action 0 + 3321 : 1 +state 2840 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2841 + action 0 + 3322 : 1 +state 2842 + action 0 + 3321 : 1 +state 2843 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2844 + action 0 + 3323 : 1 +state 2845 + action 0 + 3321 : 1 +state 2846 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2847 + action 0 + 3324 : 1 +state 2848 + action 0 + 3321 : 1 +state 2849 + action 0 + 2005 : 0.2 + 2006 : 0.2 + 2007 : 0.2 + 2008 : 0.2 + 2009 : 0.2 +state 2850 + action 0 + 3325 : 1 +state 2851 + action 0 + 3321 : 1 +state 2852 + action 0 + 3326 : 0.833 + 3327 : 0.167 +state 2853 observe0Greater1 observeOnlyTrueSender + action 0 + 3328 : 1 +state 2854 observe0Greater1 observeOnlyTrueSender + action 0 + 3329 : 0.833 + 3330 : 0.167 +state 2855 observe0Greater1 observeOnlyTrueSender + action 0 + 3331 : 1 +state 2856 observe0Greater1 observeOnlyTrueSender + action 0 + 3332 : 0.833 + 3333 : 0.167 +state 2857 observe0Greater1 observeOnlyTrueSender + action 0 + 3334 : 1 +state 2858 observe0Greater1 observeOnlyTrueSender + action 0 + 3335 : 0.833 + 3336 : 0.167 +state 2859 observe0Greater1 observeOnlyTrueSender + action 0 + 3337 : 1 +state 2860 observe0Greater1 observeOnlyTrueSender + action 0 + 3338 : 0.833 + 3339 : 0.167 +state 2861 observe0Greater1 observeOnlyTrueSender + action 0 + 3340 : 1 +state 2862 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2862 : 1 +state 2863 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2864 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2865 observe3Greater1 observeIGreater1 + action 0 + 3342 : 1 +state 2866 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2867 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2868 observe3Greater1 observeIGreater1 + action 0 + 3343 : 1 +state 2869 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2870 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2871 observe3Greater1 observeIGreater1 + action 0 + 3344 : 1 +state 2872 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2873 observe3Greater1 observeIGreater1 + action 0 + 2018 : 0.2 + 2019 : 0.2 + 2020 : 0.2 + 2021 : 0.2 + 2022 : 0.2 +state 2874 observe3Greater1 observeIGreater1 + action 0 + 3345 : 1 +state 2875 observe3Greater1 observeIGreater1 + action 0 + 3341 : 1 +state 2876 observe3Greater1 observeIGreater1 + action 0 + 3346 : 0.833 + 3347 : 0.167 +state 2877 + action 0 + 3348 : 1 +state 2878 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2879 + action 0 + 3349 : 1 +state 2880 + action 0 + 3348 : 1 +state 2881 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2882 + action 0 + 3350 : 1 +state 2883 + action 0 + 3348 : 1 +state 2884 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2885 + action 0 + 3351 : 1 +state 2886 + action 0 + 3348 : 1 +state 2887 + action 0 + 2024 : 0.2 + 2025 : 0.2 + 2026 : 0.2 + 2027 : 0.2 + 2028 : 0.2 +state 2888 + action 0 + 3352 : 1 +state 2889 + action 0 + 3348 : 1 +state 2890 + action 0 + 3353 : 0.833 + 3354 : 0.167 +state 2891 observe0Greater1 observeOnlyTrueSender + action 0 + 3355 : 1 +state 2892 observe0Greater1 observeOnlyTrueSender + action 0 + 3356 : 0.833 + 3357 : 0.167 +state 2893 observe0Greater1 observeOnlyTrueSender + action 0 + 3358 : 1 +state 2894 observe0Greater1 observeOnlyTrueSender + action 0 + 3359 : 0.833 + 3360 : 0.167 +state 2895 observe0Greater1 observeOnlyTrueSender + action 0 + 3361 : 1 +state 2896 observe0Greater1 observeOnlyTrueSender + action 0 + 3362 : 0.833 + 3363 : 0.167 +state 2897 observe0Greater1 observeOnlyTrueSender + action 0 + 3364 : 1 +state 2898 observe0Greater1 observeOnlyTrueSender + action 0 + 3365 : 0.833 + 3366 : 0.167 +state 2899 observe0Greater1 observeOnlyTrueSender + action 0 + 3367 : 1 +state 2900 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2900 : 1 +state 2901 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2902 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2903 observe4Greater1 observeIGreater1 + action 0 + 3369 : 1 +state 2904 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2905 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2906 observe4Greater1 observeIGreater1 + action 0 + 3370 : 1 +state 2907 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2908 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2909 observe4Greater1 observeIGreater1 + action 0 + 3371 : 1 +state 2910 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2911 observe4Greater1 observeIGreater1 + action 0 + 2037 : 0.2 + 2038 : 0.2 + 2039 : 0.2 + 2040 : 0.2 + 2041 : 0.2 +state 2912 observe4Greater1 observeIGreater1 + action 0 + 3372 : 1 +state 2913 observe4Greater1 observeIGreater1 + action 0 + 3368 : 1 +state 2914 observe4Greater1 observeIGreater1 + action 0 + 3373 : 0.833 + 3374 : 0.167 +state 2915 observe0Greater1 observeOnlyTrueSender + action 0 + 3375 : 1 +state 2916 observe0Greater1 observeOnlyTrueSender + action 0 + 3376 : 0.833 + 3377 : 0.167 +state 2917 observe0Greater1 observeOnlyTrueSender + action 0 + 3378 : 1 +state 2918 observe0Greater1 observeOnlyTrueSender + action 0 + 3379 : 0.833 + 3380 : 0.167 +state 2919 observe0Greater1 observeOnlyTrueSender + action 0 + 3381 : 1 +state 2920 observe0Greater1 observeOnlyTrueSender + action 0 + 3382 : 0.833 + 3383 : 0.167 +state 2921 observe0Greater1 observeOnlyTrueSender + action 0 + 3384 : 1 +state 2922 observe0Greater1 observeOnlyTrueSender + action 0 + 3385 : 0.833 + 3386 : 0.167 +state 2923 observe0Greater1 observeOnlyTrueSender + action 0 + 3387 : 1 +state 2924 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2924 : 1 +state 2925 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2925 : 1 +state 2926 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2926 : 1 +state 2927 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2927 : 1 +state 2928 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 2928 : 1 +state 2929 observe1Greater1 observeIGreater1 + action 0 + 3388 : 0.8 + 3389 : 0.2 +state 2930 observe1Greater1 observeIGreater1 + action 0 + 3390 : 0.8 + 3391 : 0.2 +state 2931 observe1Greater1 observeIGreater1 + action 0 + 3392 : 0.8 + 3393 : 0.2 +state 2932 observe1Greater1 observeIGreater1 + action 0 + 3394 : 0.8 + 3395 : 0.2 +state 2933 observe1Greater1 observeIGreater1 + action 0 + 3396 : 0.8 + 3397 : 0.2 +state 2934 observe1Greater1 observeIGreater1 + action 0 + 3398 : 1 +state 2935 observe1Greater1 observeIGreater1 + action 0 + 3399 : 0.8 + 3400 : 0.2 +state 2936 observe1Greater1 observeIGreater1 + action 0 + 3401 : 0.8 + 3402 : 0.2 +state 2937 observe1Greater1 observeIGreater1 + action 0 + 3403 : 0.8 + 3404 : 0.2 +state 2938 observe1Greater1 observeIGreater1 + action 0 + 3405 : 0.8 + 3406 : 0.2 +state 2939 observe1Greater1 observeIGreater1 + action 0 + 3407 : 0.8 + 3408 : 0.2 +state 2940 observe1Greater1 observeIGreater1 + action 0 + 3409 : 1 +state 2941 observe1Greater1 observeIGreater1 + action 0 + 3410 : 0.8 + 3411 : 0.2 +state 2942 observe1Greater1 observeIGreater1 + action 0 + 3412 : 0.8 + 3413 : 0.2 +state 2943 observe1Greater1 observeIGreater1 + action 0 + 3414 : 0.8 + 3415 : 0.2 +state 2944 observe1Greater1 observeIGreater1 + action 0 + 3416 : 0.8 + 3417 : 0.2 +state 2945 observe1Greater1 observeIGreater1 + action 0 + 3418 : 0.8 + 3419 : 0.2 +state 2946 observe1Greater1 observeIGreater1 + action 0 + 3420 : 1 +state 2947 observe1Greater1 observeIGreater1 + action 0 + 3421 : 0.8 + 3422 : 0.2 +state 2948 observe1Greater1 observeIGreater1 + action 0 + 3423 : 0.8 + 3424 : 0.2 +state 2949 observe1Greater1 observeIGreater1 + action 0 + 3425 : 0.8 + 3426 : 0.2 +state 2950 observe1Greater1 observeIGreater1 + action 0 + 3427 : 0.8 + 3428 : 0.2 +state 2951 observe1Greater1 observeIGreater1 + action 0 + 3429 : 0.8 + 3430 : 0.2 +state 2952 observe1Greater1 observeIGreater1 + action 0 + 3431 : 1 +state 2953 observe1Greater1 observeIGreater1 + action 0 + 3271 : 0.833 + 3272 : 0.167 +state 2954 observe1Greater1 observeIGreater1 + action 0 + 3432 : 1 +state 2955 observe1Greater1 observeIGreater1 + action 0 + 3433 : 1 +state 2956 observe1Greater1 observeIGreater1 + action 0 + 3434 : 1 +state 2957 observe1Greater1 observeIGreater1 + action 0 + 3435 : 1 +state 2958 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 2959 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3441 : 1 +state 2960 observe2Greater1 observeIGreater1 + action 0 + 3442 : 0.8 + 3443 : 0.2 +state 2961 observe2Greater1 observeIGreater1 + action 0 + 3444 : 0.8 + 3445 : 0.2 +state 2962 observe2Greater1 observeIGreater1 + action 0 + 3446 : 0.8 + 3447 : 0.2 +state 2963 observe2Greater1 observeIGreater1 + action 0 + 3448 : 0.8 + 3449 : 0.2 +state 2964 observe2Greater1 observeIGreater1 + action 0 + 3450 : 0.8 + 3451 : 0.2 +state 2965 observe2Greater1 observeIGreater1 + action 0 + 3452 : 1 +state 2966 + action 0 + 3453 : 0.8 + 3454 : 0.2 +state 2967 + action 0 + 3455 : 0.8 + 3456 : 0.2 +state 2968 + action 0 + 3457 : 0.8 + 3458 : 0.2 +state 2969 + action 0 + 3459 : 0.8 + 3460 : 0.2 +state 2970 + action 0 + 3461 : 0.8 + 3462 : 0.2 +state 2971 + action 0 + 3463 : 1 +state 2972 + action 0 + 3464 : 0.8 + 3465 : 0.2 +state 2973 + action 0 + 3466 : 0.8 + 3467 : 0.2 +state 2974 + action 0 + 3468 : 0.8 + 3469 : 0.2 +state 2975 + action 0 + 3470 : 0.8 + 3471 : 0.2 +state 2976 + action 0 + 3472 : 0.8 + 3473 : 0.2 +state 2977 + action 0 + 3474 : 1 +state 2978 + action 0 + 3278 : 0.833 + 3279 : 0.167 +state 2979 observe1Greater1 observeIGreater1 + action 0 + 3475 : 1 +state 2980 observe2Greater1 observeIGreater1 + action 0 + 3476 : 1 +state 2981 + action 0 + 3477 : 1 +state 2982 + action 0 + 3478 : 1 +state 2983 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 2984 observe0Greater1 observeOnlyTrueSender + action 0 + 3484 : 1 +state 2985 observe3Greater1 observeIGreater1 + action 0 + 3485 : 0.8 + 3486 : 0.2 +state 2986 observe3Greater1 observeIGreater1 + action 0 + 3487 : 0.8 + 3488 : 0.2 +state 2987 observe3Greater1 observeIGreater1 + action 0 + 3489 : 0.8 + 3490 : 0.2 +state 2988 observe3Greater1 observeIGreater1 + action 0 + 3491 : 0.8 + 3492 : 0.2 +state 2989 observe3Greater1 observeIGreater1 + action 0 + 3493 : 0.8 + 3494 : 0.2 +state 2990 observe3Greater1 observeIGreater1 + action 0 + 3495 : 1 +state 2991 + action 0 + 3496 : 0.8 + 3497 : 0.2 +state 2992 + action 0 + 3498 : 0.8 + 3499 : 0.2 +state 2993 + action 0 + 3500 : 0.8 + 3501 : 0.2 +state 2994 + action 0 + 3502 : 0.8 + 3503 : 0.2 +state 2995 + action 0 + 3504 : 0.8 + 3505 : 0.2 +state 2996 + action 0 + 3506 : 1 +state 2997 + action 0 + 3285 : 0.833 + 3286 : 0.167 +state 2998 observe1Greater1 observeIGreater1 + action 0 + 3507 : 1 +state 2999 + action 0 + 3508 : 1 +state 3000 observe3Greater1 observeIGreater1 + action 0 + 3509 : 1 +state 3001 + action 0 + 3510 : 1 +state 3002 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 3003 observe0Greater1 observeOnlyTrueSender + action 0 + 3516 : 1 +state 3004 observe4Greater1 observeIGreater1 + action 0 + 3517 : 0.8 + 3518 : 0.2 +state 3005 observe4Greater1 observeIGreater1 + action 0 + 3519 : 0.8 + 3520 : 0.2 +state 3006 observe4Greater1 observeIGreater1 + action 0 + 3521 : 0.8 + 3522 : 0.2 +state 3007 observe4Greater1 observeIGreater1 + action 0 + 3523 : 0.8 + 3524 : 0.2 +state 3008 observe4Greater1 observeIGreater1 + action 0 + 3525 : 0.8 + 3526 : 0.2 +state 3009 observe4Greater1 observeIGreater1 + action 0 + 3527 : 1 +state 3010 + action 0 + 3292 : 0.833 + 3293 : 0.167 +state 3011 observe1Greater1 observeIGreater1 + action 0 + 3528 : 1 +state 3012 + action 0 + 3529 : 1 +state 3013 + action 0 + 3530 : 1 +state 3014 observe4Greater1 observeIGreater1 + action 0 + 3531 : 1 +state 3015 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 3016 observe0Greater1 observeOnlyTrueSender + action 0 + 3537 : 1 +state 3017 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3017 : 1 +state 3018 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3019 observe0Greater1 observeOnlyTrueSender + action 0 + 3538 : 1 +state 3020 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3020 : 1 +state 3021 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3022 observe0Greater1 observeOnlyTrueSender + action 0 + 3539 : 1 +state 3023 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3023 : 1 +state 3024 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3025 observe0Greater1 observeOnlyTrueSender + action 0 + 3540 : 1 +state 3026 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3026 : 1 +state 3027 observe0Greater1 observeOnlyTrueSender + action 0 + 2121 : 0.2 + 2122 : 0.2 + 2123 : 0.2 + 2124 : 0.2 + 2125 : 0.2 +state 3028 observe0Greater1 observeOnlyTrueSender + action 0 + 3541 : 1 +state 3029 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3029 : 1 +state 3030 observe2Greater1 observeIGreater1 + action 0 + 3542 : 0.8 + 3543 : 0.2 +state 3031 observe2Greater1 observeIGreater1 + action 0 + 3544 : 0.8 + 3545 : 0.2 +state 3032 observe2Greater1 observeIGreater1 + action 0 + 3546 : 0.8 + 3547 : 0.2 +state 3033 observe2Greater1 observeIGreater1 + action 0 + 3548 : 0.8 + 3549 : 0.2 +state 3034 observe2Greater1 observeIGreater1 + action 0 + 3550 : 0.8 + 3551 : 0.2 +state 3035 observe2Greater1 observeIGreater1 + action 0 + 3552 : 1 +state 3036 observe2Greater1 observeIGreater1 + action 0 + 3553 : 0.8 + 3554 : 0.2 +state 3037 observe2Greater1 observeIGreater1 + action 0 + 3555 : 0.8 + 3556 : 0.2 +state 3038 observe2Greater1 observeIGreater1 + action 0 + 3557 : 0.8 + 3558 : 0.2 +state 3039 observe2Greater1 observeIGreater1 + action 0 + 3559 : 0.8 + 3560 : 0.2 +state 3040 observe2Greater1 observeIGreater1 + action 0 + 3561 : 0.8 + 3562 : 0.2 +state 3041 observe2Greater1 observeIGreater1 + action 0 + 3563 : 1 +state 3042 observe2Greater1 observeIGreater1 + action 0 + 3564 : 0.8 + 3565 : 0.2 +state 3043 observe2Greater1 observeIGreater1 + action 0 + 3566 : 0.8 + 3567 : 0.2 +state 3044 observe2Greater1 observeIGreater1 + action 0 + 3568 : 0.8 + 3569 : 0.2 +state 3045 observe2Greater1 observeIGreater1 + action 0 + 3570 : 0.8 + 3571 : 0.2 +state 3046 observe2Greater1 observeIGreater1 + action 0 + 3572 : 0.8 + 3573 : 0.2 +state 3047 observe2Greater1 observeIGreater1 + action 0 + 3574 : 1 +state 3048 observe2Greater1 observeIGreater1 + action 0 + 3312 : 0.833 + 3313 : 0.167 +state 3049 observe2Greater1 observeIGreater1 + action 0 + 3575 : 1 +state 3050 observe2Greater1 observeIGreater1 + action 0 + 3576 : 1 +state 3051 observe2Greater1 observeIGreater1 + action 0 + 3577 : 1 +state 3052 observe2Greater1 observeIGreater1 + action 0 + 3578 : 1 +state 3053 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 3054 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3584 : 1 +state 3055 observe3Greater1 observeIGreater1 + action 0 + 3585 : 0.8 + 3586 : 0.2 +state 3056 observe3Greater1 observeIGreater1 + action 0 + 3587 : 0.8 + 3588 : 0.2 +state 3057 observe3Greater1 observeIGreater1 + action 0 + 3589 : 0.8 + 3590 : 0.2 +state 3058 observe3Greater1 observeIGreater1 + action 0 + 3591 : 0.8 + 3592 : 0.2 +state 3059 observe3Greater1 observeIGreater1 + action 0 + 3593 : 0.8 + 3594 : 0.2 +state 3060 observe3Greater1 observeIGreater1 + action 0 + 3595 : 1 +state 3061 + action 0 + 3596 : 0.8 + 3597 : 0.2 +state 3062 + action 0 + 3598 : 0.8 + 3599 : 0.2 +state 3063 + action 0 + 3600 : 0.8 + 3601 : 0.2 +state 3064 + action 0 + 3602 : 0.8 + 3603 : 0.2 +state 3065 + action 0 + 3604 : 0.8 + 3605 : 0.2 +state 3066 + action 0 + 3606 : 1 +state 3067 + action 0 + 3319 : 0.833 + 3320 : 0.167 +state 3068 + action 0 + 3607 : 1 +state 3069 observe2Greater1 observeIGreater1 + action 0 + 3608 : 1 +state 3070 observe3Greater1 observeIGreater1 + action 0 + 3609 : 1 +state 3071 + action 0 + 3610 : 1 +state 3072 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 3073 observe0Greater1 observeOnlyTrueSender + action 0 + 3616 : 1 +state 3074 observe4Greater1 observeIGreater1 + action 0 + 3617 : 0.8 + 3618 : 0.2 +state 3075 observe4Greater1 observeIGreater1 + action 0 + 3619 : 0.8 + 3620 : 0.2 +state 3076 observe4Greater1 observeIGreater1 + action 0 + 3621 : 0.8 + 3622 : 0.2 +state 3077 observe4Greater1 observeIGreater1 + action 0 + 3623 : 0.8 + 3624 : 0.2 +state 3078 observe4Greater1 observeIGreater1 + action 0 + 3625 : 0.8 + 3626 : 0.2 +state 3079 observe4Greater1 observeIGreater1 + action 0 + 3627 : 1 +state 3080 + action 0 + 3326 : 0.833 + 3327 : 0.167 +state 3081 + action 0 + 3628 : 1 +state 3082 observe2Greater1 observeIGreater1 + action 0 + 3629 : 1 +state 3083 + action 0 + 3630 : 1 +state 3084 observe4Greater1 observeIGreater1 + action 0 + 3631 : 1 +state 3085 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 3086 observe0Greater1 observeOnlyTrueSender + action 0 + 3637 : 1 +state 3087 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3087 : 1 +state 3088 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3089 observe0Greater1 observeOnlyTrueSender + action 0 + 3638 : 1 +state 3090 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3090 : 1 +state 3091 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3092 observe0Greater1 observeOnlyTrueSender + action 0 + 3639 : 1 +state 3093 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3093 : 1 +state 3094 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3095 observe0Greater1 observeOnlyTrueSender + action 0 + 3640 : 1 +state 3096 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3096 : 1 +state 3097 observe0Greater1 observeOnlyTrueSender + action 0 + 2170 : 0.2 + 2171 : 0.2 + 2172 : 0.2 + 2173 : 0.2 + 2174 : 0.2 +state 3098 observe0Greater1 observeOnlyTrueSender + action 0 + 3641 : 1 +state 3099 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3099 : 1 +state 3100 observe3Greater1 observeIGreater1 + action 0 + 3642 : 0.8 + 3643 : 0.2 +state 3101 observe3Greater1 observeIGreater1 + action 0 + 3644 : 0.8 + 3645 : 0.2 +state 3102 observe3Greater1 observeIGreater1 + action 0 + 3646 : 0.8 + 3647 : 0.2 +state 3103 observe3Greater1 observeIGreater1 + action 0 + 3648 : 0.8 + 3649 : 0.2 +state 3104 observe3Greater1 observeIGreater1 + action 0 + 3650 : 0.8 + 3651 : 0.2 +state 3105 observe3Greater1 observeIGreater1 + action 0 + 3652 : 1 +state 3106 observe3Greater1 observeIGreater1 + action 0 + 3653 : 0.8 + 3654 : 0.2 +state 3107 observe3Greater1 observeIGreater1 + action 0 + 3655 : 0.8 + 3656 : 0.2 +state 3108 observe3Greater1 observeIGreater1 + action 0 + 3657 : 0.8 + 3658 : 0.2 +state 3109 observe3Greater1 observeIGreater1 + action 0 + 3659 : 0.8 + 3660 : 0.2 +state 3110 observe3Greater1 observeIGreater1 + action 0 + 3661 : 0.8 + 3662 : 0.2 +state 3111 observe3Greater1 observeIGreater1 + action 0 + 3663 : 1 +state 3112 observe3Greater1 observeIGreater1 + action 0 + 3346 : 0.833 + 3347 : 0.167 +state 3113 observe3Greater1 observeIGreater1 + action 0 + 3664 : 1 +state 3114 observe3Greater1 observeIGreater1 + action 0 + 3665 : 1 +state 3115 observe3Greater1 observeIGreater1 + action 0 + 3666 : 1 +state 3116 observe3Greater1 observeIGreater1 + action 0 + 3667 : 1 +state 3117 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 3118 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3673 : 1 +state 3119 observe4Greater1 observeIGreater1 + action 0 + 3674 : 0.8 + 3675 : 0.2 +state 3120 observe4Greater1 observeIGreater1 + action 0 + 3676 : 0.8 + 3677 : 0.2 +state 3121 observe4Greater1 observeIGreater1 + action 0 + 3678 : 0.8 + 3679 : 0.2 +state 3122 observe4Greater1 observeIGreater1 + action 0 + 3680 : 0.8 + 3681 : 0.2 +state 3123 observe4Greater1 observeIGreater1 + action 0 + 3682 : 0.8 + 3683 : 0.2 +state 3124 observe4Greater1 observeIGreater1 + action 0 + 3684 : 1 +state 3125 + action 0 + 3353 : 0.833 + 3354 : 0.167 +state 3126 + action 0 + 3685 : 1 +state 3127 + action 0 + 3686 : 1 +state 3128 observe3Greater1 observeIGreater1 + action 0 + 3687 : 1 +state 3129 observe4Greater1 observeIGreater1 + action 0 + 3688 : 1 +state 3130 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 3131 observe0Greater1 observeOnlyTrueSender + action 0 + 3694 : 1 +state 3132 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3132 : 1 +state 3133 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3134 observe0Greater1 observeOnlyTrueSender + action 0 + 3695 : 1 +state 3135 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3135 : 1 +state 3136 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3137 observe0Greater1 observeOnlyTrueSender + action 0 + 3696 : 1 +state 3138 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3138 : 1 +state 3139 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3140 observe0Greater1 observeOnlyTrueSender + action 0 + 3697 : 1 +state 3141 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3141 : 1 +state 3142 observe0Greater1 observeOnlyTrueSender + action 0 + 2205 : 0.2 + 2206 : 0.2 + 2207 : 0.2 + 2208 : 0.2 + 2209 : 0.2 +state 3143 observe0Greater1 observeOnlyTrueSender + action 0 + 3698 : 1 +state 3144 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3144 : 1 +state 3145 observe4Greater1 observeIGreater1 + action 0 + 3699 : 0.8 + 3700 : 0.2 +state 3146 observe4Greater1 observeIGreater1 + action 0 + 3701 : 0.8 + 3702 : 0.2 +state 3147 observe4Greater1 observeIGreater1 + action 0 + 3703 : 0.8 + 3704 : 0.2 +state 3148 observe4Greater1 observeIGreater1 + action 0 + 3705 : 0.8 + 3706 : 0.2 +state 3149 observe4Greater1 observeIGreater1 + action 0 + 3707 : 0.8 + 3708 : 0.2 +state 3150 observe4Greater1 observeIGreater1 + action 0 + 3709 : 1 +state 3151 observe4Greater1 observeIGreater1 + action 0 + 3373 : 0.833 + 3374 : 0.167 +state 3152 observe4Greater1 observeIGreater1 + action 0 + 3710 : 1 +state 3153 observe4Greater1 observeIGreater1 + action 0 + 3711 : 1 +state 3154 observe4Greater1 observeIGreater1 + action 0 + 3712 : 1 +state 3155 observe4Greater1 observeIGreater1 + action 0 + 3713 : 1 +state 3156 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 3157 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3719 : 1 +state 3158 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3158 : 1 +state 3159 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3160 observe0Greater1 observeOnlyTrueSender + action 0 + 3720 : 1 +state 3161 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3161 : 1 +state 3162 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3163 observe0Greater1 observeOnlyTrueSender + action 0 + 3721 : 1 +state 3164 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3164 : 1 +state 3165 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3166 observe0Greater1 observeOnlyTrueSender + action 0 + 3722 : 1 +state 3167 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3167 : 1 +state 3168 observe0Greater1 observeOnlyTrueSender + action 0 + 2227 : 0.2 + 2228 : 0.2 + 2229 : 0.2 + 2230 : 0.2 + 2231 : 0.2 +state 3169 observe0Greater1 observeOnlyTrueSender + action 0 + 3723 : 1 +state 3170 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3170 : 1 +state 3171 deadlock + action 0 + 3171 : 1 +state 3172 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3173 + action 0 + 3724 : 1 +state 3174 deadlock + action 0 + 3174 : 1 +state 3175 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3176 + action 0 + 3725 : 1 +state 3177 deadlock + action 0 + 3177 : 1 +state 3178 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3179 + action 0 + 3726 : 1 +state 3180 deadlock + action 0 + 3180 : 1 +state 3181 + action 0 + 2237 : 0.2 + 2238 : 0.2 + 2239 : 0.2 + 2240 : 0.2 + 2241 : 0.2 +state 3182 + action 0 + 3727 : 1 +state 3183 deadlock + action 0 + 3183 : 1 +state 3184 + action 0 + 2257 : 0.8 + 3728 : 0.2 +state 3185 + action 0 + 3729 : 0.8 + 3730 : 0.2 +state 3186 + action 0 + 3731 : 0.8 + 3732 : 0.2 +state 3187 + action 0 + 3733 : 0.8 + 3734 : 0.2 +state 3188 + action 0 + 3735 : 0.8 + 3736 : 0.2 +state 3189 + action 0 + 3737 : 1 +state 3190 + action 0 + 2264 : 0.8 + 3738 : 0.2 +state 3191 + action 0 + 3739 : 0.8 + 3740 : 0.2 +state 3192 + action 0 + 3741 : 0.8 + 3742 : 0.2 +state 3193 + action 0 + 3743 : 0.8 + 3744 : 0.2 +state 3194 + action 0 + 3745 : 0.8 + 3746 : 0.2 +state 3195 + action 0 + 3747 : 1 +state 3196 + action 0 + 2271 : 0.8 + 3748 : 0.2 +state 3197 + action 0 + 3749 : 0.8 + 3750 : 0.2 +state 3198 + action 0 + 3751 : 0.8 + 3752 : 0.2 +state 3199 + action 0 + 3753 : 0.8 + 3754 : 0.2 +state 3200 + action 0 + 3755 : 0.8 + 3756 : 0.2 +state 3201 + action 0 + 3757 : 1 +state 3202 + action 0 + 2278 : 0.8 + 3758 : 0.2 +state 3203 + action 0 + 3759 : 0.8 + 3760 : 0.2 +state 3204 + action 0 + 3761 : 0.8 + 3762 : 0.2 +state 3205 + action 0 + 3763 : 0.8 + 3764 : 0.2 +state 3206 + action 0 + 3765 : 0.8 + 3766 : 0.2 +state 3207 + action 0 + 3767 : 1 +state 3208 + action 0 + 3768 : 1 +state 3209 + action 0 + 3769 : 1 +state 3210 + action 0 + 3770 : 1 +state 3211 + action 0 + 3771 : 1 +state 3212 observe1Greater1 observeIGreater1 + action 0 + 3772 : 0.833 + 3773 : 0.167 +state 3213 + action 0 + 3774 : 0.833 + 3775 : 0.167 +state 3214 + action 0 + 3776 : 0.833 + 3777 : 0.167 +state 3215 + action 0 + 3778 : 0.833 + 3779 : 0.167 +state 3216 + action 0 + 3780 : 1 +state 3217 + action 0 + 3781 : 0.833 + 3782 : 0.167 +state 3218 + action 0 + 3783 : 1 +state 3219 + action 0 + 3784 : 0.833 + 3785 : 0.167 +state 3220 + action 0 + 3786 : 1 +state 3221 + action 0 + 3787 : 0.833 + 3788 : 0.167 +state 3222 + action 0 + 3789 : 1 +state 3223 + action 0 + 3790 : 0.833 + 3791 : 0.167 +state 3224 + action 0 + 3792 : 1 +state 3225 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3225 : 1 +state 3226 observe2Greater1 observeIGreater1 + action 0 + 3793 : 0.833 + 3794 : 0.167 +state 3227 + action 0 + 3795 : 0.833 + 3796 : 0.167 +state 3228 + action 0 + 3797 : 0.833 + 3798 : 0.167 +state 3229 + action 0 + 3799 : 1 +state 3230 + action 0 + 3800 : 0.833 + 3801 : 0.167 +state 3231 + action 0 + 3802 : 1 +state 3232 + action 0 + 3803 : 0.833 + 3804 : 0.167 +state 3233 + action 0 + 3805 : 1 +state 3234 + action 0 + 3806 : 0.833 + 3807 : 0.167 +state 3235 + action 0 + 3808 : 1 +state 3236 + action 0 + 3809 : 0.833 + 3810 : 0.167 +state 3237 + action 0 + 3811 : 1 +state 3238 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3238 : 1 +state 3239 observe3Greater1 observeIGreater1 + action 0 + 3812 : 0.833 + 3813 : 0.167 +state 3240 + action 0 + 3814 : 0.833 + 3815 : 0.167 +state 3241 + action 0 + 3816 : 1 +state 3242 + action 0 + 3817 : 0.833 + 3818 : 0.167 +state 3243 + action 0 + 3819 : 1 +state 3244 + action 0 + 3820 : 0.833 + 3821 : 0.167 +state 3245 + action 0 + 3822 : 1 +state 3246 + action 0 + 3823 : 0.833 + 3824 : 0.167 +state 3247 + action 0 + 3825 : 1 +state 3248 + action 0 + 3826 : 0.833 + 3827 : 0.167 +state 3249 + action 0 + 3828 : 1 +state 3250 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3250 : 1 +state 3251 observe4Greater1 observeIGreater1 + action 0 + 3829 : 0.833 + 3830 : 0.167 +state 3252 + action 0 + 3831 : 1 +state 3253 + action 0 + 3832 : 0.833 + 3833 : 0.167 +state 3254 + action 0 + 3834 : 1 +state 3255 + action 0 + 3835 : 0.833 + 3836 : 0.167 +state 3256 + action 0 + 3837 : 1 +state 3257 + action 0 + 3838 : 0.833 + 3839 : 0.167 +state 3258 + action 0 + 3840 : 1 +state 3259 + action 0 + 3841 : 0.833 + 3842 : 0.167 +state 3260 + action 0 + 3843 : 1 +state 3261 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3261 : 1 +state 3262 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3262 : 1 +state 3263 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3263 : 1 +state 3264 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3264 : 1 +state 3265 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3265 : 1 +state 3266 observe1Greater1 observeIGreater1 + action 0 + 3772 : 0.833 + 3773 : 0.167 +state 3267 observe1Greater1 observeIGreater1 + action 0 + 3844 : 1 +state 3268 observe1Greater1 observeIGreater1 + action 0 + 3845 : 1 +state 3269 observe1Greater1 observeIGreater1 + action 0 + 3846 : 1 +state 3270 observe1Greater1 observeIGreater1 + action 0 + 3847 : 1 +state 3271 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 3272 observe1Greater1 observeIGreater1 + action 0 + 3853 : 1 +state 3273 + action 0 + 3774 : 0.833 + 3775 : 0.167 +state 3274 observe1Greater1 observeIGreater1 + action 0 + 3854 : 1 +state 3275 observe2Greater1 observeIGreater1 + action 0 + 3855 : 1 +state 3276 + action 0 + 3856 : 1 +state 3277 + action 0 + 3857 : 1 +state 3278 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 3279 + action 0 + 3863 : 1 +state 3280 + action 0 + 3776 : 0.833 + 3777 : 0.167 +state 3281 observe1Greater1 observeIGreater1 + action 0 + 3864 : 1 +state 3282 + action 0 + 3865 : 1 +state 3283 observe3Greater1 observeIGreater1 + action 0 + 3866 : 1 +state 3284 + action 0 + 3867 : 1 +state 3285 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 3286 + action 0 + 3873 : 1 +state 3287 + action 0 + 3778 : 0.833 + 3779 : 0.167 +state 3288 observe1Greater1 observeIGreater1 + action 0 + 3874 : 1 +state 3289 + action 0 + 3875 : 1 +state 3290 + action 0 + 3876 : 1 +state 3291 observe4Greater1 observeIGreater1 + action 0 + 3877 : 1 +state 3292 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 3293 + action 0 + 3883 : 1 +state 3294 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3294 : 1 +state 3295 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3296 observe0Greater1 observeOnlyTrueSender + action 0 + 3884 : 1 +state 3297 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3297 : 1 +state 3298 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3299 observe0Greater1 observeOnlyTrueSender + action 0 + 3885 : 1 +state 3300 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3300 : 1 +state 3301 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3302 observe0Greater1 observeOnlyTrueSender + action 0 + 3886 : 1 +state 3303 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3303 : 1 +state 3304 observe0Greater1 observeOnlyTrueSender + action 0 + 2342 : 0.2 + 2343 : 0.2 + 2344 : 0.2 + 2345 : 0.2 + 2346 : 0.2 +state 3305 observe0Greater1 observeOnlyTrueSender + action 0 + 3887 : 1 +state 3306 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3306 : 1 +state 3307 observe2Greater1 observeIGreater1 + action 0 + 3793 : 0.833 + 3794 : 0.167 +state 3308 observe2Greater1 observeIGreater1 + action 0 + 3888 : 1 +state 3309 observe2Greater1 observeIGreater1 + action 0 + 3889 : 1 +state 3310 observe2Greater1 observeIGreater1 + action 0 + 3890 : 1 +state 3311 observe2Greater1 observeIGreater1 + action 0 + 3891 : 1 +state 3312 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 3313 observe2Greater1 observeIGreater1 + action 0 + 3897 : 1 +state 3314 + action 0 + 3795 : 0.833 + 3796 : 0.167 +state 3315 + action 0 + 3898 : 1 +state 3316 observe2Greater1 observeIGreater1 + action 0 + 3899 : 1 +state 3317 observe3Greater1 observeIGreater1 + action 0 + 3900 : 1 +state 3318 + action 0 + 3901 : 1 +state 3319 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 3320 + action 0 + 3907 : 1 +state 3321 + action 0 + 3797 : 0.833 + 3798 : 0.167 +state 3322 + action 0 + 3908 : 1 +state 3323 observe2Greater1 observeIGreater1 + action 0 + 3909 : 1 +state 3324 + action 0 + 3910 : 1 +state 3325 observe4Greater1 observeIGreater1 + action 0 + 3911 : 1 +state 3326 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 3327 + action 0 + 3917 : 1 +state 3328 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3328 : 1 +state 3329 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3330 observe0Greater1 observeOnlyTrueSender + action 0 + 3918 : 1 +state 3331 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3331 : 1 +state 3332 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3333 observe0Greater1 observeOnlyTrueSender + action 0 + 3919 : 1 +state 3334 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3334 : 1 +state 3335 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3336 observe0Greater1 observeOnlyTrueSender + action 0 + 3920 : 1 +state 3337 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3337 : 1 +state 3338 observe0Greater1 observeOnlyTrueSender + action 0 + 2382 : 0.2 + 2383 : 0.2 + 2384 : 0.2 + 2385 : 0.2 + 2386 : 0.2 +state 3339 observe0Greater1 observeOnlyTrueSender + action 0 + 3921 : 1 +state 3340 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3340 : 1 +state 3341 observe3Greater1 observeIGreater1 + action 0 + 3812 : 0.833 + 3813 : 0.167 +state 3342 observe3Greater1 observeIGreater1 + action 0 + 3922 : 1 +state 3343 observe3Greater1 observeIGreater1 + action 0 + 3923 : 1 +state 3344 observe3Greater1 observeIGreater1 + action 0 + 3924 : 1 +state 3345 observe3Greater1 observeIGreater1 + action 0 + 3925 : 1 +state 3346 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 3347 observe3Greater1 observeIGreater1 + action 0 + 3931 : 1 +state 3348 + action 0 + 3814 : 0.833 + 3815 : 0.167 +state 3349 + action 0 + 3932 : 1 +state 3350 + action 0 + 3933 : 1 +state 3351 observe3Greater1 observeIGreater1 + action 0 + 3934 : 1 +state 3352 observe4Greater1 observeIGreater1 + action 0 + 3935 : 1 +state 3353 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 3354 + action 0 + 3941 : 1 +state 3355 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3355 : 1 +state 3356 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3357 observe0Greater1 observeOnlyTrueSender + action 0 + 3942 : 1 +state 3358 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3358 : 1 +state 3359 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3360 observe0Greater1 observeOnlyTrueSender + action 0 + 3943 : 1 +state 3361 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3361 : 1 +state 3362 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3363 observe0Greater1 observeOnlyTrueSender + action 0 + 3944 : 1 +state 3364 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3364 : 1 +state 3365 observe0Greater1 observeOnlyTrueSender + action 0 + 2412 : 0.2 + 2413 : 0.2 + 2414 : 0.2 + 2415 : 0.2 + 2416 : 0.2 +state 3366 observe0Greater1 observeOnlyTrueSender + action 0 + 3945 : 1 +state 3367 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3367 : 1 +state 3368 observe4Greater1 observeIGreater1 + action 0 + 3829 : 0.833 + 3830 : 0.167 +state 3369 observe4Greater1 observeIGreater1 + action 0 + 3946 : 1 +state 3370 observe4Greater1 observeIGreater1 + action 0 + 3947 : 1 +state 3371 observe4Greater1 observeIGreater1 + action 0 + 3948 : 1 +state 3372 observe4Greater1 observeIGreater1 + action 0 + 3949 : 1 +state 3373 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 3374 observe4Greater1 observeIGreater1 + action 0 + 3955 : 1 +state 3375 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3375 : 1 +state 3376 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3377 observe0Greater1 observeOnlyTrueSender + action 0 + 3956 : 1 +state 3378 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3378 : 1 +state 3379 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3380 observe0Greater1 observeOnlyTrueSender + action 0 + 3957 : 1 +state 3381 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3381 : 1 +state 3382 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3383 observe0Greater1 observeOnlyTrueSender + action 0 + 3958 : 1 +state 3384 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3384 : 1 +state 3385 observe0Greater1 observeOnlyTrueSender + action 0 + 2432 : 0.2 + 2433 : 0.2 + 2434 : 0.2 + 2435 : 0.2 + 2436 : 0.2 +state 3386 observe0Greater1 observeOnlyTrueSender + action 0 + 3959 : 1 +state 3387 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 3387 : 1 +state 3388 observe1Greater1 observeIGreater1 + action 0 + 2442 : 0.833 + 2443 : 0.167 +state 3389 observe1Greater1 observeIGreater1 + action 0 + 3960 : 1 +state 3390 observe1Greater1 observeIGreater1 + action 0 + 3961 : 0.833 + 3962 : 0.167 +state 3391 observe1Greater1 observeIGreater1 + action 0 + 3963 : 1 +state 3392 observe1Greater1 observeIGreater1 + action 0 + 3964 : 0.833 + 3965 : 0.167 +state 3393 observe1Greater1 observeIGreater1 + action 0 + 3966 : 1 +state 3394 observe1Greater1 observeIGreater1 + action 0 + 3967 : 0.833 + 3968 : 0.167 +state 3395 observe1Greater1 observeIGreater1 + action 0 + 3969 : 1 +state 3396 observe1Greater1 observeIGreater1 + action 0 + 3970 : 0.833 + 3971 : 0.167 +state 3397 observe1Greater1 observeIGreater1 + action 0 + 3972 : 1 +state 3398 observe1Greater1 observeIGreater1 + action 0 + 3973 : 1 +state 3399 observe1Greater1 observeIGreater1 + action 0 + 2444 : 0.833 + 2445 : 0.167 +state 3400 observe1Greater1 observeIGreater1 + action 0 + 3974 : 1 +state 3401 observe1Greater1 observeIGreater1 + action 0 + 3975 : 0.833 + 3976 : 0.167 +state 3402 observe1Greater1 observeIGreater1 + action 0 + 3977 : 1 +state 3403 observe1Greater1 observeIGreater1 + action 0 + 3978 : 0.833 + 3979 : 0.167 +state 3404 observe1Greater1 observeIGreater1 + action 0 + 3980 : 1 +state 3405 observe1Greater1 observeIGreater1 + action 0 + 3981 : 0.833 + 3982 : 0.167 +state 3406 observe1Greater1 observeIGreater1 + action 0 + 3983 : 1 +state 3407 observe1Greater1 observeIGreater1 + action 0 + 3984 : 0.833 + 3985 : 0.167 +state 3408 observe1Greater1 observeIGreater1 + action 0 + 3986 : 1 +state 3409 observe1Greater1 observeIGreater1 + action 0 + 3987 : 1 +state 3410 observe1Greater1 observeIGreater1 + action 0 + 2446 : 0.833 + 2447 : 0.167 +state 3411 observe1Greater1 observeIGreater1 + action 0 + 3988 : 1 +state 3412 observe1Greater1 observeIGreater1 + action 0 + 3989 : 0.833 + 3990 : 0.167 +state 3413 observe1Greater1 observeIGreater1 + action 0 + 3991 : 1 +state 3414 observe1Greater1 observeIGreater1 + action 0 + 3992 : 0.833 + 3993 : 0.167 +state 3415 observe1Greater1 observeIGreater1 + action 0 + 3994 : 1 +state 3416 observe1Greater1 observeIGreater1 + action 0 + 3995 : 0.833 + 3996 : 0.167 +state 3417 observe1Greater1 observeIGreater1 + action 0 + 3997 : 1 +state 3418 observe1Greater1 observeIGreater1 + action 0 + 3998 : 0.833 + 3999 : 0.167 +state 3419 observe1Greater1 observeIGreater1 + action 0 + 4000 : 1 +state 3420 observe1Greater1 observeIGreater1 + action 0 + 4001 : 1 +state 3421 observe1Greater1 observeIGreater1 + action 0 + 2448 : 0.833 + 2449 : 0.167 +state 3422 observe1Greater1 observeIGreater1 + action 0 + 4002 : 1 +state 3423 observe1Greater1 observeIGreater1 + action 0 + 4003 : 0.833 + 4004 : 0.167 +state 3424 observe1Greater1 observeIGreater1 + action 0 + 4005 : 1 +state 3425 observe1Greater1 observeIGreater1 + action 0 + 4006 : 0.833 + 4007 : 0.167 +state 3426 observe1Greater1 observeIGreater1 + action 0 + 4008 : 1 +state 3427 observe1Greater1 observeIGreater1 + action 0 + 4009 : 0.833 + 4010 : 0.167 +state 3428 observe1Greater1 observeIGreater1 + action 0 + 4011 : 1 +state 3429 observe1Greater1 observeIGreater1 + action 0 + 4012 : 0.833 + 4013 : 0.167 +state 3430 observe1Greater1 observeIGreater1 + action 0 + 4014 : 1 +state 3431 observe1Greater1 observeIGreater1 + action 0 + 4015 : 1 +state 3432 observe1Greater1 observeIGreater1 + action 0 + 3973 : 1 +state 3433 observe1Greater1 observeIGreater1 + action 0 + 3987 : 1 +state 3434 observe1Greater1 observeIGreater1 + action 0 + 4001 : 1 +state 3435 observe1Greater1 observeIGreater1 + action 0 + 4015 : 1 +state 3436 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4016 : 0.8 + 4017 : 0.2 +state 3437 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4018 : 0.8 + 4019 : 0.2 +state 3438 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4020 : 0.8 + 4021 : 0.2 +state 3439 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4022 : 0.8 + 4023 : 0.2 +state 3440 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4024 : 0.8 + 4025 : 0.2 +state 3441 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4026 : 1 +state 3442 observe2Greater1 observeIGreater1 + action 0 + 2464 : 0.833 + 2465 : 0.167 +state 3443 observe2Greater1 observeIGreater1 + action 0 + 4027 : 1 +state 3444 observe2Greater1 observeIGreater1 + action 0 + 4028 : 0.833 + 4029 : 0.167 +state 3445 observe2Greater1 observeIGreater1 + action 0 + 4030 : 1 +state 3446 observe2Greater1 observeIGreater1 + action 0 + 4031 : 0.833 + 4032 : 0.167 +state 3447 observe2Greater1 observeIGreater1 + action 0 + 4033 : 1 +state 3448 observe2Greater1 observeIGreater1 + action 0 + 4034 : 0.833 + 4035 : 0.167 +state 3449 observe2Greater1 observeIGreater1 + action 0 + 4036 : 1 +state 3450 observe2Greater1 observeIGreater1 + action 0 + 4037 : 0.833 + 4038 : 0.167 +state 3451 observe2Greater1 observeIGreater1 + action 0 + 4039 : 1 +state 3452 observe2Greater1 observeIGreater1 + action 0 + 4040 : 1 +state 3453 + action 0 + 2466 : 0.833 + 2467 : 0.167 +state 3454 + action 0 + 4041 : 1 +state 3455 + action 0 + 4042 : 0.833 + 4043 : 0.167 +state 3456 + action 0 + 4044 : 1 +state 3457 + action 0 + 4045 : 0.833 + 4046 : 0.167 +state 3458 + action 0 + 4047 : 1 +state 3459 + action 0 + 4048 : 0.833 + 4049 : 0.167 +state 3460 + action 0 + 4050 : 1 +state 3461 + action 0 + 4051 : 0.833 + 4052 : 0.167 +state 3462 + action 0 + 4053 : 1 +state 3463 + action 0 + 4054 : 1 +state 3464 + action 0 + 2468 : 0.833 + 2469 : 0.167 +state 3465 + action 0 + 4055 : 1 +state 3466 + action 0 + 4056 : 0.833 + 4057 : 0.167 +state 3467 + action 0 + 4058 : 1 +state 3468 + action 0 + 4059 : 0.833 + 4060 : 0.167 +state 3469 + action 0 + 4061 : 1 +state 3470 + action 0 + 4062 : 0.833 + 4063 : 0.167 +state 3471 + action 0 + 4064 : 1 +state 3472 + action 0 + 4065 : 0.833 + 4066 : 0.167 +state 3473 + action 0 + 4067 : 1 +state 3474 + action 0 + 4068 : 1 +state 3475 observe1Greater1 observeIGreater1 + action 0 + 3987 : 1 +state 3476 observe2Greater1 observeIGreater1 + action 0 + 4040 : 1 +state 3477 + action 0 + 4054 : 1 +state 3478 + action 0 + 4068 : 1 +state 3479 observe0Greater1 observeOnlyTrueSender + action 0 + 4069 : 0.8 + 4070 : 0.2 +state 3480 observe0Greater1 observeOnlyTrueSender + action 0 + 4071 : 0.8 + 4072 : 0.2 +state 3481 observe0Greater1 observeOnlyTrueSender + action 0 + 4073 : 0.8 + 4074 : 0.2 +state 3482 observe0Greater1 observeOnlyTrueSender + action 0 + 4075 : 0.8 + 4076 : 0.2 +state 3483 observe0Greater1 observeOnlyTrueSender + action 0 + 4077 : 0.8 + 4078 : 0.2 +state 3484 observe0Greater1 observeOnlyTrueSender + action 0 + 4079 : 1 +state 3485 observe3Greater1 observeIGreater1 + action 0 + 2484 : 0.833 + 2485 : 0.167 +state 3486 observe3Greater1 observeIGreater1 + action 0 + 4080 : 1 +state 3487 observe3Greater1 observeIGreater1 + action 0 + 4081 : 0.833 + 4082 : 0.167 +state 3488 observe3Greater1 observeIGreater1 + action 0 + 4083 : 1 +state 3489 observe3Greater1 observeIGreater1 + action 0 + 4084 : 0.833 + 4085 : 0.167 +state 3490 observe3Greater1 observeIGreater1 + action 0 + 4086 : 1 +state 3491 observe3Greater1 observeIGreater1 + action 0 + 4087 : 0.833 + 4088 : 0.167 +state 3492 observe3Greater1 observeIGreater1 + action 0 + 4089 : 1 +state 3493 observe3Greater1 observeIGreater1 + action 0 + 4090 : 0.833 + 4091 : 0.167 +state 3494 observe3Greater1 observeIGreater1 + action 0 + 4092 : 1 +state 3495 observe3Greater1 observeIGreater1 + action 0 + 4093 : 1 +state 3496 + action 0 + 2486 : 0.833 + 2487 : 0.167 +state 3497 + action 0 + 4094 : 1 +state 3498 + action 0 + 4095 : 0.833 + 4096 : 0.167 +state 3499 + action 0 + 4097 : 1 +state 3500 + action 0 + 4098 : 0.833 + 4099 : 0.167 +state 3501 + action 0 + 4100 : 1 +state 3502 + action 0 + 4101 : 0.833 + 4102 : 0.167 +state 3503 + action 0 + 4103 : 1 +state 3504 + action 0 + 4104 : 0.833 + 4105 : 0.167 +state 3505 + action 0 + 4106 : 1 +state 3506 + action 0 + 4107 : 1 +state 3507 observe1Greater1 observeIGreater1 + action 0 + 4001 : 1 +state 3508 + action 0 + 4054 : 1 +state 3509 observe3Greater1 observeIGreater1 + action 0 + 4093 : 1 +state 3510 + action 0 + 4107 : 1 +state 3511 observe0Greater1 observeOnlyTrueSender + action 0 + 4108 : 0.8 + 4109 : 0.2 +state 3512 observe0Greater1 observeOnlyTrueSender + action 0 + 4110 : 0.8 + 4111 : 0.2 +state 3513 observe0Greater1 observeOnlyTrueSender + action 0 + 4112 : 0.8 + 4113 : 0.2 +state 3514 observe0Greater1 observeOnlyTrueSender + action 0 + 4114 : 0.8 + 4115 : 0.2 +state 3515 observe0Greater1 observeOnlyTrueSender + action 0 + 4116 : 0.8 + 4117 : 0.2 +state 3516 observe0Greater1 observeOnlyTrueSender + action 0 + 4118 : 1 +state 3517 observe4Greater1 observeIGreater1 + action 0 + 2502 : 0.833 + 2503 : 0.167 +state 3518 observe4Greater1 observeIGreater1 + action 0 + 4119 : 1 +state 3519 observe4Greater1 observeIGreater1 + action 0 + 4120 : 0.833 + 4121 : 0.167 +state 3520 observe4Greater1 observeIGreater1 + action 0 + 4122 : 1 +state 3521 observe4Greater1 observeIGreater1 + action 0 + 4123 : 0.833 + 4124 : 0.167 +state 3522 observe4Greater1 observeIGreater1 + action 0 + 4125 : 1 +state 3523 observe4Greater1 observeIGreater1 + action 0 + 4126 : 0.833 + 4127 : 0.167 +state 3524 observe4Greater1 observeIGreater1 + action 0 + 4128 : 1 +state 3525 observe4Greater1 observeIGreater1 + action 0 + 4129 : 0.833 + 4130 : 0.167 +state 3526 observe4Greater1 observeIGreater1 + action 0 + 4131 : 1 +state 3527 observe4Greater1 observeIGreater1 + action 0 + 4132 : 1 +state 3528 observe1Greater1 observeIGreater1 + action 0 + 4015 : 1 +state 3529 + action 0 + 4068 : 1 +state 3530 + action 0 + 4107 : 1 +state 3531 observe4Greater1 observeIGreater1 + action 0 + 4132 : 1 +state 3532 observe0Greater1 observeOnlyTrueSender + action 0 + 4133 : 0.8 + 4134 : 0.2 +state 3533 observe0Greater1 observeOnlyTrueSender + action 0 + 4135 : 0.8 + 4136 : 0.2 +state 3534 observe0Greater1 observeOnlyTrueSender + action 0 + 4137 : 0.8 + 4138 : 0.2 +state 3535 observe0Greater1 observeOnlyTrueSender + action 0 + 4139 : 0.8 + 4140 : 0.2 +state 3536 observe0Greater1 observeOnlyTrueSender + action 0 + 4141 : 0.8 + 4142 : 0.2 +state 3537 observe0Greater1 observeOnlyTrueSender + action 0 + 4143 : 1 +state 3538 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4144 : 1 +state 3539 observe0Greater1 observeOnlyTrueSender + action 0 + 4145 : 1 +state 3540 observe0Greater1 observeOnlyTrueSender + action 0 + 4146 : 1 +state 3541 observe0Greater1 observeOnlyTrueSender + action 0 + 4147 : 1 +state 3542 observe2Greater1 observeIGreater1 + action 0 + 2529 : 0.833 + 2530 : 0.167 +state 3543 observe2Greater1 observeIGreater1 + action 0 + 4148 : 1 +state 3544 observe2Greater1 observeIGreater1 + action 0 + 4149 : 0.833 + 4150 : 0.167 +state 3545 observe2Greater1 observeIGreater1 + action 0 + 4151 : 1 +state 3546 observe2Greater1 observeIGreater1 + action 0 + 4152 : 0.833 + 4153 : 0.167 +state 3547 observe2Greater1 observeIGreater1 + action 0 + 4154 : 1 +state 3548 observe2Greater1 observeIGreater1 + action 0 + 4155 : 0.833 + 4156 : 0.167 +state 3549 observe2Greater1 observeIGreater1 + action 0 + 4157 : 1 +state 3550 observe2Greater1 observeIGreater1 + action 0 + 4158 : 0.833 + 4159 : 0.167 +state 3551 observe2Greater1 observeIGreater1 + action 0 + 4160 : 1 +state 3552 observe2Greater1 observeIGreater1 + action 0 + 4161 : 1 +state 3553 observe2Greater1 observeIGreater1 + action 0 + 2531 : 0.833 + 2532 : 0.167 +state 3554 observe2Greater1 observeIGreater1 + action 0 + 4162 : 1 +state 3555 observe2Greater1 observeIGreater1 + action 0 + 4163 : 0.833 + 4164 : 0.167 +state 3556 observe2Greater1 observeIGreater1 + action 0 + 4165 : 1 +state 3557 observe2Greater1 observeIGreater1 + action 0 + 4166 : 0.833 + 4167 : 0.167 +state 3558 observe2Greater1 observeIGreater1 + action 0 + 4168 : 1 +state 3559 observe2Greater1 observeIGreater1 + action 0 + 4169 : 0.833 + 4170 : 0.167 +state 3560 observe2Greater1 observeIGreater1 + action 0 + 4171 : 1 +state 3561 observe2Greater1 observeIGreater1 + action 0 + 4172 : 0.833 + 4173 : 0.167 +state 3562 observe2Greater1 observeIGreater1 + action 0 + 4174 : 1 +state 3563 observe2Greater1 observeIGreater1 + action 0 + 4175 : 1 +state 3564 observe2Greater1 observeIGreater1 + action 0 + 2533 : 0.833 + 2534 : 0.167 +state 3565 observe2Greater1 observeIGreater1 + action 0 + 4176 : 1 +state 3566 observe2Greater1 observeIGreater1 + action 0 + 4177 : 0.833 + 4178 : 0.167 +state 3567 observe2Greater1 observeIGreater1 + action 0 + 4179 : 1 +state 3568 observe2Greater1 observeIGreater1 + action 0 + 4180 : 0.833 + 4181 : 0.167 +state 3569 observe2Greater1 observeIGreater1 + action 0 + 4182 : 1 +state 3570 observe2Greater1 observeIGreater1 + action 0 + 4183 : 0.833 + 4184 : 0.167 +state 3571 observe2Greater1 observeIGreater1 + action 0 + 4185 : 1 +state 3572 observe2Greater1 observeIGreater1 + action 0 + 4186 : 0.833 + 4187 : 0.167 +state 3573 observe2Greater1 observeIGreater1 + action 0 + 4188 : 1 +state 3574 observe2Greater1 observeIGreater1 + action 0 + 4189 : 1 +state 3575 observe2Greater1 observeIGreater1 + action 0 + 4040 : 1 +state 3576 observe2Greater1 observeIGreater1 + action 0 + 4161 : 1 +state 3577 observe2Greater1 observeIGreater1 + action 0 + 4175 : 1 +state 3578 observe2Greater1 observeIGreater1 + action 0 + 4189 : 1 +state 3579 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4190 : 0.8 + 4191 : 0.2 +state 3580 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4192 : 0.8 + 4193 : 0.2 +state 3581 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4194 : 0.8 + 4195 : 0.2 +state 3582 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4196 : 0.8 + 4197 : 0.2 +state 3583 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4198 : 0.8 + 4199 : 0.2 +state 3584 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4200 : 1 +state 3585 observe3Greater1 observeIGreater1 + action 0 + 2549 : 0.833 + 2550 : 0.167 +state 3586 observe3Greater1 observeIGreater1 + action 0 + 4201 : 1 +state 3587 observe3Greater1 observeIGreater1 + action 0 + 4202 : 0.833 + 4203 : 0.167 +state 3588 observe3Greater1 observeIGreater1 + action 0 + 4204 : 1 +state 3589 observe3Greater1 observeIGreater1 + action 0 + 4205 : 0.833 + 4206 : 0.167 +state 3590 observe3Greater1 observeIGreater1 + action 0 + 4207 : 1 +state 3591 observe3Greater1 observeIGreater1 + action 0 + 4208 : 0.833 + 4209 : 0.167 +state 3592 observe3Greater1 observeIGreater1 + action 0 + 4210 : 1 +state 3593 observe3Greater1 observeIGreater1 + action 0 + 4211 : 0.833 + 4212 : 0.167 +state 3594 observe3Greater1 observeIGreater1 + action 0 + 4213 : 1 +state 3595 observe3Greater1 observeIGreater1 + action 0 + 4214 : 1 +state 3596 + action 0 + 2551 : 0.833 + 2552 : 0.167 +state 3597 + action 0 + 4215 : 1 +state 3598 + action 0 + 4216 : 0.833 + 4217 : 0.167 +state 3599 + action 0 + 4218 : 1 +state 3600 + action 0 + 4219 : 0.833 + 4220 : 0.167 +state 3601 + action 0 + 4221 : 1 +state 3602 + action 0 + 4222 : 0.833 + 4223 : 0.167 +state 3603 + action 0 + 4224 : 1 +state 3604 + action 0 + 4225 : 0.833 + 4226 : 0.167 +state 3605 + action 0 + 4227 : 1 +state 3606 + action 0 + 4228 : 1 +state 3607 + action 0 + 4054 : 1 +state 3608 observe2Greater1 observeIGreater1 + action 0 + 4175 : 1 +state 3609 observe3Greater1 observeIGreater1 + action 0 + 4214 : 1 +state 3610 + action 0 + 4228 : 1 +state 3611 observe0Greater1 observeOnlyTrueSender + action 0 + 4229 : 0.8 + 4230 : 0.2 +state 3612 observe0Greater1 observeOnlyTrueSender + action 0 + 4231 : 0.8 + 4232 : 0.2 +state 3613 observe0Greater1 observeOnlyTrueSender + action 0 + 4233 : 0.8 + 4234 : 0.2 +state 3614 observe0Greater1 observeOnlyTrueSender + action 0 + 4235 : 0.8 + 4236 : 0.2 +state 3615 observe0Greater1 observeOnlyTrueSender + action 0 + 4237 : 0.8 + 4238 : 0.2 +state 3616 observe0Greater1 observeOnlyTrueSender + action 0 + 4239 : 1 +state 3617 observe4Greater1 observeIGreater1 + action 0 + 2567 : 0.833 + 2568 : 0.167 +state 3618 observe4Greater1 observeIGreater1 + action 0 + 4240 : 1 +state 3619 observe4Greater1 observeIGreater1 + action 0 + 4241 : 0.833 + 4242 : 0.167 +state 3620 observe4Greater1 observeIGreater1 + action 0 + 4243 : 1 +state 3621 observe4Greater1 observeIGreater1 + action 0 + 4244 : 0.833 + 4245 : 0.167 +state 3622 observe4Greater1 observeIGreater1 + action 0 + 4246 : 1 +state 3623 observe4Greater1 observeIGreater1 + action 0 + 4247 : 0.833 + 4248 : 0.167 +state 3624 observe4Greater1 observeIGreater1 + action 0 + 4249 : 1 +state 3625 observe4Greater1 observeIGreater1 + action 0 + 4250 : 0.833 + 4251 : 0.167 +state 3626 observe4Greater1 observeIGreater1 + action 0 + 4252 : 1 +state 3627 observe4Greater1 observeIGreater1 + action 0 + 4253 : 1 +state 3628 + action 0 + 4068 : 1 +state 3629 observe2Greater1 observeIGreater1 + action 0 + 4189 : 1 +state 3630 + action 0 + 4228 : 1 +state 3631 observe4Greater1 observeIGreater1 + action 0 + 4253 : 1 +state 3632 observe0Greater1 observeOnlyTrueSender + action 0 + 4254 : 0.8 + 4255 : 0.2 +state 3633 observe0Greater1 observeOnlyTrueSender + action 0 + 4256 : 0.8 + 4257 : 0.2 +state 3634 observe0Greater1 observeOnlyTrueSender + action 0 + 4258 : 0.8 + 4259 : 0.2 +state 3635 observe0Greater1 observeOnlyTrueSender + action 0 + 4260 : 0.8 + 4261 : 0.2 +state 3636 observe0Greater1 observeOnlyTrueSender + action 0 + 4262 : 0.8 + 4263 : 0.2 +state 3637 observe0Greater1 observeOnlyTrueSender + action 0 + 4264 : 1 +state 3638 observe0Greater1 observeOnlyTrueSender + action 0 + 4265 : 1 +state 3639 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4266 : 1 +state 3640 observe0Greater1 observeOnlyTrueSender + action 0 + 4267 : 1 +state 3641 observe0Greater1 observeOnlyTrueSender + action 0 + 4268 : 1 +state 3642 observe3Greater1 observeIGreater1 + action 0 + 2594 : 0.833 + 2595 : 0.167 +state 3643 observe3Greater1 observeIGreater1 + action 0 + 4269 : 1 +state 3644 observe3Greater1 observeIGreater1 + action 0 + 4270 : 0.833 + 4271 : 0.167 +state 3645 observe3Greater1 observeIGreater1 + action 0 + 4272 : 1 +state 3646 observe3Greater1 observeIGreater1 + action 0 + 4273 : 0.833 + 4274 : 0.167 +state 3647 observe3Greater1 observeIGreater1 + action 0 + 4275 : 1 +state 3648 observe3Greater1 observeIGreater1 + action 0 + 4276 : 0.833 + 4277 : 0.167 +state 3649 observe3Greater1 observeIGreater1 + action 0 + 4278 : 1 +state 3650 observe3Greater1 observeIGreater1 + action 0 + 4279 : 0.833 + 4280 : 0.167 +state 3651 observe3Greater1 observeIGreater1 + action 0 + 4281 : 1 +state 3652 observe3Greater1 observeIGreater1 + action 0 + 4282 : 1 +state 3653 observe3Greater1 observeIGreater1 + action 0 + 2596 : 0.833 + 2597 : 0.167 +state 3654 observe3Greater1 observeIGreater1 + action 0 + 4283 : 1 +state 3655 observe3Greater1 observeIGreater1 + action 0 + 4284 : 0.833 + 4285 : 0.167 +state 3656 observe3Greater1 observeIGreater1 + action 0 + 4286 : 1 +state 3657 observe3Greater1 observeIGreater1 + action 0 + 4287 : 0.833 + 4288 : 0.167 +state 3658 observe3Greater1 observeIGreater1 + action 0 + 4289 : 1 +state 3659 observe3Greater1 observeIGreater1 + action 0 + 4290 : 0.833 + 4291 : 0.167 +state 3660 observe3Greater1 observeIGreater1 + action 0 + 4292 : 1 +state 3661 observe3Greater1 observeIGreater1 + action 0 + 4293 : 0.833 + 4294 : 0.167 +state 3662 observe3Greater1 observeIGreater1 + action 0 + 4295 : 1 +state 3663 observe3Greater1 observeIGreater1 + action 0 + 4296 : 1 +state 3664 observe3Greater1 observeIGreater1 + action 0 + 4093 : 1 +state 3665 observe3Greater1 observeIGreater1 + action 0 + 4214 : 1 +state 3666 observe3Greater1 observeIGreater1 + action 0 + 4282 : 1 +state 3667 observe3Greater1 observeIGreater1 + action 0 + 4296 : 1 +state 3668 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4297 : 0.8 + 4298 : 0.2 +state 3669 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4299 : 0.8 + 4300 : 0.2 +state 3670 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4301 : 0.8 + 4302 : 0.2 +state 3671 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4303 : 0.8 + 4304 : 0.2 +state 3672 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4305 : 0.8 + 4306 : 0.2 +state 3673 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4307 : 1 +state 3674 observe4Greater1 observeIGreater1 + action 0 + 2612 : 0.833 + 2613 : 0.167 +state 3675 observe4Greater1 observeIGreater1 + action 0 + 4308 : 1 +state 3676 observe4Greater1 observeIGreater1 + action 0 + 4309 : 0.833 + 4310 : 0.167 +state 3677 observe4Greater1 observeIGreater1 + action 0 + 4311 : 1 +state 3678 observe4Greater1 observeIGreater1 + action 0 + 4312 : 0.833 + 4313 : 0.167 +state 3679 observe4Greater1 observeIGreater1 + action 0 + 4314 : 1 +state 3680 observe4Greater1 observeIGreater1 + action 0 + 4315 : 0.833 + 4316 : 0.167 +state 3681 observe4Greater1 observeIGreater1 + action 0 + 4317 : 1 +state 3682 observe4Greater1 observeIGreater1 + action 0 + 4318 : 0.833 + 4319 : 0.167 +state 3683 observe4Greater1 observeIGreater1 + action 0 + 4320 : 1 +state 3684 observe4Greater1 observeIGreater1 + action 0 + 4321 : 1 +state 3685 + action 0 + 4107 : 1 +state 3686 + action 0 + 4228 : 1 +state 3687 observe3Greater1 observeIGreater1 + action 0 + 4296 : 1 +state 3688 observe4Greater1 observeIGreater1 + action 0 + 4321 : 1 +state 3689 observe0Greater1 observeOnlyTrueSender + action 0 + 4322 : 0.8 + 4323 : 0.2 +state 3690 observe0Greater1 observeOnlyTrueSender + action 0 + 4324 : 0.8 + 4325 : 0.2 +state 3691 observe0Greater1 observeOnlyTrueSender + action 0 + 4326 : 0.8 + 4327 : 0.2 +state 3692 observe0Greater1 observeOnlyTrueSender + action 0 + 4328 : 0.8 + 4329 : 0.2 +state 3693 observe0Greater1 observeOnlyTrueSender + action 0 + 4330 : 0.8 + 4331 : 0.2 +state 3694 observe0Greater1 observeOnlyTrueSender + action 0 + 4332 : 1 +state 3695 observe0Greater1 observeOnlyTrueSender + action 0 + 4333 : 1 +state 3696 observe0Greater1 observeOnlyTrueSender + action 0 + 4334 : 1 +state 3697 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4335 : 1 +state 3698 observe0Greater1 observeOnlyTrueSender + action 0 + 4336 : 1 +state 3699 observe4Greater1 observeIGreater1 + action 0 + 2639 : 0.833 + 2640 : 0.167 +state 3700 observe4Greater1 observeIGreater1 + action 0 + 4337 : 1 +state 3701 observe4Greater1 observeIGreater1 + action 0 + 4338 : 0.833 + 4339 : 0.167 +state 3702 observe4Greater1 observeIGreater1 + action 0 + 4340 : 1 +state 3703 observe4Greater1 observeIGreater1 + action 0 + 4341 : 0.833 + 4342 : 0.167 +state 3704 observe4Greater1 observeIGreater1 + action 0 + 4343 : 1 +state 3705 observe4Greater1 observeIGreater1 + action 0 + 4344 : 0.833 + 4345 : 0.167 +state 3706 observe4Greater1 observeIGreater1 + action 0 + 4346 : 1 +state 3707 observe4Greater1 observeIGreater1 + action 0 + 4347 : 0.833 + 4348 : 0.167 +state 3708 observe4Greater1 observeIGreater1 + action 0 + 4349 : 1 +state 3709 observe4Greater1 observeIGreater1 + action 0 + 4350 : 1 +state 3710 observe4Greater1 observeIGreater1 + action 0 + 4132 : 1 +state 3711 observe4Greater1 observeIGreater1 + action 0 + 4253 : 1 +state 3712 observe4Greater1 observeIGreater1 + action 0 + 4321 : 1 +state 3713 observe4Greater1 observeIGreater1 + action 0 + 4350 : 1 +state 3714 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4351 : 0.8 + 4352 : 0.2 +state 3715 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4353 : 0.8 + 4354 : 0.2 +state 3716 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4355 : 0.8 + 4356 : 0.2 +state 3717 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4357 : 0.8 + 4358 : 0.2 +state 3718 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4359 : 0.8 + 4360 : 0.2 +state 3719 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4361 : 1 +state 3720 observe0Greater1 observeOnlyTrueSender + action 0 + 4362 : 1 +state 3721 observe0Greater1 observeOnlyTrueSender + action 0 + 4363 : 1 +state 3722 observe0Greater1 observeOnlyTrueSender + action 0 + 4364 : 1 +state 3723 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4365 : 1 +state 3724 + action 0 + 4366 : 1 +state 3725 + action 0 + 4367 : 1 +state 3726 + action 0 + 4368 : 1 +state 3727 + action 0 + 4369 : 1 +state 3728 + action 0 + 4370 : 1 +state 3729 + action 0 + 4371 : 0.833 + 4372 : 0.167 +state 3730 + action 0 + 4373 : 1 +state 3731 + action 0 + 4374 : 0.833 + 4375 : 0.167 +state 3732 + action 0 + 4376 : 1 +state 3733 + action 0 + 4377 : 0.833 + 4378 : 0.167 +state 3734 + action 0 + 4379 : 1 +state 3735 + action 0 + 4380 : 0.833 + 4381 : 0.167 +state 3736 + action 0 + 4382 : 1 +state 3737 deadlock + action 0 + 3737 : 1 +state 3738 + action 0 + 4383 : 1 +state 3739 + action 0 + 4384 : 0.833 + 4385 : 0.167 +state 3740 + action 0 + 4386 : 1 +state 3741 + action 0 + 4387 : 0.833 + 4388 : 0.167 +state 3742 + action 0 + 4389 : 1 +state 3743 + action 0 + 4390 : 0.833 + 4391 : 0.167 +state 3744 + action 0 + 4392 : 1 +state 3745 + action 0 + 4393 : 0.833 + 4394 : 0.167 +state 3746 + action 0 + 4395 : 1 +state 3747 deadlock + action 0 + 3747 : 1 +state 3748 + action 0 + 4396 : 1 +state 3749 + action 0 + 4397 : 0.833 + 4398 : 0.167 +state 3750 + action 0 + 4399 : 1 +state 3751 + action 0 + 4400 : 0.833 + 4401 : 0.167 +state 3752 + action 0 + 4402 : 1 +state 3753 + action 0 + 4403 : 0.833 + 4404 : 0.167 +state 3754 + action 0 + 4405 : 1 +state 3755 + action 0 + 4406 : 0.833 + 4407 : 0.167 +state 3756 + action 0 + 4408 : 1 +state 3757 deadlock + action 0 + 3757 : 1 +state 3758 + action 0 + 4409 : 1 +state 3759 + action 0 + 4410 : 0.833 + 4411 : 0.167 +state 3760 + action 0 + 4412 : 1 +state 3761 + action 0 + 4413 : 0.833 + 4414 : 0.167 +state 3762 + action 0 + 4415 : 1 +state 3763 + action 0 + 4416 : 0.833 + 4417 : 0.167 +state 3764 + action 0 + 4418 : 1 +state 3765 + action 0 + 4419 : 0.833 + 4420 : 0.167 +state 3766 + action 0 + 4421 : 1 +state 3767 deadlock + action 0 + 3767 : 1 +state 3768 deadlock + action 0 + 3768 : 1 +state 3769 deadlock + action 0 + 3769 : 1 +state 3770 deadlock + action 0 + 3770 : 1 +state 3771 deadlock + action 0 + 3771 : 1 +state 3772 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 3773 observe1Greater1 observeIGreater1 + action 0 + 4427 : 1 +state 3774 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 3775 + action 0 + 4433 : 1 +state 3776 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 3777 + action 0 + 4439 : 1 +state 3778 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 3779 + action 0 + 4445 : 1 +state 3780 deadlock + action 0 + 3780 : 1 +state 3781 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3782 + action 0 + 4446 : 1 +state 3783 deadlock + action 0 + 3783 : 1 +state 3784 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3785 + action 0 + 4447 : 1 +state 3786 deadlock + action 0 + 3786 : 1 +state 3787 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3788 + action 0 + 4448 : 1 +state 3789 deadlock + action 0 + 3789 : 1 +state 3790 + action 0 + 2705 : 0.2 + 2706 : 0.2 + 2707 : 0.2 + 2708 : 0.2 + 2709 : 0.2 +state 3791 + action 0 + 4449 : 1 +state 3792 deadlock + action 0 + 3792 : 1 +state 3793 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 3794 observe2Greater1 observeIGreater1 + action 0 + 4455 : 1 +state 3795 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 3796 + action 0 + 4461 : 1 +state 3797 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 3798 + action 0 + 4467 : 1 +state 3799 deadlock + action 0 + 3799 : 1 +state 3800 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3801 + action 0 + 4468 : 1 +state 3802 deadlock + action 0 + 3802 : 1 +state 3803 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3804 + action 0 + 4469 : 1 +state 3805 deadlock + action 0 + 3805 : 1 +state 3806 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3807 + action 0 + 4470 : 1 +state 3808 deadlock + action 0 + 3808 : 1 +state 3809 + action 0 + 2715 : 0.2 + 2716 : 0.2 + 2717 : 0.2 + 2718 : 0.2 + 2719 : 0.2 +state 3810 + action 0 + 4471 : 1 +state 3811 deadlock + action 0 + 3811 : 1 +state 3812 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 3813 observe3Greater1 observeIGreater1 + action 0 + 4477 : 1 +state 3814 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 3815 + action 0 + 4483 : 1 +state 3816 deadlock + action 0 + 3816 : 1 +state 3817 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3818 + action 0 + 4484 : 1 +state 3819 deadlock + action 0 + 3819 : 1 +state 3820 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3821 + action 0 + 4485 : 1 +state 3822 deadlock + action 0 + 3822 : 1 +state 3823 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3824 + action 0 + 4486 : 1 +state 3825 deadlock + action 0 + 3825 : 1 +state 3826 + action 0 + 2725 : 0.2 + 2726 : 0.2 + 2727 : 0.2 + 2728 : 0.2 + 2729 : 0.2 +state 3827 + action 0 + 4487 : 1 +state 3828 deadlock + action 0 + 3828 : 1 +state 3829 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 3830 observe4Greater1 observeIGreater1 + action 0 + 4493 : 1 +state 3831 deadlock + action 0 + 3831 : 1 +state 3832 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3833 + action 0 + 4494 : 1 +state 3834 deadlock + action 0 + 3834 : 1 +state 3835 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3836 + action 0 + 4495 : 1 +state 3837 deadlock + action 0 + 3837 : 1 +state 3838 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3839 + action 0 + 4496 : 1 +state 3840 deadlock + action 0 + 3840 : 1 +state 3841 + action 0 + 2735 : 0.2 + 2736 : 0.2 + 2737 : 0.2 + 2738 : 0.2 + 2739 : 0.2 +state 3842 + action 0 + 4497 : 1 +state 3843 deadlock + action 0 + 3843 : 1 +state 3844 observe1Greater1 observeIGreater1 + action 0 + 4498 : 1 +state 3845 observe1Greater1 observeIGreater1 + action 0 + 4499 : 1 +state 3846 observe1Greater1 observeIGreater1 + action 0 + 4500 : 1 +state 3847 observe1Greater1 observeIGreater1 + action 0 + 4501 : 1 +state 3848 observe1Greater1 observeIGreater1 + action 0 + 2953 : 0.8 + 4502 : 0.2 +state 3849 observe1Greater1 observeIGreater1 + action 0 + 4503 : 0.8 + 4504 : 0.2 +state 3850 observe1Greater1 observeIGreater1 + action 0 + 4505 : 0.8 + 4506 : 0.2 +state 3851 observe1Greater1 observeIGreater1 + action 0 + 4507 : 0.8 + 4508 : 0.2 +state 3852 observe1Greater1 observeIGreater1 + action 0 + 4509 : 0.8 + 4510 : 0.2 +state 3853 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4511 : 1 +state 3854 observe1Greater1 observeIGreater1 + action 0 + 4499 : 1 +state 3855 observe2Greater1 observeIGreater1 + action 0 + 4512 : 1 +state 3856 + action 0 + 4513 : 1 +state 3857 + action 0 + 4514 : 1 +state 3858 + action 0 + 2978 : 0.8 + 4515 : 0.2 +state 3859 + action 0 + 4516 : 0.8 + 4517 : 0.2 +state 3860 + action 0 + 4518 : 0.8 + 4519 : 0.2 +state 3861 + action 0 + 4520 : 0.8 + 4521 : 0.2 +state 3862 + action 0 + 4522 : 0.8 + 4523 : 0.2 +state 3863 observe0Greater1 observeOnlyTrueSender + action 0 + 4524 : 1 +state 3864 observe1Greater1 observeIGreater1 + action 0 + 4500 : 1 +state 3865 + action 0 + 4513 : 1 +state 3866 observe3Greater1 observeIGreater1 + action 0 + 4525 : 1 +state 3867 + action 0 + 4526 : 1 +state 3868 + action 0 + 2997 : 0.8 + 4527 : 0.2 +state 3869 + action 0 + 4528 : 0.8 + 4529 : 0.2 +state 3870 + action 0 + 4530 : 0.8 + 4531 : 0.2 +state 3871 + action 0 + 4532 : 0.8 + 4533 : 0.2 +state 3872 + action 0 + 4534 : 0.8 + 4535 : 0.2 +state 3873 observe0Greater1 observeOnlyTrueSender + action 0 + 4536 : 1 +state 3874 observe1Greater1 observeIGreater1 + action 0 + 4501 : 1 +state 3875 + action 0 + 4514 : 1 +state 3876 + action 0 + 4526 : 1 +state 3877 observe4Greater1 observeIGreater1 + action 0 + 4537 : 1 +state 3878 + action 0 + 3010 : 0.8 + 4538 : 0.2 +state 3879 + action 0 + 4539 : 0.8 + 4540 : 0.2 +state 3880 + action 0 + 4541 : 0.8 + 4542 : 0.2 +state 3881 + action 0 + 4543 : 0.8 + 4544 : 0.2 +state 3882 + action 0 + 4545 : 0.8 + 4546 : 0.2 +state 3883 observe0Greater1 observeOnlyTrueSender + action 0 + 4547 : 1 +state 3884 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4548 : 1 +state 3885 observe0Greater1 observeOnlyTrueSender + action 0 + 4549 : 1 +state 3886 observe0Greater1 observeOnlyTrueSender + action 0 + 4550 : 1 +state 3887 observe0Greater1 observeOnlyTrueSender + action 0 + 4551 : 1 +state 3888 observe2Greater1 observeIGreater1 + action 0 + 4512 : 1 +state 3889 observe2Greater1 observeIGreater1 + action 0 + 4552 : 1 +state 3890 observe2Greater1 observeIGreater1 + action 0 + 4553 : 1 +state 3891 observe2Greater1 observeIGreater1 + action 0 + 4554 : 1 +state 3892 observe2Greater1 observeIGreater1 + action 0 + 3048 : 0.8 + 4555 : 0.2 +state 3893 observe2Greater1 observeIGreater1 + action 0 + 4556 : 0.8 + 4557 : 0.2 +state 3894 observe2Greater1 observeIGreater1 + action 0 + 4558 : 0.8 + 4559 : 0.2 +state 3895 observe2Greater1 observeIGreater1 + action 0 + 4560 : 0.8 + 4561 : 0.2 +state 3896 observe2Greater1 observeIGreater1 + action 0 + 4562 : 0.8 + 4563 : 0.2 +state 3897 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4564 : 1 +state 3898 + action 0 + 4513 : 1 +state 3899 observe2Greater1 observeIGreater1 + action 0 + 4553 : 1 +state 3900 observe3Greater1 observeIGreater1 + action 0 + 4565 : 1 +state 3901 + action 0 + 4566 : 1 +state 3902 + action 0 + 3067 : 0.8 + 4567 : 0.2 +state 3903 + action 0 + 4568 : 0.8 + 4569 : 0.2 +state 3904 + action 0 + 4570 : 0.8 + 4571 : 0.2 +state 3905 + action 0 + 4572 : 0.8 + 4573 : 0.2 +state 3906 + action 0 + 4574 : 0.8 + 4575 : 0.2 +state 3907 observe0Greater1 observeOnlyTrueSender + action 0 + 4576 : 1 +state 3908 + action 0 + 4514 : 1 +state 3909 observe2Greater1 observeIGreater1 + action 0 + 4554 : 1 +state 3910 + action 0 + 4566 : 1 +state 3911 observe4Greater1 observeIGreater1 + action 0 + 4577 : 1 +state 3912 + action 0 + 3080 : 0.8 + 4578 : 0.2 +state 3913 + action 0 + 4579 : 0.8 + 4580 : 0.2 +state 3914 + action 0 + 4581 : 0.8 + 4582 : 0.2 +state 3915 + action 0 + 4583 : 0.8 + 4584 : 0.2 +state 3916 + action 0 + 4585 : 0.8 + 4586 : 0.2 +state 3917 observe0Greater1 observeOnlyTrueSender + action 0 + 4587 : 1 +state 3918 observe0Greater1 observeOnlyTrueSender + action 0 + 4588 : 1 +state 3919 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4589 : 1 +state 3920 observe0Greater1 observeOnlyTrueSender + action 0 + 4590 : 1 +state 3921 observe0Greater1 observeOnlyTrueSender + action 0 + 4591 : 1 +state 3922 observe3Greater1 observeIGreater1 + action 0 + 4525 : 1 +state 3923 observe3Greater1 observeIGreater1 + action 0 + 4565 : 1 +state 3924 observe3Greater1 observeIGreater1 + action 0 + 4592 : 1 +state 3925 observe3Greater1 observeIGreater1 + action 0 + 4593 : 1 +state 3926 observe3Greater1 observeIGreater1 + action 0 + 3112 : 0.8 + 4594 : 0.2 +state 3927 observe3Greater1 observeIGreater1 + action 0 + 4595 : 0.8 + 4596 : 0.2 +state 3928 observe3Greater1 observeIGreater1 + action 0 + 4597 : 0.8 + 4598 : 0.2 +state 3929 observe3Greater1 observeIGreater1 + action 0 + 4599 : 0.8 + 4600 : 0.2 +state 3930 observe3Greater1 observeIGreater1 + action 0 + 4601 : 0.8 + 4602 : 0.2 +state 3931 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4603 : 1 +state 3932 + action 0 + 4526 : 1 +state 3933 + action 0 + 4566 : 1 +state 3934 observe3Greater1 observeIGreater1 + action 0 + 4593 : 1 +state 3935 observe4Greater1 observeIGreater1 + action 0 + 4604 : 1 +state 3936 + action 0 + 3125 : 0.8 + 4605 : 0.2 +state 3937 + action 0 + 4606 : 0.8 + 4607 : 0.2 +state 3938 + action 0 + 4608 : 0.8 + 4609 : 0.2 +state 3939 + action 0 + 4610 : 0.8 + 4611 : 0.2 +state 3940 + action 0 + 4612 : 0.8 + 4613 : 0.2 +state 3941 observe0Greater1 observeOnlyTrueSender + action 0 + 4614 : 1 +state 3942 observe0Greater1 observeOnlyTrueSender + action 0 + 4615 : 1 +state 3943 observe0Greater1 observeOnlyTrueSender + action 0 + 4616 : 1 +state 3944 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4617 : 1 +state 3945 observe0Greater1 observeOnlyTrueSender + action 0 + 4618 : 1 +state 3946 observe4Greater1 observeIGreater1 + action 0 + 4537 : 1 +state 3947 observe4Greater1 observeIGreater1 + action 0 + 4577 : 1 +state 3948 observe4Greater1 observeIGreater1 + action 0 + 4604 : 1 +state 3949 observe4Greater1 observeIGreater1 + action 0 + 4619 : 1 +state 3950 observe4Greater1 observeIGreater1 + action 0 + 3151 : 0.8 + 4620 : 0.2 +state 3951 observe4Greater1 observeIGreater1 + action 0 + 4621 : 0.8 + 4622 : 0.2 +state 3952 observe4Greater1 observeIGreater1 + action 0 + 4623 : 0.8 + 4624 : 0.2 +state 3953 observe4Greater1 observeIGreater1 + action 0 + 4625 : 0.8 + 4626 : 0.2 +state 3954 observe4Greater1 observeIGreater1 + action 0 + 4627 : 0.8 + 4628 : 0.2 +state 3955 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4629 : 1 +state 3956 observe0Greater1 observeOnlyTrueSender + action 0 + 4630 : 1 +state 3957 observe0Greater1 observeOnlyTrueSender + action 0 + 4631 : 1 +state 3958 observe0Greater1 observeOnlyTrueSender + action 0 + 4632 : 1 +state 3959 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4633 : 1 +state 3960 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3961 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3962 observe1Greater1 observeIGreater1 + action 0 + 4635 : 1 +state 3963 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3964 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3965 observe1Greater1 observeIGreater1 + action 0 + 4636 : 1 +state 3966 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3967 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3968 observe1Greater1 observeIGreater1 + action 0 + 4637 : 1 +state 3969 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3970 observe1Greater1 observeIGreater1 + action 0 + 2929 : 0.2 + 2930 : 0.2 + 2931 : 0.2 + 2932 : 0.2 + 2933 : 0.2 +state 3971 observe1Greater1 observeIGreater1 + action 0 + 4638 : 1 +state 3972 observe1Greater1 observeIGreater1 + action 0 + 4634 : 1 +state 3973 observe1Greater1 observeIGreater1 + action 0 + 4639 : 0.833 + 4640 : 0.167 +state 3974 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3975 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3976 observe1Greater1 observeIGreater1 + action 0 + 4642 : 1 +state 3977 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3978 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3979 observe1Greater1 observeIGreater1 + action 0 + 4643 : 1 +state 3980 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3981 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3982 observe1Greater1 observeIGreater1 + action 0 + 4644 : 1 +state 3983 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3984 observe1Greater1 observeIGreater1 + action 0 + 2935 : 0.2 + 2936 : 0.2 + 2937 : 0.2 + 2938 : 0.2 + 2939 : 0.2 +state 3985 observe1Greater1 observeIGreater1 + action 0 + 4645 : 1 +state 3986 observe1Greater1 observeIGreater1 + action 0 + 4641 : 1 +state 3987 observe1Greater1 observeIGreater1 + action 0 + 4646 : 0.833 + 4647 : 0.167 +state 3988 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3989 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3990 observe1Greater1 observeIGreater1 + action 0 + 4649 : 1 +state 3991 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3992 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3993 observe1Greater1 observeIGreater1 + action 0 + 4650 : 1 +state 3994 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3995 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3996 observe1Greater1 observeIGreater1 + action 0 + 4651 : 1 +state 3997 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 3998 observe1Greater1 observeIGreater1 + action 0 + 2941 : 0.2 + 2942 : 0.2 + 2943 : 0.2 + 2944 : 0.2 + 2945 : 0.2 +state 3999 observe1Greater1 observeIGreater1 + action 0 + 4652 : 1 +state 4000 observe1Greater1 observeIGreater1 + action 0 + 4648 : 1 +state 4001 observe1Greater1 observeIGreater1 + action 0 + 4653 : 0.833 + 4654 : 0.167 +state 4002 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4003 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4004 observe1Greater1 observeIGreater1 + action 0 + 4656 : 1 +state 4005 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4006 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4007 observe1Greater1 observeIGreater1 + action 0 + 4657 : 1 +state 4008 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4009 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4010 observe1Greater1 observeIGreater1 + action 0 + 4658 : 1 +state 4011 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4012 observe1Greater1 observeIGreater1 + action 0 + 2947 : 0.2 + 2948 : 0.2 + 2949 : 0.2 + 2950 : 0.2 + 2951 : 0.2 +state 4013 observe1Greater1 observeIGreater1 + action 0 + 4659 : 1 +state 4014 observe1Greater1 observeIGreater1 + action 0 + 4655 : 1 +state 4015 observe1Greater1 observeIGreater1 + action 0 + 4660 : 0.833 + 4661 : 0.167 +state 4016 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 2958 : 0.833 + 2959 : 0.167 +state 4017 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4662 : 1 +state 4018 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4663 : 0.833 + 4664 : 0.167 +state 4019 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4665 : 1 +state 4020 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4666 : 0.833 + 4667 : 0.167 +state 4021 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4668 : 1 +state 4022 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4669 : 0.833 + 4670 : 0.167 +state 4023 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4671 : 1 +state 4024 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4672 : 0.833 + 4673 : 0.167 +state 4025 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4674 : 1 +state 4026 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4026 : 1 +state 4027 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4028 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4029 observe2Greater1 observeIGreater1 + action 0 + 4676 : 1 +state 4030 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4031 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4032 observe2Greater1 observeIGreater1 + action 0 + 4677 : 1 +state 4033 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4034 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4035 observe2Greater1 observeIGreater1 + action 0 + 4678 : 1 +state 4036 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4037 observe2Greater1 observeIGreater1 + action 0 + 2960 : 0.2 + 2961 : 0.2 + 2962 : 0.2 + 2963 : 0.2 + 2964 : 0.2 +state 4038 observe2Greater1 observeIGreater1 + action 0 + 4679 : 1 +state 4039 observe2Greater1 observeIGreater1 + action 0 + 4675 : 1 +state 4040 observe2Greater1 observeIGreater1 + action 0 + 4680 : 0.833 + 4681 : 0.167 +state 4041 + action 0 + 4682 : 1 +state 4042 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4043 + action 0 + 4683 : 1 +state 4044 + action 0 + 4682 : 1 +state 4045 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4046 + action 0 + 4684 : 1 +state 4047 + action 0 + 4682 : 1 +state 4048 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4049 + action 0 + 4685 : 1 +state 4050 + action 0 + 4682 : 1 +state 4051 + action 0 + 2966 : 0.2 + 2967 : 0.2 + 2968 : 0.2 + 2969 : 0.2 + 2970 : 0.2 +state 4052 + action 0 + 4686 : 1 +state 4053 + action 0 + 4682 : 1 +state 4054 + action 0 + 4687 : 0.833 + 4688 : 0.167 +state 4055 + action 0 + 4689 : 1 +state 4056 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4057 + action 0 + 4690 : 1 +state 4058 + action 0 + 4689 : 1 +state 4059 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4060 + action 0 + 4691 : 1 +state 4061 + action 0 + 4689 : 1 +state 4062 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4063 + action 0 + 4692 : 1 +state 4064 + action 0 + 4689 : 1 +state 4065 + action 0 + 2972 : 0.2 + 2973 : 0.2 + 2974 : 0.2 + 2975 : 0.2 + 2976 : 0.2 +state 4066 + action 0 + 4693 : 1 +state 4067 + action 0 + 4689 : 1 +state 4068 + action 0 + 4694 : 0.833 + 4695 : 0.167 +state 4069 observe0Greater1 observeOnlyTrueSender + action 0 + 2983 : 0.833 + 2984 : 0.167 +state 4070 observe0Greater1 observeOnlyTrueSender + action 0 + 4696 : 1 +state 4071 observe0Greater1 observeOnlyTrueSender + action 0 + 4697 : 0.833 + 4698 : 0.167 +state 4072 observe0Greater1 observeOnlyTrueSender + action 0 + 4699 : 1 +state 4073 observe0Greater1 observeOnlyTrueSender + action 0 + 4700 : 0.833 + 4701 : 0.167 +state 4074 observe0Greater1 observeOnlyTrueSender + action 0 + 4702 : 1 +state 4075 observe0Greater1 observeOnlyTrueSender + action 0 + 4703 : 0.833 + 4704 : 0.167 +state 4076 observe0Greater1 observeOnlyTrueSender + action 0 + 4705 : 1 +state 4077 observe0Greater1 observeOnlyTrueSender + action 0 + 4706 : 0.833 + 4707 : 0.167 +state 4078 observe0Greater1 observeOnlyTrueSender + action 0 + 4708 : 1 +state 4079 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4079 : 1 +state 4080 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4081 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4082 observe3Greater1 observeIGreater1 + action 0 + 4710 : 1 +state 4083 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4084 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4085 observe3Greater1 observeIGreater1 + action 0 + 4711 : 1 +state 4086 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4087 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4088 observe3Greater1 observeIGreater1 + action 0 + 4712 : 1 +state 4089 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4090 observe3Greater1 observeIGreater1 + action 0 + 2985 : 0.2 + 2986 : 0.2 + 2987 : 0.2 + 2988 : 0.2 + 2989 : 0.2 +state 4091 observe3Greater1 observeIGreater1 + action 0 + 4713 : 1 +state 4092 observe3Greater1 observeIGreater1 + action 0 + 4709 : 1 +state 4093 observe3Greater1 observeIGreater1 + action 0 + 4714 : 0.833 + 4715 : 0.167 +state 4094 + action 0 + 4716 : 1 +state 4095 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4096 + action 0 + 4717 : 1 +state 4097 + action 0 + 4716 : 1 +state 4098 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4099 + action 0 + 4718 : 1 +state 4100 + action 0 + 4716 : 1 +state 4101 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4102 + action 0 + 4719 : 1 +state 4103 + action 0 + 4716 : 1 +state 4104 + action 0 + 2991 : 0.2 + 2992 : 0.2 + 2993 : 0.2 + 2994 : 0.2 + 2995 : 0.2 +state 4105 + action 0 + 4720 : 1 +state 4106 + action 0 + 4716 : 1 +state 4107 + action 0 + 4721 : 0.833 + 4722 : 0.167 +state 4108 observe0Greater1 observeOnlyTrueSender + action 0 + 3002 : 0.833 + 3003 : 0.167 +state 4109 observe0Greater1 observeOnlyTrueSender + action 0 + 4723 : 1 +state 4110 observe0Greater1 observeOnlyTrueSender + action 0 + 4724 : 0.833 + 4725 : 0.167 +state 4111 observe0Greater1 observeOnlyTrueSender + action 0 + 4726 : 1 +state 4112 observe0Greater1 observeOnlyTrueSender + action 0 + 4727 : 0.833 + 4728 : 0.167 +state 4113 observe0Greater1 observeOnlyTrueSender + action 0 + 4729 : 1 +state 4114 observe0Greater1 observeOnlyTrueSender + action 0 + 4730 : 0.833 + 4731 : 0.167 +state 4115 observe0Greater1 observeOnlyTrueSender + action 0 + 4732 : 1 +state 4116 observe0Greater1 observeOnlyTrueSender + action 0 + 4733 : 0.833 + 4734 : 0.167 +state 4117 observe0Greater1 observeOnlyTrueSender + action 0 + 4735 : 1 +state 4118 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4118 : 1 +state 4119 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4120 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4121 observe4Greater1 observeIGreater1 + action 0 + 4737 : 1 +state 4122 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4123 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4124 observe4Greater1 observeIGreater1 + action 0 + 4738 : 1 +state 4125 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4126 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4127 observe4Greater1 observeIGreater1 + action 0 + 4739 : 1 +state 4128 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4129 observe4Greater1 observeIGreater1 + action 0 + 3004 : 0.2 + 3005 : 0.2 + 3006 : 0.2 + 3007 : 0.2 + 3008 : 0.2 +state 4130 observe4Greater1 observeIGreater1 + action 0 + 4740 : 1 +state 4131 observe4Greater1 observeIGreater1 + action 0 + 4736 : 1 +state 4132 observe4Greater1 observeIGreater1 + action 0 + 4741 : 0.833 + 4742 : 0.167 +state 4133 observe0Greater1 observeOnlyTrueSender + action 0 + 3015 : 0.833 + 3016 : 0.167 +state 4134 observe0Greater1 observeOnlyTrueSender + action 0 + 4743 : 1 +state 4135 observe0Greater1 observeOnlyTrueSender + action 0 + 4744 : 0.833 + 4745 : 0.167 +state 4136 observe0Greater1 observeOnlyTrueSender + action 0 + 4746 : 1 +state 4137 observe0Greater1 observeOnlyTrueSender + action 0 + 4747 : 0.833 + 4748 : 0.167 +state 4138 observe0Greater1 observeOnlyTrueSender + action 0 + 4749 : 1 +state 4139 observe0Greater1 observeOnlyTrueSender + action 0 + 4750 : 0.833 + 4751 : 0.167 +state 4140 observe0Greater1 observeOnlyTrueSender + action 0 + 4752 : 1 +state 4141 observe0Greater1 observeOnlyTrueSender + action 0 + 4753 : 0.833 + 4754 : 0.167 +state 4142 observe0Greater1 observeOnlyTrueSender + action 0 + 4755 : 1 +state 4143 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4143 : 1 +state 4144 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4144 : 1 +state 4145 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4145 : 1 +state 4146 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4146 : 1 +state 4147 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4147 : 1 +state 4148 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4149 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4150 observe2Greater1 observeIGreater1 + action 0 + 4757 : 1 +state 4151 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4152 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4153 observe2Greater1 observeIGreater1 + action 0 + 4758 : 1 +state 4154 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4155 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4156 observe2Greater1 observeIGreater1 + action 0 + 4759 : 1 +state 4157 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4158 observe2Greater1 observeIGreater1 + action 0 + 3030 : 0.2 + 3031 : 0.2 + 3032 : 0.2 + 3033 : 0.2 + 3034 : 0.2 +state 4159 observe2Greater1 observeIGreater1 + action 0 + 4760 : 1 +state 4160 observe2Greater1 observeIGreater1 + action 0 + 4756 : 1 +state 4161 observe2Greater1 observeIGreater1 + action 0 + 4761 : 0.833 + 4762 : 0.167 +state 4162 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4163 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4164 observe2Greater1 observeIGreater1 + action 0 + 4764 : 1 +state 4165 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4166 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4167 observe2Greater1 observeIGreater1 + action 0 + 4765 : 1 +state 4168 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4169 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4170 observe2Greater1 observeIGreater1 + action 0 + 4766 : 1 +state 4171 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4172 observe2Greater1 observeIGreater1 + action 0 + 3036 : 0.2 + 3037 : 0.2 + 3038 : 0.2 + 3039 : 0.2 + 3040 : 0.2 +state 4173 observe2Greater1 observeIGreater1 + action 0 + 4767 : 1 +state 4174 observe2Greater1 observeIGreater1 + action 0 + 4763 : 1 +state 4175 observe2Greater1 observeIGreater1 + action 0 + 4768 : 0.833 + 4769 : 0.167 +state 4176 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4177 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4178 observe2Greater1 observeIGreater1 + action 0 + 4771 : 1 +state 4179 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4180 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4181 observe2Greater1 observeIGreater1 + action 0 + 4772 : 1 +state 4182 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4183 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4184 observe2Greater1 observeIGreater1 + action 0 + 4773 : 1 +state 4185 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4186 observe2Greater1 observeIGreater1 + action 0 + 3042 : 0.2 + 3043 : 0.2 + 3044 : 0.2 + 3045 : 0.2 + 3046 : 0.2 +state 4187 observe2Greater1 observeIGreater1 + action 0 + 4774 : 1 +state 4188 observe2Greater1 observeIGreater1 + action 0 + 4770 : 1 +state 4189 observe2Greater1 observeIGreater1 + action 0 + 4775 : 0.833 + 4776 : 0.167 +state 4190 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3053 : 0.833 + 3054 : 0.167 +state 4191 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4777 : 1 +state 4192 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4778 : 0.833 + 4779 : 0.167 +state 4193 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4780 : 1 +state 4194 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4781 : 0.833 + 4782 : 0.167 +state 4195 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4783 : 1 +state 4196 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4784 : 0.833 + 4785 : 0.167 +state 4197 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4786 : 1 +state 4198 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4787 : 0.833 + 4788 : 0.167 +state 4199 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4789 : 1 +state 4200 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4200 : 1 +state 4201 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4202 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4203 observe3Greater1 observeIGreater1 + action 0 + 4791 : 1 +state 4204 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4205 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4206 observe3Greater1 observeIGreater1 + action 0 + 4792 : 1 +state 4207 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4208 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4209 observe3Greater1 observeIGreater1 + action 0 + 4793 : 1 +state 4210 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4211 observe3Greater1 observeIGreater1 + action 0 + 3055 : 0.2 + 3056 : 0.2 + 3057 : 0.2 + 3058 : 0.2 + 3059 : 0.2 +state 4212 observe3Greater1 observeIGreater1 + action 0 + 4794 : 1 +state 4213 observe3Greater1 observeIGreater1 + action 0 + 4790 : 1 +state 4214 observe3Greater1 observeIGreater1 + action 0 + 4795 : 0.833 + 4796 : 0.167 +state 4215 + action 0 + 4797 : 1 +state 4216 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4217 + action 0 + 4798 : 1 +state 4218 + action 0 + 4797 : 1 +state 4219 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4220 + action 0 + 4799 : 1 +state 4221 + action 0 + 4797 : 1 +state 4222 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4223 + action 0 + 4800 : 1 +state 4224 + action 0 + 4797 : 1 +state 4225 + action 0 + 3061 : 0.2 + 3062 : 0.2 + 3063 : 0.2 + 3064 : 0.2 + 3065 : 0.2 +state 4226 + action 0 + 4801 : 1 +state 4227 + action 0 + 4797 : 1 +state 4228 + action 0 + 4802 : 0.833 + 4803 : 0.167 +state 4229 observe0Greater1 observeOnlyTrueSender + action 0 + 3072 : 0.833 + 3073 : 0.167 +state 4230 observe0Greater1 observeOnlyTrueSender + action 0 + 4804 : 1 +state 4231 observe0Greater1 observeOnlyTrueSender + action 0 + 4805 : 0.833 + 4806 : 0.167 +state 4232 observe0Greater1 observeOnlyTrueSender + action 0 + 4807 : 1 +state 4233 observe0Greater1 observeOnlyTrueSender + action 0 + 4808 : 0.833 + 4809 : 0.167 +state 4234 observe0Greater1 observeOnlyTrueSender + action 0 + 4810 : 1 +state 4235 observe0Greater1 observeOnlyTrueSender + action 0 + 4811 : 0.833 + 4812 : 0.167 +state 4236 observe0Greater1 observeOnlyTrueSender + action 0 + 4813 : 1 +state 4237 observe0Greater1 observeOnlyTrueSender + action 0 + 4814 : 0.833 + 4815 : 0.167 +state 4238 observe0Greater1 observeOnlyTrueSender + action 0 + 4816 : 1 +state 4239 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4239 : 1 +state 4240 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4241 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4242 observe4Greater1 observeIGreater1 + action 0 + 4818 : 1 +state 4243 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4244 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4245 observe4Greater1 observeIGreater1 + action 0 + 4819 : 1 +state 4246 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4247 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4248 observe4Greater1 observeIGreater1 + action 0 + 4820 : 1 +state 4249 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4250 observe4Greater1 observeIGreater1 + action 0 + 3074 : 0.2 + 3075 : 0.2 + 3076 : 0.2 + 3077 : 0.2 + 3078 : 0.2 +state 4251 observe4Greater1 observeIGreater1 + action 0 + 4821 : 1 +state 4252 observe4Greater1 observeIGreater1 + action 0 + 4817 : 1 +state 4253 observe4Greater1 observeIGreater1 + action 0 + 4822 : 0.833 + 4823 : 0.167 +state 4254 observe0Greater1 observeOnlyTrueSender + action 0 + 3085 : 0.833 + 3086 : 0.167 +state 4255 observe0Greater1 observeOnlyTrueSender + action 0 + 4824 : 1 +state 4256 observe0Greater1 observeOnlyTrueSender + action 0 + 4825 : 0.833 + 4826 : 0.167 +state 4257 observe0Greater1 observeOnlyTrueSender + action 0 + 4827 : 1 +state 4258 observe0Greater1 observeOnlyTrueSender + action 0 + 4828 : 0.833 + 4829 : 0.167 +state 4259 observe0Greater1 observeOnlyTrueSender + action 0 + 4830 : 1 +state 4260 observe0Greater1 observeOnlyTrueSender + action 0 + 4831 : 0.833 + 4832 : 0.167 +state 4261 observe0Greater1 observeOnlyTrueSender + action 0 + 4833 : 1 +state 4262 observe0Greater1 observeOnlyTrueSender + action 0 + 4834 : 0.833 + 4835 : 0.167 +state 4263 observe0Greater1 observeOnlyTrueSender + action 0 + 4836 : 1 +state 4264 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4264 : 1 +state 4265 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4265 : 1 +state 4266 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4266 : 1 +state 4267 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4267 : 1 +state 4268 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4268 : 1 +state 4269 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4270 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4271 observe3Greater1 observeIGreater1 + action 0 + 4838 : 1 +state 4272 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4273 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4274 observe3Greater1 observeIGreater1 + action 0 + 4839 : 1 +state 4275 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4276 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4277 observe3Greater1 observeIGreater1 + action 0 + 4840 : 1 +state 4278 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4279 observe3Greater1 observeIGreater1 + action 0 + 3100 : 0.2 + 3101 : 0.2 + 3102 : 0.2 + 3103 : 0.2 + 3104 : 0.2 +state 4280 observe3Greater1 observeIGreater1 + action 0 + 4841 : 1 +state 4281 observe3Greater1 observeIGreater1 + action 0 + 4837 : 1 +state 4282 observe3Greater1 observeIGreater1 + action 0 + 4842 : 0.833 + 4843 : 0.167 +state 4283 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4284 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4285 observe3Greater1 observeIGreater1 + action 0 + 4845 : 1 +state 4286 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4287 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4288 observe3Greater1 observeIGreater1 + action 0 + 4846 : 1 +state 4289 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4290 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4291 observe3Greater1 observeIGreater1 + action 0 + 4847 : 1 +state 4292 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4293 observe3Greater1 observeIGreater1 + action 0 + 3106 : 0.2 + 3107 : 0.2 + 3108 : 0.2 + 3109 : 0.2 + 3110 : 0.2 +state 4294 observe3Greater1 observeIGreater1 + action 0 + 4848 : 1 +state 4295 observe3Greater1 observeIGreater1 + action 0 + 4844 : 1 +state 4296 observe3Greater1 observeIGreater1 + action 0 + 4849 : 0.833 + 4850 : 0.167 +state 4297 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3117 : 0.833 + 3118 : 0.167 +state 4298 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4851 : 1 +state 4299 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4852 : 0.833 + 4853 : 0.167 +state 4300 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4854 : 1 +state 4301 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4855 : 0.833 + 4856 : 0.167 +state 4302 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4857 : 1 +state 4303 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4858 : 0.833 + 4859 : 0.167 +state 4304 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4860 : 1 +state 4305 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4861 : 0.833 + 4862 : 0.167 +state 4306 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4863 : 1 +state 4307 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4307 : 1 +state 4308 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4309 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4310 observe4Greater1 observeIGreater1 + action 0 + 4865 : 1 +state 4311 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4312 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4313 observe4Greater1 observeIGreater1 + action 0 + 4866 : 1 +state 4314 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4315 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4316 observe4Greater1 observeIGreater1 + action 0 + 4867 : 1 +state 4317 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4318 observe4Greater1 observeIGreater1 + action 0 + 3119 : 0.2 + 3120 : 0.2 + 3121 : 0.2 + 3122 : 0.2 + 3123 : 0.2 +state 4319 observe4Greater1 observeIGreater1 + action 0 + 4868 : 1 +state 4320 observe4Greater1 observeIGreater1 + action 0 + 4864 : 1 +state 4321 observe4Greater1 observeIGreater1 + action 0 + 4869 : 0.833 + 4870 : 0.167 +state 4322 observe0Greater1 observeOnlyTrueSender + action 0 + 3130 : 0.833 + 3131 : 0.167 +state 4323 observe0Greater1 observeOnlyTrueSender + action 0 + 4871 : 1 +state 4324 observe0Greater1 observeOnlyTrueSender + action 0 + 4872 : 0.833 + 4873 : 0.167 +state 4325 observe0Greater1 observeOnlyTrueSender + action 0 + 4874 : 1 +state 4326 observe0Greater1 observeOnlyTrueSender + action 0 + 4875 : 0.833 + 4876 : 0.167 +state 4327 observe0Greater1 observeOnlyTrueSender + action 0 + 4877 : 1 +state 4328 observe0Greater1 observeOnlyTrueSender + action 0 + 4878 : 0.833 + 4879 : 0.167 +state 4329 observe0Greater1 observeOnlyTrueSender + action 0 + 4880 : 1 +state 4330 observe0Greater1 observeOnlyTrueSender + action 0 + 4881 : 0.833 + 4882 : 0.167 +state 4331 observe0Greater1 observeOnlyTrueSender + action 0 + 4883 : 1 +state 4332 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4332 : 1 +state 4333 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4333 : 1 +state 4334 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4334 : 1 +state 4335 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4335 : 1 +state 4336 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4336 : 1 +state 4337 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4338 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4339 observe4Greater1 observeIGreater1 + action 0 + 4885 : 1 +state 4340 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4341 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4342 observe4Greater1 observeIGreater1 + action 0 + 4886 : 1 +state 4343 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4344 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4345 observe4Greater1 observeIGreater1 + action 0 + 4887 : 1 +state 4346 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4347 observe4Greater1 observeIGreater1 + action 0 + 3145 : 0.2 + 3146 : 0.2 + 3147 : 0.2 + 3148 : 0.2 + 3149 : 0.2 +state 4348 observe4Greater1 observeIGreater1 + action 0 + 4888 : 1 +state 4349 observe4Greater1 observeIGreater1 + action 0 + 4884 : 1 +state 4350 observe4Greater1 observeIGreater1 + action 0 + 4889 : 0.833 + 4890 : 0.167 +state 4351 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3156 : 0.833 + 3157 : 0.167 +state 4352 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4891 : 1 +state 4353 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4892 : 0.833 + 4893 : 0.167 +state 4354 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4894 : 1 +state 4355 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4895 : 0.833 + 4896 : 0.167 +state 4356 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4897 : 1 +state 4357 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4898 : 0.833 + 4899 : 0.167 +state 4358 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4900 : 1 +state 4359 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4901 : 0.833 + 4902 : 0.167 +state 4360 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4903 : 1 +state 4361 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4361 : 1 +state 4362 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4362 : 1 +state 4363 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4363 : 1 +state 4364 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4364 : 1 +state 4365 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4365 : 1 +state 4366 deadlock + action 0 + 4366 : 1 +state 4367 deadlock + action 0 + 4367 : 1 +state 4368 deadlock + action 0 + 4368 : 1 +state 4369 deadlock + action 0 + 4369 : 1 +state 4370 deadlock + action 0 + 4370 : 1 +state 4371 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4372 + action 0 + 4904 : 1 +state 4373 deadlock + action 0 + 4373 : 1 +state 4374 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4375 + action 0 + 4905 : 1 +state 4376 deadlock + action 0 + 4376 : 1 +state 4377 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4378 + action 0 + 4906 : 1 +state 4379 deadlock + action 0 + 4379 : 1 +state 4380 + action 0 + 3184 : 0.2 + 3185 : 0.2 + 3186 : 0.2 + 3187 : 0.2 + 3188 : 0.2 +state 4381 + action 0 + 4907 : 1 +state 4382 deadlock + action 0 + 4382 : 1 +state 4383 deadlock + action 0 + 4383 : 1 +state 4384 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4385 + action 0 + 4908 : 1 +state 4386 deadlock + action 0 + 4386 : 1 +state 4387 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4388 + action 0 + 4909 : 1 +state 4389 deadlock + action 0 + 4389 : 1 +state 4390 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4391 + action 0 + 4910 : 1 +state 4392 deadlock + action 0 + 4392 : 1 +state 4393 + action 0 + 3190 : 0.2 + 3191 : 0.2 + 3192 : 0.2 + 3193 : 0.2 + 3194 : 0.2 +state 4394 + action 0 + 4911 : 1 +state 4395 deadlock + action 0 + 4395 : 1 +state 4396 deadlock + action 0 + 4396 : 1 +state 4397 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4398 + action 0 + 4912 : 1 +state 4399 deadlock + action 0 + 4399 : 1 +state 4400 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4401 + action 0 + 4913 : 1 +state 4402 deadlock + action 0 + 4402 : 1 +state 4403 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4404 + action 0 + 4914 : 1 +state 4405 deadlock + action 0 + 4405 : 1 +state 4406 + action 0 + 3196 : 0.2 + 3197 : 0.2 + 3198 : 0.2 + 3199 : 0.2 + 3200 : 0.2 +state 4407 + action 0 + 4915 : 1 +state 4408 deadlock + action 0 + 4408 : 1 +state 4409 deadlock + action 0 + 4409 : 1 +state 4410 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4411 + action 0 + 4916 : 1 +state 4412 deadlock + action 0 + 4412 : 1 +state 4413 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4414 + action 0 + 4917 : 1 +state 4415 deadlock + action 0 + 4415 : 1 +state 4416 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4417 + action 0 + 4918 : 1 +state 4418 deadlock + action 0 + 4418 : 1 +state 4419 + action 0 + 3202 : 0.2 + 3203 : 0.2 + 3204 : 0.2 + 3205 : 0.2 + 3206 : 0.2 +state 4420 + action 0 + 4919 : 1 +state 4421 deadlock + action 0 + 4421 : 1 +state 4422 observe1Greater1 observeIGreater1 + action 0 + 3266 : 0.8 + 4920 : 0.2 +state 4423 observe1Greater1 observeIGreater1 + action 0 + 4921 : 0.8 + 4922 : 0.2 +state 4424 observe1Greater1 observeIGreater1 + action 0 + 4923 : 0.8 + 4924 : 0.2 +state 4425 observe1Greater1 observeIGreater1 + action 0 + 4925 : 0.8 + 4926 : 0.2 +state 4426 observe1Greater1 observeIGreater1 + action 0 + 4927 : 0.8 + 4928 : 0.2 +state 4427 observe1Greater1 observeIGreater1 + action 0 + 4929 : 1 +state 4428 + action 0 + 3273 : 0.8 + 4930 : 0.2 +state 4429 + action 0 + 4931 : 0.8 + 4932 : 0.2 +state 4430 + action 0 + 4933 : 0.8 + 4934 : 0.2 +state 4431 + action 0 + 4935 : 0.8 + 4936 : 0.2 +state 4432 + action 0 + 4937 : 0.8 + 4938 : 0.2 +state 4433 + action 0 + 4939 : 1 +state 4434 + action 0 + 3280 : 0.8 + 4940 : 0.2 +state 4435 + action 0 + 4941 : 0.8 + 4942 : 0.2 +state 4436 + action 0 + 4943 : 0.8 + 4944 : 0.2 +state 4437 + action 0 + 4945 : 0.8 + 4946 : 0.2 +state 4438 + action 0 + 4947 : 0.8 + 4948 : 0.2 +state 4439 + action 0 + 4949 : 1 +state 4440 + action 0 + 3287 : 0.8 + 4950 : 0.2 +state 4441 + action 0 + 4951 : 0.8 + 4952 : 0.2 +state 4442 + action 0 + 4953 : 0.8 + 4954 : 0.2 +state 4443 + action 0 + 4955 : 0.8 + 4956 : 0.2 +state 4444 + action 0 + 4957 : 0.8 + 4958 : 0.2 +state 4445 + action 0 + 4959 : 1 +state 4446 observe1Greater1 observeIGreater1 + action 0 + 4960 : 1 +state 4447 + action 0 + 4961 : 1 +state 4448 + action 0 + 4962 : 1 +state 4449 + action 0 + 4963 : 1 +state 4450 observe2Greater1 observeIGreater1 + action 0 + 3307 : 0.8 + 4964 : 0.2 +state 4451 observe2Greater1 observeIGreater1 + action 0 + 4965 : 0.8 + 4966 : 0.2 +state 4452 observe2Greater1 observeIGreater1 + action 0 + 4967 : 0.8 + 4968 : 0.2 +state 4453 observe2Greater1 observeIGreater1 + action 0 + 4969 : 0.8 + 4970 : 0.2 +state 4454 observe2Greater1 observeIGreater1 + action 0 + 4971 : 0.8 + 4972 : 0.2 +state 4455 observe2Greater1 observeIGreater1 + action 0 + 4973 : 1 +state 4456 + action 0 + 3314 : 0.8 + 4974 : 0.2 +state 4457 + action 0 + 4975 : 0.8 + 4976 : 0.2 +state 4458 + action 0 + 4977 : 0.8 + 4978 : 0.2 +state 4459 + action 0 + 4979 : 0.8 + 4980 : 0.2 +state 4460 + action 0 + 4981 : 0.8 + 4982 : 0.2 +state 4461 + action 0 + 4983 : 1 +state 4462 + action 0 + 3321 : 0.8 + 4984 : 0.2 +state 4463 + action 0 + 4985 : 0.8 + 4986 : 0.2 +state 4464 + action 0 + 4987 : 0.8 + 4988 : 0.2 +state 4465 + action 0 + 4989 : 0.8 + 4990 : 0.2 +state 4466 + action 0 + 4991 : 0.8 + 4992 : 0.2 +state 4467 + action 0 + 4993 : 1 +state 4468 + action 0 + 4994 : 1 +state 4469 observe2Greater1 observeIGreater1 + action 0 + 4995 : 1 +state 4470 + action 0 + 4996 : 1 +state 4471 + action 0 + 4997 : 1 +state 4472 observe3Greater1 observeIGreater1 + action 0 + 3341 : 0.8 + 4998 : 0.2 +state 4473 observe3Greater1 observeIGreater1 + action 0 + 4999 : 0.8 + 5000 : 0.2 +state 4474 observe3Greater1 observeIGreater1 + action 0 + 5001 : 0.8 + 5002 : 0.2 +state 4475 observe3Greater1 observeIGreater1 + action 0 + 5003 : 0.8 + 5004 : 0.2 +state 4476 observe3Greater1 observeIGreater1 + action 0 + 5005 : 0.8 + 5006 : 0.2 +state 4477 observe3Greater1 observeIGreater1 + action 0 + 5007 : 1 +state 4478 + action 0 + 3348 : 0.8 + 5008 : 0.2 +state 4479 + action 0 + 5009 : 0.8 + 5010 : 0.2 +state 4480 + action 0 + 5011 : 0.8 + 5012 : 0.2 +state 4481 + action 0 + 5013 : 0.8 + 5014 : 0.2 +state 4482 + action 0 + 5015 : 0.8 + 5016 : 0.2 +state 4483 + action 0 + 5017 : 1 +state 4484 + action 0 + 5018 : 1 +state 4485 + action 0 + 5019 : 1 +state 4486 observe3Greater1 observeIGreater1 + action 0 + 5020 : 1 +state 4487 + action 0 + 5021 : 1 +state 4488 observe4Greater1 observeIGreater1 + action 0 + 3368 : 0.8 + 5022 : 0.2 +state 4489 observe4Greater1 observeIGreater1 + action 0 + 5023 : 0.8 + 5024 : 0.2 +state 4490 observe4Greater1 observeIGreater1 + action 0 + 5025 : 0.8 + 5026 : 0.2 +state 4491 observe4Greater1 observeIGreater1 + action 0 + 5027 : 0.8 + 5028 : 0.2 +state 4492 observe4Greater1 observeIGreater1 + action 0 + 5029 : 0.8 + 5030 : 0.2 +state 4493 observe4Greater1 observeIGreater1 + action 0 + 5031 : 1 +state 4494 + action 0 + 5032 : 1 +state 4495 + action 0 + 5033 : 1 +state 4496 + action 0 + 5034 : 1 +state 4497 observe4Greater1 observeIGreater1 + action 0 + 5035 : 1 +state 4498 observe1Greater1 observeIGreater1 + action 0 + 5036 : 0.833 + 5037 : 0.167 +state 4499 observe1Greater1 observeIGreater1 + action 0 + 5038 : 0.833 + 5039 : 0.167 +state 4500 observe1Greater1 observeIGreater1 + action 0 + 5040 : 0.833 + 5041 : 0.167 +state 4501 observe1Greater1 observeIGreater1 + action 0 + 5042 : 0.833 + 5043 : 0.167 +state 4502 observe1Greater1 observeIGreater1 + action 0 + 5044 : 1 +state 4503 observe1Greater1 observeIGreater1 + action 0 + 5045 : 0.833 + 5046 : 0.167 +state 4504 observe1Greater1 observeIGreater1 + action 0 + 5047 : 1 +state 4505 observe1Greater1 observeIGreater1 + action 0 + 5048 : 0.833 + 5049 : 0.167 +state 4506 observe1Greater1 observeIGreater1 + action 0 + 5050 : 1 +state 4507 observe1Greater1 observeIGreater1 + action 0 + 5051 : 0.833 + 5052 : 0.167 +state 4508 observe1Greater1 observeIGreater1 + action 0 + 5053 : 1 +state 4509 observe1Greater1 observeIGreater1 + action 0 + 5054 : 0.833 + 5055 : 0.167 +state 4510 observe1Greater1 observeIGreater1 + action 0 + 5056 : 1 +state 4511 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4511 : 1 +state 4512 observe2Greater1 observeIGreater1 + action 0 + 5057 : 0.833 + 5058 : 0.167 +state 4513 + action 0 + 5059 : 0.833 + 5060 : 0.167 +state 4514 + action 0 + 5061 : 0.833 + 5062 : 0.167 +state 4515 + action 0 + 5063 : 1 +state 4516 + action 0 + 5064 : 0.833 + 5065 : 0.167 +state 4517 + action 0 + 5066 : 1 +state 4518 + action 0 + 5067 : 0.833 + 5068 : 0.167 +state 4519 + action 0 + 5069 : 1 +state 4520 + action 0 + 5070 : 0.833 + 5071 : 0.167 +state 4521 + action 0 + 5072 : 1 +state 4522 + action 0 + 5073 : 0.833 + 5074 : 0.167 +state 4523 + action 0 + 5075 : 1 +state 4524 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4524 : 1 +state 4525 observe3Greater1 observeIGreater1 + action 0 + 5076 : 0.833 + 5077 : 0.167 +state 4526 + action 0 + 5078 : 0.833 + 5079 : 0.167 +state 4527 + action 0 + 5080 : 1 +state 4528 + action 0 + 5081 : 0.833 + 5082 : 0.167 +state 4529 + action 0 + 5083 : 1 +state 4530 + action 0 + 5084 : 0.833 + 5085 : 0.167 +state 4531 + action 0 + 5086 : 1 +state 4532 + action 0 + 5087 : 0.833 + 5088 : 0.167 +state 4533 + action 0 + 5089 : 1 +state 4534 + action 0 + 5090 : 0.833 + 5091 : 0.167 +state 4535 + action 0 + 5092 : 1 +state 4536 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4536 : 1 +state 4537 observe4Greater1 observeIGreater1 + action 0 + 5093 : 0.833 + 5094 : 0.167 +state 4538 + action 0 + 5095 : 1 +state 4539 + action 0 + 5096 : 0.833 + 5097 : 0.167 +state 4540 + action 0 + 5098 : 1 +state 4541 + action 0 + 5099 : 0.833 + 5100 : 0.167 +state 4542 + action 0 + 5101 : 1 +state 4543 + action 0 + 5102 : 0.833 + 5103 : 0.167 +state 4544 + action 0 + 5104 : 1 +state 4545 + action 0 + 5105 : 0.833 + 5106 : 0.167 +state 4546 + action 0 + 5107 : 1 +state 4547 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4547 : 1 +state 4548 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4548 : 1 +state 4549 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4549 : 1 +state 4550 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4550 : 1 +state 4551 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4551 : 1 +state 4552 observe2Greater1 observeIGreater1 + action 0 + 5108 : 0.833 + 5109 : 0.167 +state 4553 observe2Greater1 observeIGreater1 + action 0 + 5110 : 0.833 + 5111 : 0.167 +state 4554 observe2Greater1 observeIGreater1 + action 0 + 5112 : 0.833 + 5113 : 0.167 +state 4555 observe2Greater1 observeIGreater1 + action 0 + 5114 : 1 +state 4556 observe2Greater1 observeIGreater1 + action 0 + 5115 : 0.833 + 5116 : 0.167 +state 4557 observe2Greater1 observeIGreater1 + action 0 + 5117 : 1 +state 4558 observe2Greater1 observeIGreater1 + action 0 + 5118 : 0.833 + 5119 : 0.167 +state 4559 observe2Greater1 observeIGreater1 + action 0 + 5120 : 1 +state 4560 observe2Greater1 observeIGreater1 + action 0 + 5121 : 0.833 + 5122 : 0.167 +state 4561 observe2Greater1 observeIGreater1 + action 0 + 5123 : 1 +state 4562 observe2Greater1 observeIGreater1 + action 0 + 5124 : 0.833 + 5125 : 0.167 +state 4563 observe2Greater1 observeIGreater1 + action 0 + 5126 : 1 +state 4564 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4564 : 1 +state 4565 observe3Greater1 observeIGreater1 + action 0 + 5127 : 0.833 + 5128 : 0.167 +state 4566 + action 0 + 5129 : 0.833 + 5130 : 0.167 +state 4567 + action 0 + 5131 : 1 +state 4568 + action 0 + 5132 : 0.833 + 5133 : 0.167 +state 4569 + action 0 + 5134 : 1 +state 4570 + action 0 + 5135 : 0.833 + 5136 : 0.167 +state 4571 + action 0 + 5137 : 1 +state 4572 + action 0 + 5138 : 0.833 + 5139 : 0.167 +state 4573 + action 0 + 5140 : 1 +state 4574 + action 0 + 5141 : 0.833 + 5142 : 0.167 +state 4575 + action 0 + 5143 : 1 +state 4576 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4576 : 1 +state 4577 observe4Greater1 observeIGreater1 + action 0 + 5144 : 0.833 + 5145 : 0.167 +state 4578 + action 0 + 5146 : 1 +state 4579 + action 0 + 5147 : 0.833 + 5148 : 0.167 +state 4580 + action 0 + 5149 : 1 +state 4581 + action 0 + 5150 : 0.833 + 5151 : 0.167 +state 4582 + action 0 + 5152 : 1 +state 4583 + action 0 + 5153 : 0.833 + 5154 : 0.167 +state 4584 + action 0 + 5155 : 1 +state 4585 + action 0 + 5156 : 0.833 + 5157 : 0.167 +state 4586 + action 0 + 5158 : 1 +state 4587 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4587 : 1 +state 4588 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4588 : 1 +state 4589 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4589 : 1 +state 4590 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4590 : 1 +state 4591 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4591 : 1 +state 4592 observe3Greater1 observeIGreater1 + action 0 + 5159 : 0.833 + 5160 : 0.167 +state 4593 observe3Greater1 observeIGreater1 + action 0 + 5161 : 0.833 + 5162 : 0.167 +state 4594 observe3Greater1 observeIGreater1 + action 0 + 5163 : 1 +state 4595 observe3Greater1 observeIGreater1 + action 0 + 5164 : 0.833 + 5165 : 0.167 +state 4596 observe3Greater1 observeIGreater1 + action 0 + 5166 : 1 +state 4597 observe3Greater1 observeIGreater1 + action 0 + 5167 : 0.833 + 5168 : 0.167 +state 4598 observe3Greater1 observeIGreater1 + action 0 + 5169 : 1 +state 4599 observe3Greater1 observeIGreater1 + action 0 + 5170 : 0.833 + 5171 : 0.167 +state 4600 observe3Greater1 observeIGreater1 + action 0 + 5172 : 1 +state 4601 observe3Greater1 observeIGreater1 + action 0 + 5173 : 0.833 + 5174 : 0.167 +state 4602 observe3Greater1 observeIGreater1 + action 0 + 5175 : 1 +state 4603 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4603 : 1 +state 4604 observe4Greater1 observeIGreater1 + action 0 + 5176 : 0.833 + 5177 : 0.167 +state 4605 + action 0 + 5178 : 1 +state 4606 + action 0 + 5179 : 0.833 + 5180 : 0.167 +state 4607 + action 0 + 5181 : 1 +state 4608 + action 0 + 5182 : 0.833 + 5183 : 0.167 +state 4609 + action 0 + 5184 : 1 +state 4610 + action 0 + 5185 : 0.833 + 5186 : 0.167 +state 4611 + action 0 + 5187 : 1 +state 4612 + action 0 + 5188 : 0.833 + 5189 : 0.167 +state 4613 + action 0 + 5190 : 1 +state 4614 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4614 : 1 +state 4615 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4615 : 1 +state 4616 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4616 : 1 +state 4617 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4617 : 1 +state 4618 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4618 : 1 +state 4619 observe4Greater1 observeIGreater1 + action 0 + 5191 : 0.833 + 5192 : 0.167 +state 4620 observe4Greater1 observeIGreater1 + action 0 + 5193 : 1 +state 4621 observe4Greater1 observeIGreater1 + action 0 + 5194 : 0.833 + 5195 : 0.167 +state 4622 observe4Greater1 observeIGreater1 + action 0 + 5196 : 1 +state 4623 observe4Greater1 observeIGreater1 + action 0 + 5197 : 0.833 + 5198 : 0.167 +state 4624 observe4Greater1 observeIGreater1 + action 0 + 5199 : 1 +state 4625 observe4Greater1 observeIGreater1 + action 0 + 5200 : 0.833 + 5201 : 0.167 +state 4626 observe4Greater1 observeIGreater1 + action 0 + 5202 : 1 +state 4627 observe4Greater1 observeIGreater1 + action 0 + 5203 : 0.833 + 5204 : 0.167 +state 4628 observe4Greater1 observeIGreater1 + action 0 + 5205 : 1 +state 4629 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4629 : 1 +state 4630 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4630 : 1 +state 4631 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4631 : 1 +state 4632 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4632 : 1 +state 4633 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4633 : 1 +state 4634 observe1Greater1 observeIGreater1 + action 0 + 5036 : 0.833 + 5037 : 0.167 +state 4635 observe1Greater1 observeIGreater1 + action 0 + 5206 : 1 +state 4636 observe1Greater1 observeIGreater1 + action 0 + 5207 : 1 +state 4637 observe1Greater1 observeIGreater1 + action 0 + 5208 : 1 +state 4638 observe1Greater1 observeIGreater1 + action 0 + 5209 : 1 +state 4639 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 4640 observe1Greater1 observeIGreater1 + action 0 + 5215 : 1 +state 4641 observe1Greater1 observeIGreater1 + action 0 + 5038 : 0.833 + 5039 : 0.167 +state 4642 observe1Greater1 observeIGreater1 + action 0 + 5216 : 1 +state 4643 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5217 : 1 +state 4644 observe1Greater1 observeIGreater1 + action 0 + 5218 : 1 +state 4645 observe1Greater1 observeIGreater1 + action 0 + 5219 : 1 +state 4646 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 4647 observe1Greater1 observeIGreater1 + action 0 + 5225 : 1 +state 4648 observe1Greater1 observeIGreater1 + action 0 + 5040 : 0.833 + 5041 : 0.167 +state 4649 observe1Greater1 observeIGreater1 + action 0 + 5226 : 1 +state 4650 observe1Greater1 observeIGreater1 + action 0 + 5227 : 1 +state 4651 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5228 : 1 +state 4652 observe1Greater1 observeIGreater1 + action 0 + 5229 : 1 +state 4653 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 4654 observe1Greater1 observeIGreater1 + action 0 + 5235 : 1 +state 4655 observe1Greater1 observeIGreater1 + action 0 + 5042 : 0.833 + 5043 : 0.167 +state 4656 observe1Greater1 observeIGreater1 + action 0 + 5236 : 1 +state 4657 observe1Greater1 observeIGreater1 + action 0 + 5237 : 1 +state 4658 observe1Greater1 observeIGreater1 + action 0 + 5238 : 1 +state 4659 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5239 : 1 +state 4660 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 4661 observe1Greater1 observeIGreater1 + action 0 + 5245 : 1 +state 4662 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4662 : 1 +state 4663 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4664 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5246 : 1 +state 4665 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4665 : 1 +state 4666 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4667 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5247 : 1 +state 4668 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4668 : 1 +state 4669 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4670 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5248 : 1 +state 4671 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4671 : 1 +state 4672 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 3436 : 0.2 + 3437 : 0.2 + 3438 : 0.2 + 3439 : 0.2 + 3440 : 0.2 +state 4673 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5249 : 1 +state 4674 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 4674 : 1 +state 4675 observe2Greater1 observeIGreater1 + action 0 + 5057 : 0.833 + 5058 : 0.167 +state 4676 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5250 : 1 +state 4677 observe2Greater1 observeIGreater1 + action 0 + 5251 : 1 +state 4678 observe2Greater1 observeIGreater1 + action 0 + 5252 : 1 +state 4679 observe2Greater1 observeIGreater1 + action 0 + 5253 : 1 +state 4680 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 4681 observe2Greater1 observeIGreater1 + action 0 + 5259 : 1 +state 4682 + action 0 + 5059 : 0.833 + 5060 : 0.167 +state 4683 observe1Greater1 observeIGreater1 + action 0 + 5260 : 1 +state 4684 observe2Greater1 observeIGreater1 + action 0 + 5261 : 1 +state 4685 observe3Greater1 observeIGreater1 + action 0 + 5262 : 1 +state 4686 + action 0 + 5263 : 1 +state 4687 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 4688 + action 0 + 5269 : 1 +state 4689 + action 0 + 5061 : 0.833 + 5062 : 0.167 +state 4690 observe1Greater1 observeIGreater1 + action 0 + 5270 : 1 +state 4691 observe2Greater1 observeIGreater1 + action 0 + 5271 : 1 +state 4692 + action 0 + 5272 : 1 +state 4693 observe4Greater1 observeIGreater1 + action 0 + 5273 : 1 +state 4694 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 4695 + action 0 + 5279 : 1 +state 4696 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4696 : 1 +state 4697 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4698 observe0Greater1 observeOnlyTrueSender + action 0 + 5280 : 1 +state 4699 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4699 : 1 +state 4700 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4701 observe0Greater1 observeOnlyTrueSender + action 0 + 5281 : 1 +state 4702 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4702 : 1 +state 4703 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4704 observe0Greater1 observeOnlyTrueSender + action 0 + 5282 : 1 +state 4705 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4705 : 1 +state 4706 observe0Greater1 observeOnlyTrueSender + action 0 + 3479 : 0.2 + 3480 : 0.2 + 3481 : 0.2 + 3482 : 0.2 + 3483 : 0.2 +state 4707 observe0Greater1 observeOnlyTrueSender + action 0 + 5283 : 1 +state 4708 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4708 : 1 +state 4709 observe3Greater1 observeIGreater1 + action 0 + 5076 : 0.833 + 5077 : 0.167 +state 4710 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5284 : 1 +state 4711 observe3Greater1 observeIGreater1 + action 0 + 5285 : 1 +state 4712 observe3Greater1 observeIGreater1 + action 0 + 5286 : 1 +state 4713 observe3Greater1 observeIGreater1 + action 0 + 5287 : 1 +state 4714 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 4715 observe3Greater1 observeIGreater1 + action 0 + 5293 : 1 +state 4716 + action 0 + 5078 : 0.833 + 5079 : 0.167 +state 4717 observe1Greater1 observeIGreater1 + action 0 + 5294 : 1 +state 4718 + action 0 + 5295 : 1 +state 4719 observe3Greater1 observeIGreater1 + action 0 + 5296 : 1 +state 4720 observe4Greater1 observeIGreater1 + action 0 + 5297 : 1 +state 4721 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 4722 + action 0 + 5303 : 1 +state 4723 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4723 : 1 +state 4724 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4725 observe0Greater1 observeOnlyTrueSender + action 0 + 5304 : 1 +state 4726 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4726 : 1 +state 4727 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4728 observe0Greater1 observeOnlyTrueSender + action 0 + 5305 : 1 +state 4729 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4729 : 1 +state 4730 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4731 observe0Greater1 observeOnlyTrueSender + action 0 + 5306 : 1 +state 4732 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4732 : 1 +state 4733 observe0Greater1 observeOnlyTrueSender + action 0 + 3511 : 0.2 + 3512 : 0.2 + 3513 : 0.2 + 3514 : 0.2 + 3515 : 0.2 +state 4734 observe0Greater1 observeOnlyTrueSender + action 0 + 5307 : 1 +state 4735 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4735 : 1 +state 4736 observe4Greater1 observeIGreater1 + action 0 + 5093 : 0.833 + 5094 : 0.167 +state 4737 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5308 : 1 +state 4738 observe4Greater1 observeIGreater1 + action 0 + 5309 : 1 +state 4739 observe4Greater1 observeIGreater1 + action 0 + 5310 : 1 +state 4740 observe4Greater1 observeIGreater1 + action 0 + 5311 : 1 +state 4741 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 4742 observe4Greater1 observeIGreater1 + action 0 + 5317 : 1 +state 4743 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4743 : 1 +state 4744 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4745 observe0Greater1 observeOnlyTrueSender + action 0 + 5318 : 1 +state 4746 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4746 : 1 +state 4747 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4748 observe0Greater1 observeOnlyTrueSender + action 0 + 5319 : 1 +state 4749 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4749 : 1 +state 4750 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4751 observe0Greater1 observeOnlyTrueSender + action 0 + 5320 : 1 +state 4752 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4752 : 1 +state 4753 observe0Greater1 observeOnlyTrueSender + action 0 + 3532 : 0.2 + 3533 : 0.2 + 3534 : 0.2 + 3535 : 0.2 + 3536 : 0.2 +state 4754 observe0Greater1 observeOnlyTrueSender + action 0 + 5321 : 1 +state 4755 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4755 : 1 +state 4756 observe2Greater1 observeIGreater1 + action 0 + 5108 : 0.833 + 5109 : 0.167 +state 4757 observe2Greater1 observeIGreater1 + action 0 + 5322 : 1 +state 4758 observe2Greater1 observeIGreater1 + action 0 + 5323 : 1 +state 4759 observe2Greater1 observeIGreater1 + action 0 + 5324 : 1 +state 4760 observe2Greater1 observeIGreater1 + action 0 + 5325 : 1 +state 4761 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 4762 observe2Greater1 observeIGreater1 + action 0 + 5331 : 1 +state 4763 observe2Greater1 observeIGreater1 + action 0 + 5110 : 0.833 + 5111 : 0.167 +state 4764 observe2Greater1 observeIGreater1 + action 0 + 5332 : 1 +state 4765 observe2Greater1 observeIGreater1 + action 0 + 5333 : 1 +state 4766 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5334 : 1 +state 4767 observe2Greater1 observeIGreater1 + action 0 + 5335 : 1 +state 4768 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 4769 observe2Greater1 observeIGreater1 + action 0 + 5341 : 1 +state 4770 observe2Greater1 observeIGreater1 + action 0 + 5112 : 0.833 + 5113 : 0.167 +state 4771 observe2Greater1 observeIGreater1 + action 0 + 5342 : 1 +state 4772 observe2Greater1 observeIGreater1 + action 0 + 5343 : 1 +state 4773 observe2Greater1 observeIGreater1 + action 0 + 5344 : 1 +state 4774 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5345 : 1 +state 4775 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 4776 observe2Greater1 observeIGreater1 + action 0 + 5351 : 1 +state 4777 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4777 : 1 +state 4778 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4779 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5352 : 1 +state 4780 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4780 : 1 +state 4781 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4782 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5353 : 1 +state 4783 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4783 : 1 +state 4784 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4785 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5354 : 1 +state 4786 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4786 : 1 +state 4787 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 3579 : 0.2 + 3580 : 0.2 + 3581 : 0.2 + 3582 : 0.2 + 3583 : 0.2 +state 4788 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5355 : 1 +state 4789 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 4789 : 1 +state 4790 observe3Greater1 observeIGreater1 + action 0 + 5127 : 0.833 + 5128 : 0.167 +state 4791 observe3Greater1 observeIGreater1 + action 0 + 5356 : 1 +state 4792 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5357 : 1 +state 4793 observe3Greater1 observeIGreater1 + action 0 + 5358 : 1 +state 4794 observe3Greater1 observeIGreater1 + action 0 + 5359 : 1 +state 4795 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 4796 observe3Greater1 observeIGreater1 + action 0 + 5365 : 1 +state 4797 + action 0 + 5129 : 0.833 + 5130 : 0.167 +state 4798 + action 0 + 5366 : 1 +state 4799 observe2Greater1 observeIGreater1 + action 0 + 5367 : 1 +state 4800 observe3Greater1 observeIGreater1 + action 0 + 5368 : 1 +state 4801 observe4Greater1 observeIGreater1 + action 0 + 5369 : 1 +state 4802 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 4803 + action 0 + 5375 : 1 +state 4804 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4804 : 1 +state 4805 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4806 observe0Greater1 observeOnlyTrueSender + action 0 + 5376 : 1 +state 4807 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4807 : 1 +state 4808 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4809 observe0Greater1 observeOnlyTrueSender + action 0 + 5377 : 1 +state 4810 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4810 : 1 +state 4811 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4812 observe0Greater1 observeOnlyTrueSender + action 0 + 5378 : 1 +state 4813 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4813 : 1 +state 4814 observe0Greater1 observeOnlyTrueSender + action 0 + 3611 : 0.2 + 3612 : 0.2 + 3613 : 0.2 + 3614 : 0.2 + 3615 : 0.2 +state 4815 observe0Greater1 observeOnlyTrueSender + action 0 + 5379 : 1 +state 4816 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4816 : 1 +state 4817 observe4Greater1 observeIGreater1 + action 0 + 5144 : 0.833 + 5145 : 0.167 +state 4818 observe4Greater1 observeIGreater1 + action 0 + 5380 : 1 +state 4819 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5381 : 1 +state 4820 observe4Greater1 observeIGreater1 + action 0 + 5382 : 1 +state 4821 observe4Greater1 observeIGreater1 + action 0 + 5383 : 1 +state 4822 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 4823 observe4Greater1 observeIGreater1 + action 0 + 5389 : 1 +state 4824 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4824 : 1 +state 4825 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4826 observe0Greater1 observeOnlyTrueSender + action 0 + 5390 : 1 +state 4827 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4827 : 1 +state 4828 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4829 observe0Greater1 observeOnlyTrueSender + action 0 + 5391 : 1 +state 4830 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4830 : 1 +state 4831 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4832 observe0Greater1 observeOnlyTrueSender + action 0 + 5392 : 1 +state 4833 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4833 : 1 +state 4834 observe0Greater1 observeOnlyTrueSender + action 0 + 3632 : 0.2 + 3633 : 0.2 + 3634 : 0.2 + 3635 : 0.2 + 3636 : 0.2 +state 4835 observe0Greater1 observeOnlyTrueSender + action 0 + 5393 : 1 +state 4836 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4836 : 1 +state 4837 observe3Greater1 observeIGreater1 + action 0 + 5159 : 0.833 + 5160 : 0.167 +state 4838 observe3Greater1 observeIGreater1 + action 0 + 5394 : 1 +state 4839 observe3Greater1 observeIGreater1 + action 0 + 5395 : 1 +state 4840 observe3Greater1 observeIGreater1 + action 0 + 5396 : 1 +state 4841 observe3Greater1 observeIGreater1 + action 0 + 5397 : 1 +state 4842 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 4843 observe3Greater1 observeIGreater1 + action 0 + 5403 : 1 +state 4844 observe3Greater1 observeIGreater1 + action 0 + 5161 : 0.833 + 5162 : 0.167 +state 4845 observe3Greater1 observeIGreater1 + action 0 + 5404 : 1 +state 4846 observe3Greater1 observeIGreater1 + action 0 + 5405 : 1 +state 4847 observe3Greater1 observeIGreater1 + action 0 + 5406 : 1 +state 4848 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5407 : 1 +state 4849 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 4850 observe3Greater1 observeIGreater1 + action 0 + 5413 : 1 +state 4851 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4851 : 1 +state 4852 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4853 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5414 : 1 +state 4854 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4854 : 1 +state 4855 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4856 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5415 : 1 +state 4857 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4857 : 1 +state 4858 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4859 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5416 : 1 +state 4860 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4860 : 1 +state 4861 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 3668 : 0.2 + 3669 : 0.2 + 3670 : 0.2 + 3671 : 0.2 + 3672 : 0.2 +state 4862 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5417 : 1 +state 4863 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 4863 : 1 +state 4864 observe4Greater1 observeIGreater1 + action 0 + 5176 : 0.833 + 5177 : 0.167 +state 4865 observe4Greater1 observeIGreater1 + action 0 + 5418 : 1 +state 4866 observe4Greater1 observeIGreater1 + action 0 + 5419 : 1 +state 4867 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5420 : 1 +state 4868 observe4Greater1 observeIGreater1 + action 0 + 5421 : 1 +state 4869 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 4870 observe4Greater1 observeIGreater1 + action 0 + 5427 : 1 +state 4871 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4871 : 1 +state 4872 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4873 observe0Greater1 observeOnlyTrueSender + action 0 + 5428 : 1 +state 4874 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4874 : 1 +state 4875 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4876 observe0Greater1 observeOnlyTrueSender + action 0 + 5429 : 1 +state 4877 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4877 : 1 +state 4878 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4879 observe0Greater1 observeOnlyTrueSender + action 0 + 5430 : 1 +state 4880 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4880 : 1 +state 4881 observe0Greater1 observeOnlyTrueSender + action 0 + 3689 : 0.2 + 3690 : 0.2 + 3691 : 0.2 + 3692 : 0.2 + 3693 : 0.2 +state 4882 observe0Greater1 observeOnlyTrueSender + action 0 + 5431 : 1 +state 4883 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 4883 : 1 +state 4884 observe4Greater1 observeIGreater1 + action 0 + 5191 : 0.833 + 5192 : 0.167 +state 4885 observe4Greater1 observeIGreater1 + action 0 + 5432 : 1 +state 4886 observe4Greater1 observeIGreater1 + action 0 + 5433 : 1 +state 4887 observe4Greater1 observeIGreater1 + action 0 + 5434 : 1 +state 4888 observe4Greater1 observeIGreater1 + action 0 + 5435 : 1 +state 4889 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 4890 observe4Greater1 observeIGreater1 + action 0 + 5441 : 1 +state 4891 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4891 : 1 +state 4892 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4893 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5442 : 1 +state 4894 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4894 : 1 +state 4895 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4896 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5443 : 1 +state 4897 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4897 : 1 +state 4898 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4899 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5444 : 1 +state 4900 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4900 : 1 +state 4901 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 3714 : 0.2 + 3715 : 0.2 + 3716 : 0.2 + 3717 : 0.2 + 3718 : 0.2 +state 4902 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5445 : 1 +state 4903 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 4903 : 1 +state 4904 observe1Greater1 observeIGreater1 + action 0 + 5446 : 1 +state 4905 + action 0 + 5447 : 1 +state 4906 + action 0 + 5448 : 1 +state 4907 + action 0 + 5449 : 1 +state 4908 + action 0 + 5450 : 1 +state 4909 observe2Greater1 observeIGreater1 + action 0 + 5451 : 1 +state 4910 + action 0 + 5452 : 1 +state 4911 + action 0 + 5453 : 1 +state 4912 + action 0 + 5454 : 1 +state 4913 + action 0 + 5455 : 1 +state 4914 observe3Greater1 observeIGreater1 + action 0 + 5456 : 1 +state 4915 + action 0 + 5457 : 1 +state 4916 + action 0 + 5458 : 1 +state 4917 + action 0 + 5459 : 1 +state 4918 + action 0 + 5460 : 1 +state 4919 observe4Greater1 observeIGreater1 + action 0 + 5461 : 1 +state 4920 observe1Greater1 observeIGreater1 + action 0 + 5462 : 1 +state 4921 observe1Greater1 observeIGreater1 + action 0 + 5463 : 0.833 + 5464 : 0.167 +state 4922 observe1Greater1 observeIGreater1 + action 0 + 5465 : 1 +state 4923 observe1Greater1 observeIGreater1 + action 0 + 5466 : 0.833 + 5467 : 0.167 +state 4924 observe1Greater1 observeIGreater1 + action 0 + 5468 : 1 +state 4925 observe1Greater1 observeIGreater1 + action 0 + 5469 : 0.833 + 5470 : 0.167 +state 4926 observe1Greater1 observeIGreater1 + action 0 + 5471 : 1 +state 4927 observe1Greater1 observeIGreater1 + action 0 + 5472 : 0.833 + 5473 : 0.167 +state 4928 observe1Greater1 observeIGreater1 + action 0 + 5474 : 1 +state 4929 deadlock observe1Greater1 observeIGreater1 + action 0 + 4929 : 1 +state 4930 + action 0 + 5475 : 1 +state 4931 + action 0 + 5476 : 0.833 + 5477 : 0.167 +state 4932 + action 0 + 5478 : 1 +state 4933 + action 0 + 5479 : 0.833 + 5480 : 0.167 +state 4934 + action 0 + 5481 : 1 +state 4935 + action 0 + 5482 : 0.833 + 5483 : 0.167 +state 4936 + action 0 + 5484 : 1 +state 4937 + action 0 + 5485 : 0.833 + 5486 : 0.167 +state 4938 + action 0 + 5487 : 1 +state 4939 deadlock + action 0 + 4939 : 1 +state 4940 + action 0 + 5488 : 1 +state 4941 + action 0 + 5489 : 0.833 + 5490 : 0.167 +state 4942 + action 0 + 5491 : 1 +state 4943 + action 0 + 5492 : 0.833 + 5493 : 0.167 +state 4944 + action 0 + 5494 : 1 +state 4945 + action 0 + 5495 : 0.833 + 5496 : 0.167 +state 4946 + action 0 + 5497 : 1 +state 4947 + action 0 + 5498 : 0.833 + 5499 : 0.167 +state 4948 + action 0 + 5500 : 1 +state 4949 deadlock + action 0 + 4949 : 1 +state 4950 + action 0 + 5501 : 1 +state 4951 + action 0 + 5502 : 0.833 + 5503 : 0.167 +state 4952 + action 0 + 5504 : 1 +state 4953 + action 0 + 5505 : 0.833 + 5506 : 0.167 +state 4954 + action 0 + 5507 : 1 +state 4955 + action 0 + 5508 : 0.833 + 5509 : 0.167 +state 4956 + action 0 + 5510 : 1 +state 4957 + action 0 + 5511 : 0.833 + 5512 : 0.167 +state 4958 + action 0 + 5513 : 1 +state 4959 deadlock + action 0 + 4959 : 1 +state 4960 deadlock observe1Greater1 observeIGreater1 + action 0 + 4960 : 1 +state 4961 deadlock + action 0 + 4961 : 1 +state 4962 deadlock + action 0 + 4962 : 1 +state 4963 deadlock + action 0 + 4963 : 1 +state 4964 observe2Greater1 observeIGreater1 + action 0 + 5514 : 1 +state 4965 observe2Greater1 observeIGreater1 + action 0 + 5515 : 0.833 + 5516 : 0.167 +state 4966 observe2Greater1 observeIGreater1 + action 0 + 5517 : 1 +state 4967 observe2Greater1 observeIGreater1 + action 0 + 5518 : 0.833 + 5519 : 0.167 +state 4968 observe2Greater1 observeIGreater1 + action 0 + 5520 : 1 +state 4969 observe2Greater1 observeIGreater1 + action 0 + 5521 : 0.833 + 5522 : 0.167 +state 4970 observe2Greater1 observeIGreater1 + action 0 + 5523 : 1 +state 4971 observe2Greater1 observeIGreater1 + action 0 + 5524 : 0.833 + 5525 : 0.167 +state 4972 observe2Greater1 observeIGreater1 + action 0 + 5526 : 1 +state 4973 deadlock observe2Greater1 observeIGreater1 + action 0 + 4973 : 1 +state 4974 + action 0 + 5527 : 1 +state 4975 + action 0 + 5528 : 0.833 + 5529 : 0.167 +state 4976 + action 0 + 5530 : 1 +state 4977 + action 0 + 5531 : 0.833 + 5532 : 0.167 +state 4978 + action 0 + 5533 : 1 +state 4979 + action 0 + 5534 : 0.833 + 5535 : 0.167 +state 4980 + action 0 + 5536 : 1 +state 4981 + action 0 + 5537 : 0.833 + 5538 : 0.167 +state 4982 + action 0 + 5539 : 1 +state 4983 deadlock + action 0 + 4983 : 1 +state 4984 + action 0 + 5540 : 1 +state 4985 + action 0 + 5541 : 0.833 + 5542 : 0.167 +state 4986 + action 0 + 5543 : 1 +state 4987 + action 0 + 5544 : 0.833 + 5545 : 0.167 +state 4988 + action 0 + 5546 : 1 +state 4989 + action 0 + 5547 : 0.833 + 5548 : 0.167 +state 4990 + action 0 + 5549 : 1 +state 4991 + action 0 + 5550 : 0.833 + 5551 : 0.167 +state 4992 + action 0 + 5552 : 1 +state 4993 deadlock + action 0 + 4993 : 1 +state 4994 deadlock + action 0 + 4994 : 1 +state 4995 deadlock observe2Greater1 observeIGreater1 + action 0 + 4995 : 1 +state 4996 deadlock + action 0 + 4996 : 1 +state 4997 deadlock + action 0 + 4997 : 1 +state 4998 observe3Greater1 observeIGreater1 + action 0 + 5553 : 1 +state 4999 observe3Greater1 observeIGreater1 + action 0 + 5554 : 0.833 + 5555 : 0.167 +state 5000 observe3Greater1 observeIGreater1 + action 0 + 5556 : 1 +state 5001 observe3Greater1 observeIGreater1 + action 0 + 5557 : 0.833 + 5558 : 0.167 +state 5002 observe3Greater1 observeIGreater1 + action 0 + 5559 : 1 +state 5003 observe3Greater1 observeIGreater1 + action 0 + 5560 : 0.833 + 5561 : 0.167 +state 5004 observe3Greater1 observeIGreater1 + action 0 + 5562 : 1 +state 5005 observe3Greater1 observeIGreater1 + action 0 + 5563 : 0.833 + 5564 : 0.167 +state 5006 observe3Greater1 observeIGreater1 + action 0 + 5565 : 1 +state 5007 deadlock observe3Greater1 observeIGreater1 + action 0 + 5007 : 1 +state 5008 + action 0 + 5566 : 1 +state 5009 + action 0 + 5567 : 0.833 + 5568 : 0.167 +state 5010 + action 0 + 5569 : 1 +state 5011 + action 0 + 5570 : 0.833 + 5571 : 0.167 +state 5012 + action 0 + 5572 : 1 +state 5013 + action 0 + 5573 : 0.833 + 5574 : 0.167 +state 5014 + action 0 + 5575 : 1 +state 5015 + action 0 + 5576 : 0.833 + 5577 : 0.167 +state 5016 + action 0 + 5578 : 1 +state 5017 deadlock + action 0 + 5017 : 1 +state 5018 deadlock + action 0 + 5018 : 1 +state 5019 deadlock + action 0 + 5019 : 1 +state 5020 deadlock observe3Greater1 observeIGreater1 + action 0 + 5020 : 1 +state 5021 deadlock + action 0 + 5021 : 1 +state 5022 observe4Greater1 observeIGreater1 + action 0 + 5579 : 1 +state 5023 observe4Greater1 observeIGreater1 + action 0 + 5580 : 0.833 + 5581 : 0.167 +state 5024 observe4Greater1 observeIGreater1 + action 0 + 5582 : 1 +state 5025 observe4Greater1 observeIGreater1 + action 0 + 5583 : 0.833 + 5584 : 0.167 +state 5026 observe4Greater1 observeIGreater1 + action 0 + 5585 : 1 +state 5027 observe4Greater1 observeIGreater1 + action 0 + 5586 : 0.833 + 5587 : 0.167 +state 5028 observe4Greater1 observeIGreater1 + action 0 + 5588 : 1 +state 5029 observe4Greater1 observeIGreater1 + action 0 + 5589 : 0.833 + 5590 : 0.167 +state 5030 observe4Greater1 observeIGreater1 + action 0 + 5591 : 1 +state 5031 deadlock observe4Greater1 observeIGreater1 + action 0 + 5031 : 1 +state 5032 deadlock + action 0 + 5032 : 1 +state 5033 deadlock + action 0 + 5033 : 1 +state 5034 deadlock + action 0 + 5034 : 1 +state 5035 deadlock observe4Greater1 observeIGreater1 + action 0 + 5035 : 1 +state 5036 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 5037 observe1Greater1 observeIGreater1 + action 0 + 5597 : 1 +state 5038 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 5039 observe1Greater1 observeIGreater1 + action 0 + 5603 : 1 +state 5040 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 5041 observe1Greater1 observeIGreater1 + action 0 + 5609 : 1 +state 5042 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 5043 observe1Greater1 observeIGreater1 + action 0 + 5615 : 1 +state 5044 deadlock observe1Greater1 observeIGreater1 + action 0 + 5044 : 1 +state 5045 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5046 observe1Greater1 observeIGreater1 + action 0 + 5616 : 1 +state 5047 deadlock observe1Greater1 observeIGreater1 + action 0 + 5047 : 1 +state 5048 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5049 observe1Greater1 observeIGreater1 + action 0 + 5617 : 1 +state 5050 deadlock observe1Greater1 observeIGreater1 + action 0 + 5050 : 1 +state 5051 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5052 observe1Greater1 observeIGreater1 + action 0 + 5618 : 1 +state 5053 deadlock observe1Greater1 observeIGreater1 + action 0 + 5053 : 1 +state 5054 observe1Greater1 observeIGreater1 + action 0 + 3848 : 0.2 + 3849 : 0.2 + 3850 : 0.2 + 3851 : 0.2 + 3852 : 0.2 +state 5055 observe1Greater1 observeIGreater1 + action 0 + 5619 : 1 +state 5056 deadlock observe1Greater1 observeIGreater1 + action 0 + 5056 : 1 +state 5057 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 5058 observe2Greater1 observeIGreater1 + action 0 + 5625 : 1 +state 5059 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 5060 + action 0 + 5631 : 1 +state 5061 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 5062 + action 0 + 5637 : 1 +state 5063 deadlock + action 0 + 5063 : 1 +state 5064 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5065 + action 0 + 5638 : 1 +state 5066 deadlock + action 0 + 5066 : 1 +state 5067 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5068 + action 0 + 5639 : 1 +state 5069 deadlock + action 0 + 5069 : 1 +state 5070 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5071 + action 0 + 5640 : 1 +state 5072 deadlock + action 0 + 5072 : 1 +state 5073 + action 0 + 3858 : 0.2 + 3859 : 0.2 + 3860 : 0.2 + 3861 : 0.2 + 3862 : 0.2 +state 5074 + action 0 + 5641 : 1 +state 5075 deadlock + action 0 + 5075 : 1 +state 5076 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 5077 observe3Greater1 observeIGreater1 + action 0 + 5647 : 1 +state 5078 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 5079 + action 0 + 5653 : 1 +state 5080 deadlock + action 0 + 5080 : 1 +state 5081 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5082 + action 0 + 5654 : 1 +state 5083 deadlock + action 0 + 5083 : 1 +state 5084 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5085 + action 0 + 5655 : 1 +state 5086 deadlock + action 0 + 5086 : 1 +state 5087 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5088 + action 0 + 5656 : 1 +state 5089 deadlock + action 0 + 5089 : 1 +state 5090 + action 0 + 3868 : 0.2 + 3869 : 0.2 + 3870 : 0.2 + 3871 : 0.2 + 3872 : 0.2 +state 5091 + action 0 + 5657 : 1 +state 5092 deadlock + action 0 + 5092 : 1 +state 5093 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 5094 observe4Greater1 observeIGreater1 + action 0 + 5663 : 1 +state 5095 deadlock + action 0 + 5095 : 1 +state 5096 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5097 + action 0 + 5664 : 1 +state 5098 deadlock + action 0 + 5098 : 1 +state 5099 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5100 + action 0 + 5665 : 1 +state 5101 deadlock + action 0 + 5101 : 1 +state 5102 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5103 + action 0 + 5666 : 1 +state 5104 deadlock + action 0 + 5104 : 1 +state 5105 + action 0 + 3878 : 0.2 + 3879 : 0.2 + 3880 : 0.2 + 3881 : 0.2 + 3882 : 0.2 +state 5106 + action 0 + 5667 : 1 +state 5107 deadlock + action 0 + 5107 : 1 +state 5108 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 5109 observe2Greater1 observeIGreater1 + action 0 + 5673 : 1 +state 5110 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 5111 observe2Greater1 observeIGreater1 + action 0 + 5679 : 1 +state 5112 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 5113 observe2Greater1 observeIGreater1 + action 0 + 5685 : 1 +state 5114 deadlock observe2Greater1 observeIGreater1 + action 0 + 5114 : 1 +state 5115 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5116 observe2Greater1 observeIGreater1 + action 0 + 5686 : 1 +state 5117 deadlock observe2Greater1 observeIGreater1 + action 0 + 5117 : 1 +state 5118 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5119 observe2Greater1 observeIGreater1 + action 0 + 5687 : 1 +state 5120 deadlock observe2Greater1 observeIGreater1 + action 0 + 5120 : 1 +state 5121 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5122 observe2Greater1 observeIGreater1 + action 0 + 5688 : 1 +state 5123 deadlock observe2Greater1 observeIGreater1 + action 0 + 5123 : 1 +state 5124 observe2Greater1 observeIGreater1 + action 0 + 3892 : 0.2 + 3893 : 0.2 + 3894 : 0.2 + 3895 : 0.2 + 3896 : 0.2 +state 5125 observe2Greater1 observeIGreater1 + action 0 + 5689 : 1 +state 5126 deadlock observe2Greater1 observeIGreater1 + action 0 + 5126 : 1 +state 5127 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 5128 observe3Greater1 observeIGreater1 + action 0 + 5695 : 1 +state 5129 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 5130 + action 0 + 5701 : 1 +state 5131 deadlock + action 0 + 5131 : 1 +state 5132 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5133 + action 0 + 5702 : 1 +state 5134 deadlock + action 0 + 5134 : 1 +state 5135 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5136 + action 0 + 5703 : 1 +state 5137 deadlock + action 0 + 5137 : 1 +state 5138 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5139 + action 0 + 5704 : 1 +state 5140 deadlock + action 0 + 5140 : 1 +state 5141 + action 0 + 3902 : 0.2 + 3903 : 0.2 + 3904 : 0.2 + 3905 : 0.2 + 3906 : 0.2 +state 5142 + action 0 + 5705 : 1 +state 5143 deadlock + action 0 + 5143 : 1 +state 5144 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 5145 observe4Greater1 observeIGreater1 + action 0 + 5711 : 1 +state 5146 deadlock + action 0 + 5146 : 1 +state 5147 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5148 + action 0 + 5712 : 1 +state 5149 deadlock + action 0 + 5149 : 1 +state 5150 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5151 + action 0 + 5713 : 1 +state 5152 deadlock + action 0 + 5152 : 1 +state 5153 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5154 + action 0 + 5714 : 1 +state 5155 deadlock + action 0 + 5155 : 1 +state 5156 + action 0 + 3912 : 0.2 + 3913 : 0.2 + 3914 : 0.2 + 3915 : 0.2 + 3916 : 0.2 +state 5157 + action 0 + 5715 : 1 +state 5158 deadlock + action 0 + 5158 : 1 +state 5159 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 5160 observe3Greater1 observeIGreater1 + action 0 + 5721 : 1 +state 5161 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 5162 observe3Greater1 observeIGreater1 + action 0 + 5727 : 1 +state 5163 deadlock observe3Greater1 observeIGreater1 + action 0 + 5163 : 1 +state 5164 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5165 observe3Greater1 observeIGreater1 + action 0 + 5728 : 1 +state 5166 deadlock observe3Greater1 observeIGreater1 + action 0 + 5166 : 1 +state 5167 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5168 observe3Greater1 observeIGreater1 + action 0 + 5729 : 1 +state 5169 deadlock observe3Greater1 observeIGreater1 + action 0 + 5169 : 1 +state 5170 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5171 observe3Greater1 observeIGreater1 + action 0 + 5730 : 1 +state 5172 deadlock observe3Greater1 observeIGreater1 + action 0 + 5172 : 1 +state 5173 observe3Greater1 observeIGreater1 + action 0 + 3926 : 0.2 + 3927 : 0.2 + 3928 : 0.2 + 3929 : 0.2 + 3930 : 0.2 +state 5174 observe3Greater1 observeIGreater1 + action 0 + 5731 : 1 +state 5175 deadlock observe3Greater1 observeIGreater1 + action 0 + 5175 : 1 +state 5176 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 5177 observe4Greater1 observeIGreater1 + action 0 + 5737 : 1 +state 5178 deadlock + action 0 + 5178 : 1 +state 5179 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5180 + action 0 + 5738 : 1 +state 5181 deadlock + action 0 + 5181 : 1 +state 5182 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5183 + action 0 + 5739 : 1 +state 5184 deadlock + action 0 + 5184 : 1 +state 5185 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5186 + action 0 + 5740 : 1 +state 5187 deadlock + action 0 + 5187 : 1 +state 5188 + action 0 + 3936 : 0.2 + 3937 : 0.2 + 3938 : 0.2 + 3939 : 0.2 + 3940 : 0.2 +state 5189 + action 0 + 5741 : 1 +state 5190 deadlock + action 0 + 5190 : 1 +state 5191 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 5192 observe4Greater1 observeIGreater1 + action 0 + 5747 : 1 +state 5193 deadlock observe4Greater1 observeIGreater1 + action 0 + 5193 : 1 +state 5194 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5195 observe4Greater1 observeIGreater1 + action 0 + 5748 : 1 +state 5196 deadlock observe4Greater1 observeIGreater1 + action 0 + 5196 : 1 +state 5197 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5198 observe4Greater1 observeIGreater1 + action 0 + 5749 : 1 +state 5199 deadlock observe4Greater1 observeIGreater1 + action 0 + 5199 : 1 +state 5200 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5201 observe4Greater1 observeIGreater1 + action 0 + 5750 : 1 +state 5202 deadlock observe4Greater1 observeIGreater1 + action 0 + 5202 : 1 +state 5203 observe4Greater1 observeIGreater1 + action 0 + 3950 : 0.2 + 3951 : 0.2 + 3952 : 0.2 + 3953 : 0.2 + 3954 : 0.2 +state 5204 observe4Greater1 observeIGreater1 + action 0 + 5751 : 1 +state 5205 deadlock observe4Greater1 observeIGreater1 + action 0 + 5205 : 1 +state 5206 observe1Greater1 observeIGreater1 + action 0 + 5752 : 1 +state 5207 observe1Greater1 observeIGreater1 + action 0 + 5753 : 1 +state 5208 observe1Greater1 observeIGreater1 + action 0 + 5754 : 1 +state 5209 observe1Greater1 observeIGreater1 + action 0 + 5755 : 1 +state 5210 observe1Greater1 observeIGreater1 + action 0 + 5756 : 0.8 + 5757 : 0.2 +state 5211 observe1Greater1 observeIGreater1 + action 0 + 5758 : 0.8 + 5759 : 0.2 +state 5212 observe1Greater1 observeIGreater1 + action 0 + 5760 : 0.8 + 5761 : 0.2 +state 5213 observe1Greater1 observeIGreater1 + action 0 + 5762 : 0.8 + 5763 : 0.2 +state 5214 observe1Greater1 observeIGreater1 + action 0 + 5764 : 0.8 + 5765 : 0.2 +state 5215 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5766 : 1 +state 5216 observe1Greater1 observeIGreater1 + action 0 + 5753 : 1 +state 5217 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5767 : 1 +state 5218 observe1Greater1 observeIGreater1 + action 0 + 5768 : 1 +state 5219 observe1Greater1 observeIGreater1 + action 0 + 5769 : 1 +state 5220 observe1Greater1 observeIGreater1 + action 0 + 5770 : 0.8 + 5771 : 0.2 +state 5221 observe1Greater1 observeIGreater1 + action 0 + 5772 : 0.8 + 5773 : 0.2 +state 5222 observe1Greater1 observeIGreater1 + action 0 + 5774 : 0.8 + 5775 : 0.2 +state 5223 observe1Greater1 observeIGreater1 + action 0 + 5776 : 0.8 + 5777 : 0.2 +state 5224 observe1Greater1 observeIGreater1 + action 0 + 5778 : 0.8 + 5779 : 0.2 +state 5225 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5780 : 1 +state 5226 observe1Greater1 observeIGreater1 + action 0 + 5754 : 1 +state 5227 observe1Greater1 observeIGreater1 + action 0 + 5768 : 1 +state 5228 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5781 : 1 +state 5229 observe1Greater1 observeIGreater1 + action 0 + 5782 : 1 +state 5230 observe1Greater1 observeIGreater1 + action 0 + 5783 : 0.8 + 5784 : 0.2 +state 5231 observe1Greater1 observeIGreater1 + action 0 + 5785 : 0.8 + 5786 : 0.2 +state 5232 observe1Greater1 observeIGreater1 + action 0 + 5787 : 0.8 + 5788 : 0.2 +state 5233 observe1Greater1 observeIGreater1 + action 0 + 5789 : 0.8 + 5790 : 0.2 +state 5234 observe1Greater1 observeIGreater1 + action 0 + 5791 : 0.8 + 5792 : 0.2 +state 5235 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5793 : 1 +state 5236 observe1Greater1 observeIGreater1 + action 0 + 5755 : 1 +state 5237 observe1Greater1 observeIGreater1 + action 0 + 5769 : 1 +state 5238 observe1Greater1 observeIGreater1 + action 0 + 5782 : 1 +state 5239 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5794 : 1 +state 5240 observe1Greater1 observeIGreater1 + action 0 + 5795 : 0.8 + 5796 : 0.2 +state 5241 observe1Greater1 observeIGreater1 + action 0 + 5797 : 0.8 + 5798 : 0.2 +state 5242 observe1Greater1 observeIGreater1 + action 0 + 5799 : 0.8 + 5800 : 0.2 +state 5243 observe1Greater1 observeIGreater1 + action 0 + 5801 : 0.8 + 5802 : 0.2 +state 5244 observe1Greater1 observeIGreater1 + action 0 + 5803 : 0.8 + 5804 : 0.2 +state 5245 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5805 : 1 +state 5246 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5806 : 1 +state 5247 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5807 : 1 +state 5248 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5808 : 1 +state 5249 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5809 : 1 +state 5250 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 5767 : 1 +state 5251 observe2Greater1 observeIGreater1 + action 0 + 5810 : 1 +state 5252 observe2Greater1 observeIGreater1 + action 0 + 5811 : 1 +state 5253 observe2Greater1 observeIGreater1 + action 0 + 5812 : 1 +state 5254 observe2Greater1 observeIGreater1 + action 0 + 5813 : 0.8 + 5814 : 0.2 +state 5255 observe2Greater1 observeIGreater1 + action 0 + 5815 : 0.8 + 5816 : 0.2 +state 5256 observe2Greater1 observeIGreater1 + action 0 + 5817 : 0.8 + 5818 : 0.2 +state 5257 observe2Greater1 observeIGreater1 + action 0 + 5819 : 0.8 + 5820 : 0.2 +state 5258 observe2Greater1 observeIGreater1 + action 0 + 5821 : 0.8 + 5822 : 0.2 +state 5259 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5823 : 1 +state 5260 observe1Greater1 observeIGreater1 + action 0 + 5768 : 1 +state 5261 observe2Greater1 observeIGreater1 + action 0 + 5811 : 1 +state 5262 observe3Greater1 observeIGreater1 + action 0 + 5824 : 1 +state 5263 + action 0 + 5825 : 1 +state 5264 + action 0 + 5826 : 0.8 + 5827 : 0.2 +state 5265 + action 0 + 5828 : 0.8 + 5829 : 0.2 +state 5266 + action 0 + 5830 : 0.8 + 5831 : 0.2 +state 5267 + action 0 + 5832 : 0.8 + 5833 : 0.2 +state 5268 + action 0 + 5834 : 0.8 + 5835 : 0.2 +state 5269 observe0Greater1 observeOnlyTrueSender + action 0 + 5836 : 1 +state 5270 observe1Greater1 observeIGreater1 + action 0 + 5769 : 1 +state 5271 observe2Greater1 observeIGreater1 + action 0 + 5812 : 1 +state 5272 + action 0 + 5825 : 1 +state 5273 observe4Greater1 observeIGreater1 + action 0 + 5837 : 1 +state 5274 + action 0 + 5838 : 0.8 + 5839 : 0.2 +state 5275 + action 0 + 5840 : 0.8 + 5841 : 0.2 +state 5276 + action 0 + 5842 : 0.8 + 5843 : 0.2 +state 5277 + action 0 + 5844 : 0.8 + 5845 : 0.2 +state 5278 + action 0 + 5846 : 0.8 + 5847 : 0.2 +state 5279 observe0Greater1 observeOnlyTrueSender + action 0 + 5848 : 1 +state 5280 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5849 : 1 +state 5281 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5850 : 1 +state 5282 observe0Greater1 observeOnlyTrueSender + action 0 + 5851 : 1 +state 5283 observe0Greater1 observeOnlyTrueSender + action 0 + 5852 : 1 +state 5284 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 5781 : 1 +state 5285 observe3Greater1 observeIGreater1 + action 0 + 5824 : 1 +state 5286 observe3Greater1 observeIGreater1 + action 0 + 5853 : 1 +state 5287 observe3Greater1 observeIGreater1 + action 0 + 5854 : 1 +state 5288 observe3Greater1 observeIGreater1 + action 0 + 5855 : 0.8 + 5856 : 0.2 +state 5289 observe3Greater1 observeIGreater1 + action 0 + 5857 : 0.8 + 5858 : 0.2 +state 5290 observe3Greater1 observeIGreater1 + action 0 + 5859 : 0.8 + 5860 : 0.2 +state 5291 observe3Greater1 observeIGreater1 + action 0 + 5861 : 0.8 + 5862 : 0.2 +state 5292 observe3Greater1 observeIGreater1 + action 0 + 5863 : 0.8 + 5864 : 0.2 +state 5293 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5865 : 1 +state 5294 observe1Greater1 observeIGreater1 + action 0 + 5782 : 1 +state 5295 + action 0 + 5825 : 1 +state 5296 observe3Greater1 observeIGreater1 + action 0 + 5854 : 1 +state 5297 observe4Greater1 observeIGreater1 + action 0 + 5866 : 1 +state 5298 + action 0 + 5867 : 0.8 + 5868 : 0.2 +state 5299 + action 0 + 5869 : 0.8 + 5870 : 0.2 +state 5300 + action 0 + 5871 : 0.8 + 5872 : 0.2 +state 5301 + action 0 + 5873 : 0.8 + 5874 : 0.2 +state 5302 + action 0 + 5875 : 0.8 + 5876 : 0.2 +state 5303 observe0Greater1 observeOnlyTrueSender + action 0 + 5877 : 1 +state 5304 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5878 : 1 +state 5305 observe0Greater1 observeOnlyTrueSender + action 0 + 5879 : 1 +state 5306 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5880 : 1 +state 5307 observe0Greater1 observeOnlyTrueSender + action 0 + 5881 : 1 +state 5308 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 5794 : 1 +state 5309 observe4Greater1 observeIGreater1 + action 0 + 5837 : 1 +state 5310 observe4Greater1 observeIGreater1 + action 0 + 5866 : 1 +state 5311 observe4Greater1 observeIGreater1 + action 0 + 5882 : 1 +state 5312 observe4Greater1 observeIGreater1 + action 0 + 5883 : 0.8 + 5884 : 0.2 +state 5313 observe4Greater1 observeIGreater1 + action 0 + 5885 : 0.8 + 5886 : 0.2 +state 5314 observe4Greater1 observeIGreater1 + action 0 + 5887 : 0.8 + 5888 : 0.2 +state 5315 observe4Greater1 observeIGreater1 + action 0 + 5889 : 0.8 + 5890 : 0.2 +state 5316 observe4Greater1 observeIGreater1 + action 0 + 5891 : 0.8 + 5892 : 0.2 +state 5317 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5893 : 1 +state 5318 observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5894 : 1 +state 5319 observe0Greater1 observeOnlyTrueSender + action 0 + 5895 : 1 +state 5320 observe0Greater1 observeOnlyTrueSender + action 0 + 5896 : 1 +state 5321 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5897 : 1 +state 5322 observe2Greater1 observeIGreater1 + action 0 + 5810 : 1 +state 5323 observe2Greater1 observeIGreater1 + action 0 + 5898 : 1 +state 5324 observe2Greater1 observeIGreater1 + action 0 + 5899 : 1 +state 5325 observe2Greater1 observeIGreater1 + action 0 + 5900 : 1 +state 5326 observe2Greater1 observeIGreater1 + action 0 + 5901 : 0.8 + 5902 : 0.2 +state 5327 observe2Greater1 observeIGreater1 + action 0 + 5903 : 0.8 + 5904 : 0.2 +state 5328 observe2Greater1 observeIGreater1 + action 0 + 5905 : 0.8 + 5906 : 0.2 +state 5329 observe2Greater1 observeIGreater1 + action 0 + 5907 : 0.8 + 5908 : 0.2 +state 5330 observe2Greater1 observeIGreater1 + action 0 + 5909 : 0.8 + 5910 : 0.2 +state 5331 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5911 : 1 +state 5332 observe2Greater1 observeIGreater1 + action 0 + 5811 : 1 +state 5333 observe2Greater1 observeIGreater1 + action 0 + 5899 : 1 +state 5334 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5912 : 1 +state 5335 observe2Greater1 observeIGreater1 + action 0 + 5913 : 1 +state 5336 observe2Greater1 observeIGreater1 + action 0 + 5914 : 0.8 + 5915 : 0.2 +state 5337 observe2Greater1 observeIGreater1 + action 0 + 5916 : 0.8 + 5917 : 0.2 +state 5338 observe2Greater1 observeIGreater1 + action 0 + 5918 : 0.8 + 5919 : 0.2 +state 5339 observe2Greater1 observeIGreater1 + action 0 + 5920 : 0.8 + 5921 : 0.2 +state 5340 observe2Greater1 observeIGreater1 + action 0 + 5922 : 0.8 + 5923 : 0.2 +state 5341 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5924 : 1 +state 5342 observe2Greater1 observeIGreater1 + action 0 + 5812 : 1 +state 5343 observe2Greater1 observeIGreater1 + action 0 + 5900 : 1 +state 5344 observe2Greater1 observeIGreater1 + action 0 + 5913 : 1 +state 5345 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5925 : 1 +state 5346 observe2Greater1 observeIGreater1 + action 0 + 5926 : 0.8 + 5927 : 0.2 +state 5347 observe2Greater1 observeIGreater1 + action 0 + 5928 : 0.8 + 5929 : 0.2 +state 5348 observe2Greater1 observeIGreater1 + action 0 + 5930 : 0.8 + 5931 : 0.2 +state 5349 observe2Greater1 observeIGreater1 + action 0 + 5932 : 0.8 + 5933 : 0.2 +state 5350 observe2Greater1 observeIGreater1 + action 0 + 5934 : 0.8 + 5935 : 0.2 +state 5351 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5936 : 1 +state 5352 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5937 : 1 +state 5353 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5938 : 1 +state 5354 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5939 : 1 +state 5355 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5940 : 1 +state 5356 observe3Greater1 observeIGreater1 + action 0 + 5824 : 1 +state 5357 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 5912 : 1 +state 5358 observe3Greater1 observeIGreater1 + action 0 + 5941 : 1 +state 5359 observe3Greater1 observeIGreater1 + action 0 + 5942 : 1 +state 5360 observe3Greater1 observeIGreater1 + action 0 + 5943 : 0.8 + 5944 : 0.2 +state 5361 observe3Greater1 observeIGreater1 + action 0 + 5945 : 0.8 + 5946 : 0.2 +state 5362 observe3Greater1 observeIGreater1 + action 0 + 5947 : 0.8 + 5948 : 0.2 +state 5363 observe3Greater1 observeIGreater1 + action 0 + 5949 : 0.8 + 5950 : 0.2 +state 5364 observe3Greater1 observeIGreater1 + action 0 + 5951 : 0.8 + 5952 : 0.2 +state 5365 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5953 : 1 +state 5366 + action 0 + 5825 : 1 +state 5367 observe2Greater1 observeIGreater1 + action 0 + 5913 : 1 +state 5368 observe3Greater1 observeIGreater1 + action 0 + 5942 : 1 +state 5369 observe4Greater1 observeIGreater1 + action 0 + 5954 : 1 +state 5370 + action 0 + 5955 : 0.8 + 5956 : 0.2 +state 5371 + action 0 + 5957 : 0.8 + 5958 : 0.2 +state 5372 + action 0 + 5959 : 0.8 + 5960 : 0.2 +state 5373 + action 0 + 5961 : 0.8 + 5962 : 0.2 +state 5374 + action 0 + 5963 : 0.8 + 5964 : 0.2 +state 5375 observe0Greater1 observeOnlyTrueSender + action 0 + 5965 : 1 +state 5376 observe0Greater1 observeOnlyTrueSender + action 0 + 5966 : 1 +state 5377 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5967 : 1 +state 5378 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5968 : 1 +state 5379 observe0Greater1 observeOnlyTrueSender + action 0 + 5969 : 1 +state 5380 observe4Greater1 observeIGreater1 + action 0 + 5837 : 1 +state 5381 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 5925 : 1 +state 5382 observe4Greater1 observeIGreater1 + action 0 + 5954 : 1 +state 5383 observe4Greater1 observeIGreater1 + action 0 + 5970 : 1 +state 5384 observe4Greater1 observeIGreater1 + action 0 + 5971 : 0.8 + 5972 : 0.2 +state 5385 observe4Greater1 observeIGreater1 + action 0 + 5973 : 0.8 + 5974 : 0.2 +state 5386 observe4Greater1 observeIGreater1 + action 0 + 5975 : 0.8 + 5976 : 0.2 +state 5387 observe4Greater1 observeIGreater1 + action 0 + 5977 : 0.8 + 5978 : 0.2 +state 5388 observe4Greater1 observeIGreater1 + action 0 + 5979 : 0.8 + 5980 : 0.2 +state 5389 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5981 : 1 +state 5390 observe0Greater1 observeOnlyTrueSender + action 0 + 5982 : 1 +state 5391 observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5983 : 1 +state 5392 observe0Greater1 observeOnlyTrueSender + action 0 + 5984 : 1 +state 5393 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5985 : 1 +state 5394 observe3Greater1 observeIGreater1 + action 0 + 5853 : 1 +state 5395 observe3Greater1 observeIGreater1 + action 0 + 5941 : 1 +state 5396 observe3Greater1 observeIGreater1 + action 0 + 5986 : 1 +state 5397 observe3Greater1 observeIGreater1 + action 0 + 5987 : 1 +state 5398 observe3Greater1 observeIGreater1 + action 0 + 5988 : 0.8 + 5989 : 0.2 +state 5399 observe3Greater1 observeIGreater1 + action 0 + 5990 : 0.8 + 5991 : 0.2 +state 5400 observe3Greater1 observeIGreater1 + action 0 + 5992 : 0.8 + 5993 : 0.2 +state 5401 observe3Greater1 observeIGreater1 + action 0 + 5994 : 0.8 + 5995 : 0.2 +state 5402 observe3Greater1 observeIGreater1 + action 0 + 5996 : 0.8 + 5997 : 0.2 +state 5403 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5998 : 1 +state 5404 observe3Greater1 observeIGreater1 + action 0 + 5854 : 1 +state 5405 observe3Greater1 observeIGreater1 + action 0 + 5942 : 1 +state 5406 observe3Greater1 observeIGreater1 + action 0 + 5987 : 1 +state 5407 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5999 : 1 +state 5408 observe3Greater1 observeIGreater1 + action 0 + 6000 : 0.8 + 6001 : 0.2 +state 5409 observe3Greater1 observeIGreater1 + action 0 + 6002 : 0.8 + 6003 : 0.2 +state 5410 observe3Greater1 observeIGreater1 + action 0 + 6004 : 0.8 + 6005 : 0.2 +state 5411 observe3Greater1 observeIGreater1 + action 0 + 6006 : 0.8 + 6007 : 0.2 +state 5412 observe3Greater1 observeIGreater1 + action 0 + 6008 : 0.8 + 6009 : 0.2 +state 5413 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6010 : 1 +state 5414 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6011 : 1 +state 5415 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6012 : 1 +state 5416 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6013 : 1 +state 5417 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6014 : 1 +state 5418 observe4Greater1 observeIGreater1 + action 0 + 5866 : 1 +state 5419 observe4Greater1 observeIGreater1 + action 0 + 5954 : 1 +state 5420 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 5999 : 1 +state 5421 observe4Greater1 observeIGreater1 + action 0 + 6015 : 1 +state 5422 observe4Greater1 observeIGreater1 + action 0 + 6016 : 0.8 + 6017 : 0.2 +state 5423 observe4Greater1 observeIGreater1 + action 0 + 6018 : 0.8 + 6019 : 0.2 +state 5424 observe4Greater1 observeIGreater1 + action 0 + 6020 : 0.8 + 6021 : 0.2 +state 5425 observe4Greater1 observeIGreater1 + action 0 + 6022 : 0.8 + 6023 : 0.2 +state 5426 observe4Greater1 observeIGreater1 + action 0 + 6024 : 0.8 + 6025 : 0.2 +state 5427 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6026 : 1 +state 5428 observe0Greater1 observeOnlyTrueSender + action 0 + 6027 : 1 +state 5429 observe0Greater1 observeOnlyTrueSender + action 0 + 6028 : 1 +state 5430 observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6029 : 1 +state 5431 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6030 : 1 +state 5432 observe4Greater1 observeIGreater1 + action 0 + 5882 : 1 +state 5433 observe4Greater1 observeIGreater1 + action 0 + 5970 : 1 +state 5434 observe4Greater1 observeIGreater1 + action 0 + 6015 : 1 +state 5435 observe4Greater1 observeIGreater1 + action 0 + 6031 : 1 +state 5436 observe4Greater1 observeIGreater1 + action 0 + 6032 : 0.8 + 6033 : 0.2 +state 5437 observe4Greater1 observeIGreater1 + action 0 + 6034 : 0.8 + 6035 : 0.2 +state 5438 observe4Greater1 observeIGreater1 + action 0 + 6036 : 0.8 + 6037 : 0.2 +state 5439 observe4Greater1 observeIGreater1 + action 0 + 6038 : 0.8 + 6039 : 0.2 +state 5440 observe4Greater1 observeIGreater1 + action 0 + 6040 : 0.8 + 6041 : 0.2 +state 5441 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6042 : 1 +state 5442 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6043 : 1 +state 5443 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6044 : 1 +state 5444 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6045 : 1 +state 5445 observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6046 : 1 +state 5446 deadlock observe1Greater1 observeIGreater1 + action 0 + 5446 : 1 +state 5447 deadlock + action 0 + 5447 : 1 +state 5448 deadlock + action 0 + 5448 : 1 +state 5449 deadlock + action 0 + 5449 : 1 +state 5450 deadlock + action 0 + 5450 : 1 +state 5451 deadlock observe2Greater1 observeIGreater1 + action 0 + 5451 : 1 +state 5452 deadlock + action 0 + 5452 : 1 +state 5453 deadlock + action 0 + 5453 : 1 +state 5454 deadlock + action 0 + 5454 : 1 +state 5455 deadlock + action 0 + 5455 : 1 +state 5456 deadlock observe3Greater1 observeIGreater1 + action 0 + 5456 : 1 +state 5457 deadlock + action 0 + 5457 : 1 +state 5458 deadlock + action 0 + 5458 : 1 +state 5459 deadlock + action 0 + 5459 : 1 +state 5460 deadlock + action 0 + 5460 : 1 +state 5461 deadlock observe4Greater1 observeIGreater1 + action 0 + 5461 : 1 +state 5462 deadlock observe1Greater1 observeIGreater1 + action 0 + 5462 : 1 +state 5463 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5464 observe1Greater1 observeIGreater1 + action 0 + 6047 : 1 +state 5465 deadlock observe1Greater1 observeIGreater1 + action 0 + 5465 : 1 +state 5466 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5467 observe1Greater1 observeIGreater1 + action 0 + 6048 : 1 +state 5468 deadlock observe1Greater1 observeIGreater1 + action 0 + 5468 : 1 +state 5469 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5470 observe1Greater1 observeIGreater1 + action 0 + 6049 : 1 +state 5471 deadlock observe1Greater1 observeIGreater1 + action 0 + 5471 : 1 +state 5472 observe1Greater1 observeIGreater1 + action 0 + 4422 : 0.2 + 4423 : 0.2 + 4424 : 0.2 + 4425 : 0.2 + 4426 : 0.2 +state 5473 observe1Greater1 observeIGreater1 + action 0 + 6050 : 1 +state 5474 deadlock observe1Greater1 observeIGreater1 + action 0 + 5474 : 1 +state 5475 deadlock + action 0 + 5475 : 1 +state 5476 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5477 + action 0 + 6051 : 1 +state 5478 deadlock + action 0 + 5478 : 1 +state 5479 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5480 + action 0 + 6052 : 1 +state 5481 deadlock + action 0 + 5481 : 1 +state 5482 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5483 + action 0 + 6053 : 1 +state 5484 deadlock + action 0 + 5484 : 1 +state 5485 + action 0 + 4428 : 0.2 + 4429 : 0.2 + 4430 : 0.2 + 4431 : 0.2 + 4432 : 0.2 +state 5486 + action 0 + 6054 : 1 +state 5487 deadlock + action 0 + 5487 : 1 +state 5488 deadlock + action 0 + 5488 : 1 +state 5489 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5490 + action 0 + 6055 : 1 +state 5491 deadlock + action 0 + 5491 : 1 +state 5492 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5493 + action 0 + 6056 : 1 +state 5494 deadlock + action 0 + 5494 : 1 +state 5495 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5496 + action 0 + 6057 : 1 +state 5497 deadlock + action 0 + 5497 : 1 +state 5498 + action 0 + 4434 : 0.2 + 4435 : 0.2 + 4436 : 0.2 + 4437 : 0.2 + 4438 : 0.2 +state 5499 + action 0 + 6058 : 1 +state 5500 deadlock + action 0 + 5500 : 1 +state 5501 deadlock + action 0 + 5501 : 1 +state 5502 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5503 + action 0 + 6059 : 1 +state 5504 deadlock + action 0 + 5504 : 1 +state 5505 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5506 + action 0 + 6060 : 1 +state 5507 deadlock + action 0 + 5507 : 1 +state 5508 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5509 + action 0 + 6061 : 1 +state 5510 deadlock + action 0 + 5510 : 1 +state 5511 + action 0 + 4440 : 0.2 + 4441 : 0.2 + 4442 : 0.2 + 4443 : 0.2 + 4444 : 0.2 +state 5512 + action 0 + 6062 : 1 +state 5513 deadlock + action 0 + 5513 : 1 +state 5514 deadlock observe2Greater1 observeIGreater1 + action 0 + 5514 : 1 +state 5515 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5516 observe2Greater1 observeIGreater1 + action 0 + 6063 : 1 +state 5517 deadlock observe2Greater1 observeIGreater1 + action 0 + 5517 : 1 +state 5518 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5519 observe2Greater1 observeIGreater1 + action 0 + 6064 : 1 +state 5520 deadlock observe2Greater1 observeIGreater1 + action 0 + 5520 : 1 +state 5521 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5522 observe2Greater1 observeIGreater1 + action 0 + 6065 : 1 +state 5523 deadlock observe2Greater1 observeIGreater1 + action 0 + 5523 : 1 +state 5524 observe2Greater1 observeIGreater1 + action 0 + 4450 : 0.2 + 4451 : 0.2 + 4452 : 0.2 + 4453 : 0.2 + 4454 : 0.2 +state 5525 observe2Greater1 observeIGreater1 + action 0 + 6066 : 1 +state 5526 deadlock observe2Greater1 observeIGreater1 + action 0 + 5526 : 1 +state 5527 deadlock + action 0 + 5527 : 1 +state 5528 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5529 + action 0 + 6067 : 1 +state 5530 deadlock + action 0 + 5530 : 1 +state 5531 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5532 + action 0 + 6068 : 1 +state 5533 deadlock + action 0 + 5533 : 1 +state 5534 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5535 + action 0 + 6069 : 1 +state 5536 deadlock + action 0 + 5536 : 1 +state 5537 + action 0 + 4456 : 0.2 + 4457 : 0.2 + 4458 : 0.2 + 4459 : 0.2 + 4460 : 0.2 +state 5538 + action 0 + 6070 : 1 +state 5539 deadlock + action 0 + 5539 : 1 +state 5540 deadlock + action 0 + 5540 : 1 +state 5541 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5542 + action 0 + 6071 : 1 +state 5543 deadlock + action 0 + 5543 : 1 +state 5544 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5545 + action 0 + 6072 : 1 +state 5546 deadlock + action 0 + 5546 : 1 +state 5547 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5548 + action 0 + 6073 : 1 +state 5549 deadlock + action 0 + 5549 : 1 +state 5550 + action 0 + 4462 : 0.2 + 4463 : 0.2 + 4464 : 0.2 + 4465 : 0.2 + 4466 : 0.2 +state 5551 + action 0 + 6074 : 1 +state 5552 deadlock + action 0 + 5552 : 1 +state 5553 deadlock observe3Greater1 observeIGreater1 + action 0 + 5553 : 1 +state 5554 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5555 observe3Greater1 observeIGreater1 + action 0 + 6075 : 1 +state 5556 deadlock observe3Greater1 observeIGreater1 + action 0 + 5556 : 1 +state 5557 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5558 observe3Greater1 observeIGreater1 + action 0 + 6076 : 1 +state 5559 deadlock observe3Greater1 observeIGreater1 + action 0 + 5559 : 1 +state 5560 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5561 observe3Greater1 observeIGreater1 + action 0 + 6077 : 1 +state 5562 deadlock observe3Greater1 observeIGreater1 + action 0 + 5562 : 1 +state 5563 observe3Greater1 observeIGreater1 + action 0 + 4472 : 0.2 + 4473 : 0.2 + 4474 : 0.2 + 4475 : 0.2 + 4476 : 0.2 +state 5564 observe3Greater1 observeIGreater1 + action 0 + 6078 : 1 +state 5565 deadlock observe3Greater1 observeIGreater1 + action 0 + 5565 : 1 +state 5566 deadlock + action 0 + 5566 : 1 +state 5567 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5568 + action 0 + 6079 : 1 +state 5569 deadlock + action 0 + 5569 : 1 +state 5570 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5571 + action 0 + 6080 : 1 +state 5572 deadlock + action 0 + 5572 : 1 +state 5573 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5574 + action 0 + 6081 : 1 +state 5575 deadlock + action 0 + 5575 : 1 +state 5576 + action 0 + 4478 : 0.2 + 4479 : 0.2 + 4480 : 0.2 + 4481 : 0.2 + 4482 : 0.2 +state 5577 + action 0 + 6082 : 1 +state 5578 deadlock + action 0 + 5578 : 1 +state 5579 deadlock observe4Greater1 observeIGreater1 + action 0 + 5579 : 1 +state 5580 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5581 observe4Greater1 observeIGreater1 + action 0 + 6083 : 1 +state 5582 deadlock observe4Greater1 observeIGreater1 + action 0 + 5582 : 1 +state 5583 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5584 observe4Greater1 observeIGreater1 + action 0 + 6084 : 1 +state 5585 deadlock observe4Greater1 observeIGreater1 + action 0 + 5585 : 1 +state 5586 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5587 observe4Greater1 observeIGreater1 + action 0 + 6085 : 1 +state 5588 deadlock observe4Greater1 observeIGreater1 + action 0 + 5588 : 1 +state 5589 observe4Greater1 observeIGreater1 + action 0 + 4488 : 0.2 + 4489 : 0.2 + 4490 : 0.2 + 4491 : 0.2 + 4492 : 0.2 +state 5590 observe4Greater1 observeIGreater1 + action 0 + 6086 : 1 +state 5591 deadlock observe4Greater1 observeIGreater1 + action 0 + 5591 : 1 +state 5592 observe1Greater1 observeIGreater1 + action 0 + 4634 : 0.8 + 6087 : 0.2 +state 5593 observe1Greater1 observeIGreater1 + action 0 + 6088 : 0.8 + 6089 : 0.2 +state 5594 observe1Greater1 observeIGreater1 + action 0 + 6090 : 0.8 + 6091 : 0.2 +state 5595 observe1Greater1 observeIGreater1 + action 0 + 6092 : 0.8 + 6093 : 0.2 +state 5596 observe1Greater1 observeIGreater1 + action 0 + 6094 : 0.8 + 6095 : 0.2 +state 5597 observe1Greater1 observeIGreater1 + action 0 + 6096 : 1 +state 5598 observe1Greater1 observeIGreater1 + action 0 + 4641 : 0.8 + 6097 : 0.2 +state 5599 observe1Greater1 observeIGreater1 + action 0 + 6098 : 0.8 + 6099 : 0.2 +state 5600 observe1Greater1 observeIGreater1 + action 0 + 6100 : 0.8 + 6101 : 0.2 +state 5601 observe1Greater1 observeIGreater1 + action 0 + 6102 : 0.8 + 6103 : 0.2 +state 5602 observe1Greater1 observeIGreater1 + action 0 + 6104 : 0.8 + 6105 : 0.2 +state 5603 observe1Greater1 observeIGreater1 + action 0 + 6106 : 1 +state 5604 observe1Greater1 observeIGreater1 + action 0 + 4648 : 0.8 + 6107 : 0.2 +state 5605 observe1Greater1 observeIGreater1 + action 0 + 6108 : 0.8 + 6109 : 0.2 +state 5606 observe1Greater1 observeIGreater1 + action 0 + 6110 : 0.8 + 6111 : 0.2 +state 5607 observe1Greater1 observeIGreater1 + action 0 + 6112 : 0.8 + 6113 : 0.2 +state 5608 observe1Greater1 observeIGreater1 + action 0 + 6114 : 0.8 + 6115 : 0.2 +state 5609 observe1Greater1 observeIGreater1 + action 0 + 6116 : 1 +state 5610 observe1Greater1 observeIGreater1 + action 0 + 4655 : 0.8 + 6117 : 0.2 +state 5611 observe1Greater1 observeIGreater1 + action 0 + 6118 : 0.8 + 6119 : 0.2 +state 5612 observe1Greater1 observeIGreater1 + action 0 + 6120 : 0.8 + 6121 : 0.2 +state 5613 observe1Greater1 observeIGreater1 + action 0 + 6122 : 0.8 + 6123 : 0.2 +state 5614 observe1Greater1 observeIGreater1 + action 0 + 6124 : 0.8 + 6125 : 0.2 +state 5615 observe1Greater1 observeIGreater1 + action 0 + 6126 : 1 +state 5616 observe1Greater1 observeIGreater1 + action 0 + 6127 : 1 +state 5617 observe1Greater1 observeIGreater1 + action 0 + 6128 : 1 +state 5618 observe1Greater1 observeIGreater1 + action 0 + 6129 : 1 +state 5619 observe1Greater1 observeIGreater1 + action 0 + 6130 : 1 +state 5620 observe2Greater1 observeIGreater1 + action 0 + 4675 : 0.8 + 6131 : 0.2 +state 5621 observe2Greater1 observeIGreater1 + action 0 + 6132 : 0.8 + 6133 : 0.2 +state 5622 observe2Greater1 observeIGreater1 + action 0 + 6134 : 0.8 + 6135 : 0.2 +state 5623 observe2Greater1 observeIGreater1 + action 0 + 6136 : 0.8 + 6137 : 0.2 +state 5624 observe2Greater1 observeIGreater1 + action 0 + 6138 : 0.8 + 6139 : 0.2 +state 5625 observe2Greater1 observeIGreater1 + action 0 + 6140 : 1 +state 5626 + action 0 + 4682 : 0.8 + 6141 : 0.2 +state 5627 + action 0 + 6142 : 0.8 + 6143 : 0.2 +state 5628 + action 0 + 6144 : 0.8 + 6145 : 0.2 +state 5629 + action 0 + 6146 : 0.8 + 6147 : 0.2 +state 5630 + action 0 + 6148 : 0.8 + 6149 : 0.2 +state 5631 + action 0 + 6150 : 1 +state 5632 + action 0 + 4689 : 0.8 + 6151 : 0.2 +state 5633 + action 0 + 6152 : 0.8 + 6153 : 0.2 +state 5634 + action 0 + 6154 : 0.8 + 6155 : 0.2 +state 5635 + action 0 + 6156 : 0.8 + 6157 : 0.2 +state 5636 + action 0 + 6158 : 0.8 + 6159 : 0.2 +state 5637 + action 0 + 6160 : 1 +state 5638 observe1Greater1 observeIGreater1 + action 0 + 6161 : 1 +state 5639 observe2Greater1 observeIGreater1 + action 0 + 6162 : 1 +state 5640 + action 0 + 6163 : 1 +state 5641 + action 0 + 6164 : 1 +state 5642 observe3Greater1 observeIGreater1 + action 0 + 4709 : 0.8 + 6165 : 0.2 +state 5643 observe3Greater1 observeIGreater1 + action 0 + 6166 : 0.8 + 6167 : 0.2 +state 5644 observe3Greater1 observeIGreater1 + action 0 + 6168 : 0.8 + 6169 : 0.2 +state 5645 observe3Greater1 observeIGreater1 + action 0 + 6170 : 0.8 + 6171 : 0.2 +state 5646 observe3Greater1 observeIGreater1 + action 0 + 6172 : 0.8 + 6173 : 0.2 +state 5647 observe3Greater1 observeIGreater1 + action 0 + 6174 : 1 +state 5648 + action 0 + 4716 : 0.8 + 6175 : 0.2 +state 5649 + action 0 + 6176 : 0.8 + 6177 : 0.2 +state 5650 + action 0 + 6178 : 0.8 + 6179 : 0.2 +state 5651 + action 0 + 6180 : 0.8 + 6181 : 0.2 +state 5652 + action 0 + 6182 : 0.8 + 6183 : 0.2 +state 5653 + action 0 + 6184 : 1 +state 5654 observe1Greater1 observeIGreater1 + action 0 + 6185 : 1 +state 5655 + action 0 + 6186 : 1 +state 5656 observe3Greater1 observeIGreater1 + action 0 + 6187 : 1 +state 5657 + action 0 + 6188 : 1 +state 5658 observe4Greater1 observeIGreater1 + action 0 + 4736 : 0.8 + 6189 : 0.2 +state 5659 observe4Greater1 observeIGreater1 + action 0 + 6190 : 0.8 + 6191 : 0.2 +state 5660 observe4Greater1 observeIGreater1 + action 0 + 6192 : 0.8 + 6193 : 0.2 +state 5661 observe4Greater1 observeIGreater1 + action 0 + 6194 : 0.8 + 6195 : 0.2 +state 5662 observe4Greater1 observeIGreater1 + action 0 + 6196 : 0.8 + 6197 : 0.2 +state 5663 observe4Greater1 observeIGreater1 + action 0 + 6198 : 1 +state 5664 observe1Greater1 observeIGreater1 + action 0 + 6199 : 1 +state 5665 + action 0 + 6200 : 1 +state 5666 + action 0 + 6201 : 1 +state 5667 observe4Greater1 observeIGreater1 + action 0 + 6202 : 1 +state 5668 observe2Greater1 observeIGreater1 + action 0 + 4756 : 0.8 + 6203 : 0.2 +state 5669 observe2Greater1 observeIGreater1 + action 0 + 6204 : 0.8 + 6205 : 0.2 +state 5670 observe2Greater1 observeIGreater1 + action 0 + 6206 : 0.8 + 6207 : 0.2 +state 5671 observe2Greater1 observeIGreater1 + action 0 + 6208 : 0.8 + 6209 : 0.2 +state 5672 observe2Greater1 observeIGreater1 + action 0 + 6210 : 0.8 + 6211 : 0.2 +state 5673 observe2Greater1 observeIGreater1 + action 0 + 6212 : 1 +state 5674 observe2Greater1 observeIGreater1 + action 0 + 4763 : 0.8 + 6213 : 0.2 +state 5675 observe2Greater1 observeIGreater1 + action 0 + 6214 : 0.8 + 6215 : 0.2 +state 5676 observe2Greater1 observeIGreater1 + action 0 + 6216 : 0.8 + 6217 : 0.2 +state 5677 observe2Greater1 observeIGreater1 + action 0 + 6218 : 0.8 + 6219 : 0.2 +state 5678 observe2Greater1 observeIGreater1 + action 0 + 6220 : 0.8 + 6221 : 0.2 +state 5679 observe2Greater1 observeIGreater1 + action 0 + 6222 : 1 +state 5680 observe2Greater1 observeIGreater1 + action 0 + 4770 : 0.8 + 6223 : 0.2 +state 5681 observe2Greater1 observeIGreater1 + action 0 + 6224 : 0.8 + 6225 : 0.2 +state 5682 observe2Greater1 observeIGreater1 + action 0 + 6226 : 0.8 + 6227 : 0.2 +state 5683 observe2Greater1 observeIGreater1 + action 0 + 6228 : 0.8 + 6229 : 0.2 +state 5684 observe2Greater1 observeIGreater1 + action 0 + 6230 : 0.8 + 6231 : 0.2 +state 5685 observe2Greater1 observeIGreater1 + action 0 + 6232 : 1 +state 5686 observe2Greater1 observeIGreater1 + action 0 + 6233 : 1 +state 5687 observe2Greater1 observeIGreater1 + action 0 + 6234 : 1 +state 5688 observe2Greater1 observeIGreater1 + action 0 + 6235 : 1 +state 5689 observe2Greater1 observeIGreater1 + action 0 + 6236 : 1 +state 5690 observe3Greater1 observeIGreater1 + action 0 + 4790 : 0.8 + 6237 : 0.2 +state 5691 observe3Greater1 observeIGreater1 + action 0 + 6238 : 0.8 + 6239 : 0.2 +state 5692 observe3Greater1 observeIGreater1 + action 0 + 6240 : 0.8 + 6241 : 0.2 +state 5693 observe3Greater1 observeIGreater1 + action 0 + 6242 : 0.8 + 6243 : 0.2 +state 5694 observe3Greater1 observeIGreater1 + action 0 + 6244 : 0.8 + 6245 : 0.2 +state 5695 observe3Greater1 observeIGreater1 + action 0 + 6246 : 1 +state 5696 + action 0 + 4797 : 0.8 + 6247 : 0.2 +state 5697 + action 0 + 6248 : 0.8 + 6249 : 0.2 +state 5698 + action 0 + 6250 : 0.8 + 6251 : 0.2 +state 5699 + action 0 + 6252 : 0.8 + 6253 : 0.2 +state 5700 + action 0 + 6254 : 0.8 + 6255 : 0.2 +state 5701 + action 0 + 6256 : 1 +state 5702 + action 0 + 6257 : 1 +state 5703 observe2Greater1 observeIGreater1 + action 0 + 6258 : 1 +state 5704 observe3Greater1 observeIGreater1 + action 0 + 6259 : 1 +state 5705 + action 0 + 6260 : 1 +state 5706 observe4Greater1 observeIGreater1 + action 0 + 4817 : 0.8 + 6261 : 0.2 +state 5707 observe4Greater1 observeIGreater1 + action 0 + 6262 : 0.8 + 6263 : 0.2 +state 5708 observe4Greater1 observeIGreater1 + action 0 + 6264 : 0.8 + 6265 : 0.2 +state 5709 observe4Greater1 observeIGreater1 + action 0 + 6266 : 0.8 + 6267 : 0.2 +state 5710 observe4Greater1 observeIGreater1 + action 0 + 6268 : 0.8 + 6269 : 0.2 +state 5711 observe4Greater1 observeIGreater1 + action 0 + 6270 : 1 +state 5712 + action 0 + 6271 : 1 +state 5713 observe2Greater1 observeIGreater1 + action 0 + 6272 : 1 +state 5714 + action 0 + 6273 : 1 +state 5715 observe4Greater1 observeIGreater1 + action 0 + 6274 : 1 +state 5716 observe3Greater1 observeIGreater1 + action 0 + 4837 : 0.8 + 6275 : 0.2 +state 5717 observe3Greater1 observeIGreater1 + action 0 + 6276 : 0.8 + 6277 : 0.2 +state 5718 observe3Greater1 observeIGreater1 + action 0 + 6278 : 0.8 + 6279 : 0.2 +state 5719 observe3Greater1 observeIGreater1 + action 0 + 6280 : 0.8 + 6281 : 0.2 +state 5720 observe3Greater1 observeIGreater1 + action 0 + 6282 : 0.8 + 6283 : 0.2 +state 5721 observe3Greater1 observeIGreater1 + action 0 + 6284 : 1 +state 5722 observe3Greater1 observeIGreater1 + action 0 + 4844 : 0.8 + 6285 : 0.2 +state 5723 observe3Greater1 observeIGreater1 + action 0 + 6286 : 0.8 + 6287 : 0.2 +state 5724 observe3Greater1 observeIGreater1 + action 0 + 6288 : 0.8 + 6289 : 0.2 +state 5725 observe3Greater1 observeIGreater1 + action 0 + 6290 : 0.8 + 6291 : 0.2 +state 5726 observe3Greater1 observeIGreater1 + action 0 + 6292 : 0.8 + 6293 : 0.2 +state 5727 observe3Greater1 observeIGreater1 + action 0 + 6294 : 1 +state 5728 observe3Greater1 observeIGreater1 + action 0 + 6295 : 1 +state 5729 observe3Greater1 observeIGreater1 + action 0 + 6296 : 1 +state 5730 observe3Greater1 observeIGreater1 + action 0 + 6297 : 1 +state 5731 observe3Greater1 observeIGreater1 + action 0 + 6298 : 1 +state 5732 observe4Greater1 observeIGreater1 + action 0 + 4864 : 0.8 + 6299 : 0.2 +state 5733 observe4Greater1 observeIGreater1 + action 0 + 6300 : 0.8 + 6301 : 0.2 +state 5734 observe4Greater1 observeIGreater1 + action 0 + 6302 : 0.8 + 6303 : 0.2 +state 5735 observe4Greater1 observeIGreater1 + action 0 + 6304 : 0.8 + 6305 : 0.2 +state 5736 observe4Greater1 observeIGreater1 + action 0 + 6306 : 0.8 + 6307 : 0.2 +state 5737 observe4Greater1 observeIGreater1 + action 0 + 6308 : 1 +state 5738 + action 0 + 6309 : 1 +state 5739 + action 0 + 6310 : 1 +state 5740 observe3Greater1 observeIGreater1 + action 0 + 6311 : 1 +state 5741 observe4Greater1 observeIGreater1 + action 0 + 6312 : 1 +state 5742 observe4Greater1 observeIGreater1 + action 0 + 4884 : 0.8 + 6313 : 0.2 +state 5743 observe4Greater1 observeIGreater1 + action 0 + 6314 : 0.8 + 6315 : 0.2 +state 5744 observe4Greater1 observeIGreater1 + action 0 + 6316 : 0.8 + 6317 : 0.2 +state 5745 observe4Greater1 observeIGreater1 + action 0 + 6318 : 0.8 + 6319 : 0.2 +state 5746 observe4Greater1 observeIGreater1 + action 0 + 6320 : 0.8 + 6321 : 0.2 +state 5747 observe4Greater1 observeIGreater1 + action 0 + 6322 : 1 +state 5748 observe4Greater1 observeIGreater1 + action 0 + 6323 : 1 +state 5749 observe4Greater1 observeIGreater1 + action 0 + 6324 : 1 +state 5750 observe4Greater1 observeIGreater1 + action 0 + 6325 : 1 +state 5751 observe4Greater1 observeIGreater1 + action 0 + 6326 : 1 +state 5752 observe1Greater1 observeIGreater1 + action 0 + 6327 : 0.833 + 6328 : 0.167 +state 5753 observe1Greater1 observeIGreater1 + action 0 + 6329 : 0.833 + 6330 : 0.167 +state 5754 observe1Greater1 observeIGreater1 + action 0 + 6331 : 0.833 + 6332 : 0.167 +state 5755 observe1Greater1 observeIGreater1 + action 0 + 6333 : 0.833 + 6334 : 0.167 +state 5756 observe1Greater1 observeIGreater1 + action 0 + 4639 : 0.833 + 4640 : 0.167 +state 5757 observe1Greater1 observeIGreater1 + action 0 + 6335 : 1 +state 5758 observe1Greater1 observeIGreater1 + action 0 + 6336 : 0.833 + 6337 : 0.167 +state 5759 observe1Greater1 observeIGreater1 + action 0 + 6338 : 1 +state 5760 observe1Greater1 observeIGreater1 + action 0 + 6339 : 0.833 + 6340 : 0.167 +state 5761 observe1Greater1 observeIGreater1 + action 0 + 6341 : 1 +state 5762 observe1Greater1 observeIGreater1 + action 0 + 6342 : 0.833 + 6343 : 0.167 +state 5763 observe1Greater1 observeIGreater1 + action 0 + 6344 : 1 +state 5764 observe1Greater1 observeIGreater1 + action 0 + 6345 : 0.833 + 6346 : 0.167 +state 5765 observe1Greater1 observeIGreater1 + action 0 + 6347 : 1 +state 5766 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5766 : 1 +state 5767 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6348 : 0.833 + 6349 : 0.167 +state 5768 observe1Greater1 observeIGreater1 + action 0 + 6350 : 0.833 + 6351 : 0.167 +state 5769 observe1Greater1 observeIGreater1 + action 0 + 6352 : 0.833 + 6353 : 0.167 +state 5770 observe1Greater1 observeIGreater1 + action 0 + 4646 : 0.833 + 4647 : 0.167 +state 5771 observe1Greater1 observeIGreater1 + action 0 + 6354 : 1 +state 5772 observe1Greater1 observeIGreater1 + action 0 + 6355 : 0.833 + 6356 : 0.167 +state 5773 observe1Greater1 observeIGreater1 + action 0 + 6357 : 1 +state 5774 observe1Greater1 observeIGreater1 + action 0 + 6358 : 0.833 + 6359 : 0.167 +state 5775 observe1Greater1 observeIGreater1 + action 0 + 6360 : 1 +state 5776 observe1Greater1 observeIGreater1 + action 0 + 6361 : 0.833 + 6362 : 0.167 +state 5777 observe1Greater1 observeIGreater1 + action 0 + 6363 : 1 +state 5778 observe1Greater1 observeIGreater1 + action 0 + 6364 : 0.833 + 6365 : 0.167 +state 5779 observe1Greater1 observeIGreater1 + action 0 + 6366 : 1 +state 5780 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5780 : 1 +state 5781 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 6367 : 0.833 + 6368 : 0.167 +state 5782 observe1Greater1 observeIGreater1 + action 0 + 6369 : 0.833 + 6370 : 0.167 +state 5783 observe1Greater1 observeIGreater1 + action 0 + 4653 : 0.833 + 4654 : 0.167 +state 5784 observe1Greater1 observeIGreater1 + action 0 + 6371 : 1 +state 5785 observe1Greater1 observeIGreater1 + action 0 + 6372 : 0.833 + 6373 : 0.167 +state 5786 observe1Greater1 observeIGreater1 + action 0 + 6374 : 1 +state 5787 observe1Greater1 observeIGreater1 + action 0 + 6375 : 0.833 + 6376 : 0.167 +state 5788 observe1Greater1 observeIGreater1 + action 0 + 6377 : 1 +state 5789 observe1Greater1 observeIGreater1 + action 0 + 6378 : 0.833 + 6379 : 0.167 +state 5790 observe1Greater1 observeIGreater1 + action 0 + 6380 : 1 +state 5791 observe1Greater1 observeIGreater1 + action 0 + 6381 : 0.833 + 6382 : 0.167 +state 5792 observe1Greater1 observeIGreater1 + action 0 + 6383 : 1 +state 5793 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5793 : 1 +state 5794 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 6384 : 0.833 + 6385 : 0.167 +state 5795 observe1Greater1 observeIGreater1 + action 0 + 4660 : 0.833 + 4661 : 0.167 +state 5796 observe1Greater1 observeIGreater1 + action 0 + 6386 : 1 +state 5797 observe1Greater1 observeIGreater1 + action 0 + 6387 : 0.833 + 6388 : 0.167 +state 5798 observe1Greater1 observeIGreater1 + action 0 + 6389 : 1 +state 5799 observe1Greater1 observeIGreater1 + action 0 + 6390 : 0.833 + 6391 : 0.167 +state 5800 observe1Greater1 observeIGreater1 + action 0 + 6392 : 1 +state 5801 observe1Greater1 observeIGreater1 + action 0 + 6393 : 0.833 + 6394 : 0.167 +state 5802 observe1Greater1 observeIGreater1 + action 0 + 6395 : 1 +state 5803 observe1Greater1 observeIGreater1 + action 0 + 6396 : 0.833 + 6397 : 0.167 +state 5804 observe1Greater1 observeIGreater1 + action 0 + 6398 : 1 +state 5805 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5805 : 1 +state 5806 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5806 : 1 +state 5807 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5807 : 1 +state 5808 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5808 : 1 +state 5809 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5809 : 1 +state 5810 observe2Greater1 observeIGreater1 + action 0 + 6399 : 0.833 + 6400 : 0.167 +state 5811 observe2Greater1 observeIGreater1 + action 0 + 6401 : 0.833 + 6402 : 0.167 +state 5812 observe2Greater1 observeIGreater1 + action 0 + 6403 : 0.833 + 6404 : 0.167 +state 5813 observe2Greater1 observeIGreater1 + action 0 + 4680 : 0.833 + 4681 : 0.167 +state 5814 observe2Greater1 observeIGreater1 + action 0 + 6405 : 1 +state 5815 observe2Greater1 observeIGreater1 + action 0 + 6406 : 0.833 + 6407 : 0.167 +state 5816 observe2Greater1 observeIGreater1 + action 0 + 6408 : 1 +state 5817 observe2Greater1 observeIGreater1 + action 0 + 6409 : 0.833 + 6410 : 0.167 +state 5818 observe2Greater1 observeIGreater1 + action 0 + 6411 : 1 +state 5819 observe2Greater1 observeIGreater1 + action 0 + 6412 : 0.833 + 6413 : 0.167 +state 5820 observe2Greater1 observeIGreater1 + action 0 + 6414 : 1 +state 5821 observe2Greater1 observeIGreater1 + action 0 + 6415 : 0.833 + 6416 : 0.167 +state 5822 observe2Greater1 observeIGreater1 + action 0 + 6417 : 1 +state 5823 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5823 : 1 +state 5824 observe3Greater1 observeIGreater1 + action 0 + 6418 : 0.833 + 6419 : 0.167 +state 5825 + action 0 + 6420 : 0.833 + 6421 : 0.167 +state 5826 + action 0 + 4687 : 0.833 + 4688 : 0.167 +state 5827 + action 0 + 6422 : 1 +state 5828 + action 0 + 6423 : 0.833 + 6424 : 0.167 +state 5829 + action 0 + 6425 : 1 +state 5830 + action 0 + 6426 : 0.833 + 6427 : 0.167 +state 5831 + action 0 + 6428 : 1 +state 5832 + action 0 + 6429 : 0.833 + 6430 : 0.167 +state 5833 + action 0 + 6431 : 1 +state 5834 + action 0 + 6432 : 0.833 + 6433 : 0.167 +state 5835 + action 0 + 6434 : 1 +state 5836 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5836 : 1 +state 5837 observe4Greater1 observeIGreater1 + action 0 + 6435 : 0.833 + 6436 : 0.167 +state 5838 + action 0 + 4694 : 0.833 + 4695 : 0.167 +state 5839 + action 0 + 6437 : 1 +state 5840 + action 0 + 6438 : 0.833 + 6439 : 0.167 +state 5841 + action 0 + 6440 : 1 +state 5842 + action 0 + 6441 : 0.833 + 6442 : 0.167 +state 5843 + action 0 + 6443 : 1 +state 5844 + action 0 + 6444 : 0.833 + 6445 : 0.167 +state 5845 + action 0 + 6446 : 1 +state 5846 + action 0 + 6447 : 0.833 + 6448 : 0.167 +state 5847 + action 0 + 6449 : 1 +state 5848 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5848 : 1 +state 5849 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5849 : 1 +state 5850 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5850 : 1 +state 5851 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5851 : 1 +state 5852 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5852 : 1 +state 5853 observe3Greater1 observeIGreater1 + action 0 + 6450 : 0.833 + 6451 : 0.167 +state 5854 observe3Greater1 observeIGreater1 + action 0 + 6452 : 0.833 + 6453 : 0.167 +state 5855 observe3Greater1 observeIGreater1 + action 0 + 4714 : 0.833 + 4715 : 0.167 +state 5856 observe3Greater1 observeIGreater1 + action 0 + 6454 : 1 +state 5857 observe3Greater1 observeIGreater1 + action 0 + 6455 : 0.833 + 6456 : 0.167 +state 5858 observe3Greater1 observeIGreater1 + action 0 + 6457 : 1 +state 5859 observe3Greater1 observeIGreater1 + action 0 + 6458 : 0.833 + 6459 : 0.167 +state 5860 observe3Greater1 observeIGreater1 + action 0 + 6460 : 1 +state 5861 observe3Greater1 observeIGreater1 + action 0 + 6461 : 0.833 + 6462 : 0.167 +state 5862 observe3Greater1 observeIGreater1 + action 0 + 6463 : 1 +state 5863 observe3Greater1 observeIGreater1 + action 0 + 6464 : 0.833 + 6465 : 0.167 +state 5864 observe3Greater1 observeIGreater1 + action 0 + 6466 : 1 +state 5865 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5865 : 1 +state 5866 observe4Greater1 observeIGreater1 + action 0 + 6467 : 0.833 + 6468 : 0.167 +state 5867 + action 0 + 4721 : 0.833 + 4722 : 0.167 +state 5868 + action 0 + 6469 : 1 +state 5869 + action 0 + 6470 : 0.833 + 6471 : 0.167 +state 5870 + action 0 + 6472 : 1 +state 5871 + action 0 + 6473 : 0.833 + 6474 : 0.167 +state 5872 + action 0 + 6475 : 1 +state 5873 + action 0 + 6476 : 0.833 + 6477 : 0.167 +state 5874 + action 0 + 6478 : 1 +state 5875 + action 0 + 6479 : 0.833 + 6480 : 0.167 +state 5876 + action 0 + 6481 : 1 +state 5877 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5877 : 1 +state 5878 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5878 : 1 +state 5879 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5879 : 1 +state 5880 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5880 : 1 +state 5881 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5881 : 1 +state 5882 observe4Greater1 observeIGreater1 + action 0 + 6482 : 0.833 + 6483 : 0.167 +state 5883 observe4Greater1 observeIGreater1 + action 0 + 4741 : 0.833 + 4742 : 0.167 +state 5884 observe4Greater1 observeIGreater1 + action 0 + 6484 : 1 +state 5885 observe4Greater1 observeIGreater1 + action 0 + 6485 : 0.833 + 6486 : 0.167 +state 5886 observe4Greater1 observeIGreater1 + action 0 + 6487 : 1 +state 5887 observe4Greater1 observeIGreater1 + action 0 + 6488 : 0.833 + 6489 : 0.167 +state 5888 observe4Greater1 observeIGreater1 + action 0 + 6490 : 1 +state 5889 observe4Greater1 observeIGreater1 + action 0 + 6491 : 0.833 + 6492 : 0.167 +state 5890 observe4Greater1 observeIGreater1 + action 0 + 6493 : 1 +state 5891 observe4Greater1 observeIGreater1 + action 0 + 6494 : 0.833 + 6495 : 0.167 +state 5892 observe4Greater1 observeIGreater1 + action 0 + 6496 : 1 +state 5893 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5893 : 1 +state 5894 deadlock observe0Greater1 observe1Greater1 observeIGreater1 + action 0 + 5894 : 1 +state 5895 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5895 : 1 +state 5896 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5896 : 1 +state 5897 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5897 : 1 +state 5898 observe2Greater1 observeIGreater1 + action 0 + 6497 : 0.833 + 6498 : 0.167 +state 5899 observe2Greater1 observeIGreater1 + action 0 + 6499 : 0.833 + 6500 : 0.167 +state 5900 observe2Greater1 observeIGreater1 + action 0 + 6501 : 0.833 + 6502 : 0.167 +state 5901 observe2Greater1 observeIGreater1 + action 0 + 4761 : 0.833 + 4762 : 0.167 +state 5902 observe2Greater1 observeIGreater1 + action 0 + 6503 : 1 +state 5903 observe2Greater1 observeIGreater1 + action 0 + 6504 : 0.833 + 6505 : 0.167 +state 5904 observe2Greater1 observeIGreater1 + action 0 + 6506 : 1 +state 5905 observe2Greater1 observeIGreater1 + action 0 + 6507 : 0.833 + 6508 : 0.167 +state 5906 observe2Greater1 observeIGreater1 + action 0 + 6509 : 1 +state 5907 observe2Greater1 observeIGreater1 + action 0 + 6510 : 0.833 + 6511 : 0.167 +state 5908 observe2Greater1 observeIGreater1 + action 0 + 6512 : 1 +state 5909 observe2Greater1 observeIGreater1 + action 0 + 6513 : 0.833 + 6514 : 0.167 +state 5910 observe2Greater1 observeIGreater1 + action 0 + 6515 : 1 +state 5911 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5911 : 1 +state 5912 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 6516 : 0.833 + 6517 : 0.167 +state 5913 observe2Greater1 observeIGreater1 + action 0 + 6518 : 0.833 + 6519 : 0.167 +state 5914 observe2Greater1 observeIGreater1 + action 0 + 4768 : 0.833 + 4769 : 0.167 +state 5915 observe2Greater1 observeIGreater1 + action 0 + 6520 : 1 +state 5916 observe2Greater1 observeIGreater1 + action 0 + 6521 : 0.833 + 6522 : 0.167 +state 5917 observe2Greater1 observeIGreater1 + action 0 + 6523 : 1 +state 5918 observe2Greater1 observeIGreater1 + action 0 + 6524 : 0.833 + 6525 : 0.167 +state 5919 observe2Greater1 observeIGreater1 + action 0 + 6526 : 1 +state 5920 observe2Greater1 observeIGreater1 + action 0 + 6527 : 0.833 + 6528 : 0.167 +state 5921 observe2Greater1 observeIGreater1 + action 0 + 6529 : 1 +state 5922 observe2Greater1 observeIGreater1 + action 0 + 6530 : 0.833 + 6531 : 0.167 +state 5923 observe2Greater1 observeIGreater1 + action 0 + 6532 : 1 +state 5924 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5924 : 1 +state 5925 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 6533 : 0.833 + 6534 : 0.167 +state 5926 observe2Greater1 observeIGreater1 + action 0 + 4775 : 0.833 + 4776 : 0.167 +state 5927 observe2Greater1 observeIGreater1 + action 0 + 6535 : 1 +state 5928 observe2Greater1 observeIGreater1 + action 0 + 6536 : 0.833 + 6537 : 0.167 +state 5929 observe2Greater1 observeIGreater1 + action 0 + 6538 : 1 +state 5930 observe2Greater1 observeIGreater1 + action 0 + 6539 : 0.833 + 6540 : 0.167 +state 5931 observe2Greater1 observeIGreater1 + action 0 + 6541 : 1 +state 5932 observe2Greater1 observeIGreater1 + action 0 + 6542 : 0.833 + 6543 : 0.167 +state 5933 observe2Greater1 observeIGreater1 + action 0 + 6544 : 1 +state 5934 observe2Greater1 observeIGreater1 + action 0 + 6545 : 0.833 + 6546 : 0.167 +state 5935 observe2Greater1 observeIGreater1 + action 0 + 6547 : 1 +state 5936 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5936 : 1 +state 5937 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5937 : 1 +state 5938 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5938 : 1 +state 5939 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5939 : 1 +state 5940 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5940 : 1 +state 5941 observe3Greater1 observeIGreater1 + action 0 + 6548 : 0.833 + 6549 : 0.167 +state 5942 observe3Greater1 observeIGreater1 + action 0 + 6550 : 0.833 + 6551 : 0.167 +state 5943 observe3Greater1 observeIGreater1 + action 0 + 4795 : 0.833 + 4796 : 0.167 +state 5944 observe3Greater1 observeIGreater1 + action 0 + 6552 : 1 +state 5945 observe3Greater1 observeIGreater1 + action 0 + 6553 : 0.833 + 6554 : 0.167 +state 5946 observe3Greater1 observeIGreater1 + action 0 + 6555 : 1 +state 5947 observe3Greater1 observeIGreater1 + action 0 + 6556 : 0.833 + 6557 : 0.167 +state 5948 observe3Greater1 observeIGreater1 + action 0 + 6558 : 1 +state 5949 observe3Greater1 observeIGreater1 + action 0 + 6559 : 0.833 + 6560 : 0.167 +state 5950 observe3Greater1 observeIGreater1 + action 0 + 6561 : 1 +state 5951 observe3Greater1 observeIGreater1 + action 0 + 6562 : 0.833 + 6563 : 0.167 +state 5952 observe3Greater1 observeIGreater1 + action 0 + 6564 : 1 +state 5953 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5953 : 1 +state 5954 observe4Greater1 observeIGreater1 + action 0 + 6565 : 0.833 + 6566 : 0.167 +state 5955 + action 0 + 4802 : 0.833 + 4803 : 0.167 +state 5956 + action 0 + 6567 : 1 +state 5957 + action 0 + 6568 : 0.833 + 6569 : 0.167 +state 5958 + action 0 + 6570 : 1 +state 5959 + action 0 + 6571 : 0.833 + 6572 : 0.167 +state 5960 + action 0 + 6573 : 1 +state 5961 + action 0 + 6574 : 0.833 + 6575 : 0.167 +state 5962 + action 0 + 6576 : 1 +state 5963 + action 0 + 6577 : 0.833 + 6578 : 0.167 +state 5964 + action 0 + 6579 : 1 +state 5965 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5965 : 1 +state 5966 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5966 : 1 +state 5967 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5967 : 1 +state 5968 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5968 : 1 +state 5969 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5969 : 1 +state 5970 observe4Greater1 observeIGreater1 + action 0 + 6580 : 0.833 + 6581 : 0.167 +state 5971 observe4Greater1 observeIGreater1 + action 0 + 4822 : 0.833 + 4823 : 0.167 +state 5972 observe4Greater1 observeIGreater1 + action 0 + 6582 : 1 +state 5973 observe4Greater1 observeIGreater1 + action 0 + 6583 : 0.833 + 6584 : 0.167 +state 5974 observe4Greater1 observeIGreater1 + action 0 + 6585 : 1 +state 5975 observe4Greater1 observeIGreater1 + action 0 + 6586 : 0.833 + 6587 : 0.167 +state 5976 observe4Greater1 observeIGreater1 + action 0 + 6588 : 1 +state 5977 observe4Greater1 observeIGreater1 + action 0 + 6589 : 0.833 + 6590 : 0.167 +state 5978 observe4Greater1 observeIGreater1 + action 0 + 6591 : 1 +state 5979 observe4Greater1 observeIGreater1 + action 0 + 6592 : 0.833 + 6593 : 0.167 +state 5980 observe4Greater1 observeIGreater1 + action 0 + 6594 : 1 +state 5981 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5981 : 1 +state 5982 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5982 : 1 +state 5983 deadlock observe0Greater1 observe2Greater1 observeIGreater1 + action 0 + 5983 : 1 +state 5984 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 5984 : 1 +state 5985 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 5985 : 1 +state 5986 observe3Greater1 observeIGreater1 + action 0 + 6595 : 0.833 + 6596 : 0.167 +state 5987 observe3Greater1 observeIGreater1 + action 0 + 6597 : 0.833 + 6598 : 0.167 +state 5988 observe3Greater1 observeIGreater1 + action 0 + 4842 : 0.833 + 4843 : 0.167 +state 5989 observe3Greater1 observeIGreater1 + action 0 + 6599 : 1 +state 5990 observe3Greater1 observeIGreater1 + action 0 + 6600 : 0.833 + 6601 : 0.167 +state 5991 observe3Greater1 observeIGreater1 + action 0 + 6602 : 1 +state 5992 observe3Greater1 observeIGreater1 + action 0 + 6603 : 0.833 + 6604 : 0.167 +state 5993 observe3Greater1 observeIGreater1 + action 0 + 6605 : 1 +state 5994 observe3Greater1 observeIGreater1 + action 0 + 6606 : 0.833 + 6607 : 0.167 +state 5995 observe3Greater1 observeIGreater1 + action 0 + 6608 : 1 +state 5996 observe3Greater1 observeIGreater1 + action 0 + 6609 : 0.833 + 6610 : 0.167 +state 5997 observe3Greater1 observeIGreater1 + action 0 + 6611 : 1 +state 5998 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 5998 : 1 +state 5999 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 6612 : 0.833 + 6613 : 0.167 +state 6000 observe3Greater1 observeIGreater1 + action 0 + 4849 : 0.833 + 4850 : 0.167 +state 6001 observe3Greater1 observeIGreater1 + action 0 + 6614 : 1 +state 6002 observe3Greater1 observeIGreater1 + action 0 + 6615 : 0.833 + 6616 : 0.167 +state 6003 observe3Greater1 observeIGreater1 + action 0 + 6617 : 1 +state 6004 observe3Greater1 observeIGreater1 + action 0 + 6618 : 0.833 + 6619 : 0.167 +state 6005 observe3Greater1 observeIGreater1 + action 0 + 6620 : 1 +state 6006 observe3Greater1 observeIGreater1 + action 0 + 6621 : 0.833 + 6622 : 0.167 +state 6007 observe3Greater1 observeIGreater1 + action 0 + 6623 : 1 +state 6008 observe3Greater1 observeIGreater1 + action 0 + 6624 : 0.833 + 6625 : 0.167 +state 6009 observe3Greater1 observeIGreater1 + action 0 + 6626 : 1 +state 6010 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6010 : 1 +state 6011 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6011 : 1 +state 6012 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6012 : 1 +state 6013 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6013 : 1 +state 6014 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6014 : 1 +state 6015 observe4Greater1 observeIGreater1 + action 0 + 6627 : 0.833 + 6628 : 0.167 +state 6016 observe4Greater1 observeIGreater1 + action 0 + 4869 : 0.833 + 4870 : 0.167 +state 6017 observe4Greater1 observeIGreater1 + action 0 + 6629 : 1 +state 6018 observe4Greater1 observeIGreater1 + action 0 + 6630 : 0.833 + 6631 : 0.167 +state 6019 observe4Greater1 observeIGreater1 + action 0 + 6632 : 1 +state 6020 observe4Greater1 observeIGreater1 + action 0 + 6633 : 0.833 + 6634 : 0.167 +state 6021 observe4Greater1 observeIGreater1 + action 0 + 6635 : 1 +state 6022 observe4Greater1 observeIGreater1 + action 0 + 6636 : 0.833 + 6637 : 0.167 +state 6023 observe4Greater1 observeIGreater1 + action 0 + 6638 : 1 +state 6024 observe4Greater1 observeIGreater1 + action 0 + 6639 : 0.833 + 6640 : 0.167 +state 6025 observe4Greater1 observeIGreater1 + action 0 + 6641 : 1 +state 6026 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6026 : 1 +state 6027 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 6027 : 1 +state 6028 deadlock observe0Greater1 observeOnlyTrueSender + action 0 + 6028 : 1 +state 6029 deadlock observe0Greater1 observe3Greater1 observeIGreater1 + action 0 + 6029 : 1 +state 6030 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6030 : 1 +state 6031 observe4Greater1 observeIGreater1 + action 0 + 6642 : 0.833 + 6643 : 0.167 +state 6032 observe4Greater1 observeIGreater1 + action 0 + 4889 : 0.833 + 4890 : 0.167 +state 6033 observe4Greater1 observeIGreater1 + action 0 + 6644 : 1 +state 6034 observe4Greater1 observeIGreater1 + action 0 + 6645 : 0.833 + 6646 : 0.167 +state 6035 observe4Greater1 observeIGreater1 + action 0 + 6647 : 1 +state 6036 observe4Greater1 observeIGreater1 + action 0 + 6648 : 0.833 + 6649 : 0.167 +state 6037 observe4Greater1 observeIGreater1 + action 0 + 6650 : 1 +state 6038 observe4Greater1 observeIGreater1 + action 0 + 6651 : 0.833 + 6652 : 0.167 +state 6039 observe4Greater1 observeIGreater1 + action 0 + 6653 : 1 +state 6040 observe4Greater1 observeIGreater1 + action 0 + 6654 : 0.833 + 6655 : 0.167 +state 6041 observe4Greater1 observeIGreater1 + action 0 + 6656 : 1 +state 6042 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6042 : 1 +state 6043 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6043 : 1 +state 6044 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6044 : 1 +state 6045 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6045 : 1 +state 6046 deadlock observe0Greater1 observe4Greater1 observeIGreater1 + action 0 + 6046 : 1 +state 6047 observe1Greater1 observeIGreater1 + action 0 + 6657 : 1 +state 6048 observe1Greater1 observeIGreater1 + action 0 + 6658 : 1 +state 6049 observe1Greater1 observeIGreater1 + action 0 + 6659 : 1 +state 6050 observe1Greater1 observeIGreater1 + action 0 + 6660 : 1 +state 6051 observe1Greater1 observeIGreater1 + action 0 + 6661 : 1 +state 6052 observe2Greater1 observeIGreater1 + action 0 + 6662 : 1 +state 6053 + action 0 + 6663 : 1 +state 6054 + action 0 + 6664 : 1 +state 6055 observe1Greater1 observeIGreater1 + action 0 + 6665 : 1 +state 6056 + action 0 + 6666 : 1 +state 6057 observe3Greater1 observeIGreater1 + action 0 + 6667 : 1 +state 6058 + action 0 + 6668 : 1 +state 6059 observe1Greater1 observeIGreater1 + action 0 + 6669 : 1 +state 6060 + action 0 + 6670 : 1 +state 6061 + action 0 + 6671 : 1 +state 6062 observe4Greater1 observeIGreater1 + action 0 + 6672 : 1 +state 6063 observe2Greater1 observeIGreater1 + action 0 + 6673 : 1 +state 6064 observe2Greater1 observeIGreater1 + action 0 + 6674 : 1 +state 6065 observe2Greater1 observeIGreater1 + action 0 + 6675 : 1 +state 6066 observe2Greater1 observeIGreater1 + action 0 + 6676 : 1 +state 6067 + action 0 + 6677 : 1 +state 6068 observe2Greater1 observeIGreater1 + action 0 + 6678 : 1 +state 6069 observe3Greater1 observeIGreater1 + action 0 + 6679 : 1 +state 6070 + action 0 + 6680 : 1 +state 6071 + action 0 + 6681 : 1 +state 6072 observe2Greater1 observeIGreater1 + action 0 + 6682 : 1 +state 6073 + action 0 + 6683 : 1 +state 6074 observe4Greater1 observeIGreater1 + action 0 + 6684 : 1 +state 6075 observe3Greater1 observeIGreater1 + action 0 + 6685 : 1 +state 6076 observe3Greater1 observeIGreater1 + action 0 + 6686 : 1 +state 6077 observe3Greater1 observeIGreater1 + action 0 + 6687 : 1 +state 6078 observe3Greater1 observeIGreater1 + action 0 + 6688 : 1 +state 6079 + action 0 + 6689 : 1 +state 6080 + action 0 + 6690 : 1 +state 6081 observe3Greater1 observeIGreater1 + action 0 + 6691 : 1 +state 6082 observe4Greater1 observeIGreater1 + action 0 + 6692 : 1 +state 6083 observe4Greater1 observeIGreater1 + action 0 + 6693 : 1 +state 6084 observe4Greater1 observeIGreater1 + action 0 + 6694 : 1 +state 6085 observe4Greater1 observeIGreater1 + action 0 + 6695 : 1 +state 6086 observe4Greater1 observeIGreater1 + action 0 + 6696 : 1 +state 6087 observe1Greater1 observeIGreater1 + action 0 + 6697 : 1 +state 6088 observe1Greater1 observeIGreater1 + action 0 + 6698 : 0.833 + 6699 : 0.167 +state 6089 observe1Greater1 observeIGreater1 + action 0 + 6700 : 1 +state 6090 observe1Greater1 observeIGreater1 + action 0 + 6701 : 0.833 + 6702 : 0.167 +state 6091 observe1Greater1 observeIGreater1 + action 0 + 6703 : 1 +state 6092 observe1Greater1 observeIGreater1 + action 0 + 6704 : 0.833 + 6705 : 0.167 +state 6093 observe1Greater1 observeIGreater1 + action 0 + 6706 : 1 +state 6094 observe1Greater1 observeIGreater1 + action 0 + 6707 : 0.833 + 6708 : 0.167 +state 6095 observe1Greater1 observeIGreater1 + action 0 + 6709 : 1 +state 6096 deadlock observe1Greater1 observeIGreater1 + action 0 + 6096 : 1 +state 6097 observe1Greater1 observeIGreater1 + action 0 + 6710 : 1 +state 6098 observe1Greater1 observeIGreater1 + action 0 + 6711 : 0.833 + 6712 : 0.167 +state 6099 observe1Greater1 observeIGreater1 + action 0 + 6713 : 1 +state 6100 observe1Greater1 observeIGreater1 + action 0 + 6714 : 0.833 + 6715 : 0.167 +state 6101 observe1Greater1 observeIGreater1 + action 0 + 6716 : 1 +state 6102 observe1Greater1 observeIGreater1 + action 0 + 6717 : 0.833 + 6718 : 0.167 +state 6103 observe1Greater1 observeIGreater1 + action 0 + 6719 : 1 +state 6104 observe1Greater1 observeIGreater1 + action 0 + 6720 : 0.833 + 6721 : 0.167 +state 6105 observe1Greater1 observeIGreater1 + action 0 + 6722 : 1 +state 6106 deadlock observe1Greater1 observeIGreater1 + action 0 + 6106 : 1 +state 6107 observe1Greater1 observeIGreater1 + action 0 + 6723 : 1 +state 6108 observe1Greater1 observeIGreater1 + action 0 + 6724 : 0.833 + 6725 : 0.167 +state 6109 observe1Greater1 observeIGreater1 + action 0 + 6726 : 1 +state 6110 observe1Greater1 observeIGreater1 + action 0 + 6727 : 0.833 + 6728 : 0.167 +state 6111 observe1Greater1 observeIGreater1 + action 0 + 6729 : 1 +state 6112 observe1Greater1 observeIGreater1 + action 0 + 6730 : 0.833 + 6731 : 0.167 +state 6113 observe1Greater1 observeIGreater1 + action 0 + 6732 : 1 +state 6114 observe1Greater1 observeIGreater1 + action 0 + 6733 : 0.833 + 6734 : 0.167 +state 6115 observe1Greater1 observeIGreater1 + action 0 + 6735 : 1 +state 6116 deadlock observe1Greater1 observeIGreater1 + action 0 + 6116 : 1 +state 6117 observe1Greater1 observeIGreater1 + action 0 + 6736 : 1 +state 6118 observe1Greater1 observeIGreater1 + action 0 + 6737 : 0.833 + 6738 : 0.167 +state 6119 observe1Greater1 observeIGreater1 + action 0 + 6739 : 1 +state 6120 observe1Greater1 observeIGreater1 + action 0 + 6740 : 0.833 + 6741 : 0.167 +state 6121 observe1Greater1 observeIGreater1 + action 0 + 6742 : 1 +state 6122 observe1Greater1 observeIGreater1 + action 0 + 6743 : 0.833 + 6744 : 0.167 +state 6123 observe1Greater1 observeIGreater1 + action 0 + 6745 : 1 +state 6124 observe1Greater1 observeIGreater1 + action 0 + 6746 : 0.833 + 6747 : 0.167 +state 6125 observe1Greater1 observeIGreater1 + action 0 + 6748 : 1 +state 6126 deadlock observe1Greater1 observeIGreater1 + action 0 + 6126 : 1 +state 6127 deadlock observe1Greater1 observeIGreater1 + action 0 + 6127 : 1 +state 6128 deadlock observe1Greater1 observeIGreater1 + action 0 + 6128 : 1 +state 6129 deadlock observe1Greater1 observeIGreater1 + action 0 + 6129 : 1 +state 6130 deadlock observe1Greater1 observeIGreater1 + action 0 + 6130 : 1 +state 6131 observe2Greater1 observeIGreater1 + action 0 + 6749 : 1 +state 6132 observe2Greater1 observeIGreater1 + action 0 + 6750 : 0.833 + 6751 : 0.167 +state 6133 observe2Greater1 observeIGreater1 + action 0 + 6752 : 1 +state 6134 observe2Greater1 observeIGreater1 + action 0 + 6753 : 0.833 + 6754 : 0.167 +state 6135 observe2Greater1 observeIGreater1 + action 0 + 6755 : 1 +state 6136 observe2Greater1 observeIGreater1 + action 0 + 6756 : 0.833 + 6757 : 0.167 +state 6137 observe2Greater1 observeIGreater1 + action 0 + 6758 : 1 +state 6138 observe2Greater1 observeIGreater1 + action 0 + 6759 : 0.833 + 6760 : 0.167 +state 6139 observe2Greater1 observeIGreater1 + action 0 + 6761 : 1 +state 6140 deadlock observe2Greater1 observeIGreater1 + action 0 + 6140 : 1 +state 6141 + action 0 + 6762 : 1 +state 6142 + action 0 + 6763 : 0.833 + 6764 : 0.167 +state 6143 + action 0 + 6765 : 1 +state 6144 + action 0 + 6766 : 0.833 + 6767 : 0.167 +state 6145 + action 0 + 6768 : 1 +state 6146 + action 0 + 6769 : 0.833 + 6770 : 0.167 +state 6147 + action 0 + 6771 : 1 +state 6148 + action 0 + 6772 : 0.833 + 6773 : 0.167 +state 6149 + action 0 + 6774 : 1 +state 6150 deadlock + action 0 + 6150 : 1 +state 6151 + action 0 + 6775 : 1 +state 6152 + action 0 + 6776 : 0.833 + 6777 : 0.167 +state 6153 + action 0 + 6778 : 1 +state 6154 + action 0 + 6779 : 0.833 + 6780 : 0.167 +state 6155 + action 0 + 6781 : 1 +state 6156 + action 0 + 6782 : 0.833 + 6783 : 0.167 +state 6157 + action 0 + 6784 : 1 +state 6158 + action 0 + 6785 : 0.833 + 6786 : 0.167 +state 6159 + action 0 + 6787 : 1 +state 6160 deadlock + action 0 + 6160 : 1 +state 6161 deadlock observe1Greater1 observeIGreater1 + action 0 + 6161 : 1 +state 6162 deadlock observe2Greater1 observeIGreater1 + action 0 + 6162 : 1 +state 6163 deadlock + action 0 + 6163 : 1 +state 6164 deadlock + action 0 + 6164 : 1 +state 6165 observe3Greater1 observeIGreater1 + action 0 + 6788 : 1 +state 6166 observe3Greater1 observeIGreater1 + action 0 + 6789 : 0.833 + 6790 : 0.167 +state 6167 observe3Greater1 observeIGreater1 + action 0 + 6791 : 1 +state 6168 observe3Greater1 observeIGreater1 + action 0 + 6792 : 0.833 + 6793 : 0.167 +state 6169 observe3Greater1 observeIGreater1 + action 0 + 6794 : 1 +state 6170 observe3Greater1 observeIGreater1 + action 0 + 6795 : 0.833 + 6796 : 0.167 +state 6171 observe3Greater1 observeIGreater1 + action 0 + 6797 : 1 +state 6172 observe3Greater1 observeIGreater1 + action 0 + 6798 : 0.833 + 6799 : 0.167 +state 6173 observe3Greater1 observeIGreater1 + action 0 + 6800 : 1 +state 6174 deadlock observe3Greater1 observeIGreater1 + action 0 + 6174 : 1 +state 6175 + action 0 + 6801 : 1 +state 6176 + action 0 + 6802 : 0.833 + 6803 : 0.167 +state 6177 + action 0 + 6804 : 1 +state 6178 + action 0 + 6805 : 0.833 + 6806 : 0.167 +state 6179 + action 0 + 6807 : 1 +state 6180 + action 0 + 6808 : 0.833 + 6809 : 0.167 +state 6181 + action 0 + 6810 : 1 +state 6182 + action 0 + 6811 : 0.833 + 6812 : 0.167 +state 6183 + action 0 + 6813 : 1 +state 6184 deadlock + action 0 + 6184 : 1 +state 6185 deadlock observe1Greater1 observeIGreater1 + action 0 + 6185 : 1 +state 6186 deadlock + action 0 + 6186 : 1 +state 6187 deadlock observe3Greater1 observeIGreater1 + action 0 + 6187 : 1 +state 6188 deadlock + action 0 + 6188 : 1 +state 6189 observe4Greater1 observeIGreater1 + action 0 + 6814 : 1 +state 6190 observe4Greater1 observeIGreater1 + action 0 + 6815 : 0.833 + 6816 : 0.167 +state 6191 observe4Greater1 observeIGreater1 + action 0 + 6817 : 1 +state 6192 observe4Greater1 observeIGreater1 + action 0 + 6818 : 0.833 + 6819 : 0.167 +state 6193 observe4Greater1 observeIGreater1 + action 0 + 6820 : 1 +state 6194 observe4Greater1 observeIGreater1 + action 0 + 6821 : 0.833 + 6822 : 0.167 +state 6195 observe4Greater1 observeIGreater1 + action 0 + 6823 : 1 +state 6196 observe4Greater1 observeIGreater1 + action 0 + 6824 : 0.833 + 6825 : 0.167 +state 6197 observe4Greater1 observeIGreater1 + action 0 + 6826 : 1 +state 6198 deadlock observe4Greater1 observeIGreater1 + action 0 + 6198 : 1 +state 6199 deadlock observe1Greater1 observeIGreater1 + action 0 + 6199 : 1 +state 6200 deadlock + action 0 + 6200 : 1 +state 6201 deadlock + action 0 + 6201 : 1 +state 6202 deadlock observe4Greater1 observeIGreater1 + action 0 + 6202 : 1 +state 6203 observe2Greater1 observeIGreater1 + action 0 + 6827 : 1 +state 6204 observe2Greater1 observeIGreater1 + action 0 + 6828 : 0.833 + 6829 : 0.167 +state 6205 observe2Greater1 observeIGreater1 + action 0 + 6830 : 1 +state 6206 observe2Greater1 observeIGreater1 + action 0 + 6831 : 0.833 + 6832 : 0.167 +state 6207 observe2Greater1 observeIGreater1 + action 0 + 6833 : 1 +state 6208 observe2Greater1 observeIGreater1 + action 0 + 6834 : 0.833 + 6835 : 0.167 +state 6209 observe2Greater1 observeIGreater1 + action 0 + 6836 : 1 +state 6210 observe2Greater1 observeIGreater1 + action 0 + 6837 : 0.833 + 6838 : 0.167 +state 6211 observe2Greater1 observeIGreater1 + action 0 + 6839 : 1 +state 6212 deadlock observe2Greater1 observeIGreater1 + action 0 + 6212 : 1 +state 6213 observe2Greater1 observeIGreater1 + action 0 + 6840 : 1 +state 6214 observe2Greater1 observeIGreater1 + action 0 + 6841 : 0.833 + 6842 : 0.167 +state 6215 observe2Greater1 observeIGreater1 + action 0 + 6843 : 1 +state 6216 observe2Greater1 observeIGreater1 + action 0 + 6844 : 0.833 + 6845 : 0.167 +state 6217 observe2Greater1 observeIGreater1 + action 0 + 6846 : 1 +state 6218 observe2Greater1 observeIGreater1 + action 0 + 6847 : 0.833 + 6848 : 0.167 +state 6219 observe2Greater1 observeIGreater1 + action 0 + 6849 : 1 +state 6220 observe2Greater1 observeIGreater1 + action 0 + 6850 : 0.833 + 6851 : 0.167 +state 6221 observe2Greater1 observeIGreater1 + action 0 + 6852 : 1 +state 6222 deadlock observe2Greater1 observeIGreater1 + action 0 + 6222 : 1 +state 6223 observe2Greater1 observeIGreater1 + action 0 + 6853 : 1 +state 6224 observe2Greater1 observeIGreater1 + action 0 + 6854 : 0.833 + 6855 : 0.167 +state 6225 observe2Greater1 observeIGreater1 + action 0 + 6856 : 1 +state 6226 observe2Greater1 observeIGreater1 + action 0 + 6857 : 0.833 + 6858 : 0.167 +state 6227 observe2Greater1 observeIGreater1 + action 0 + 6859 : 1 +state 6228 observe2Greater1 observeIGreater1 + action 0 + 6860 : 0.833 + 6861 : 0.167 +state 6229 observe2Greater1 observeIGreater1 + action 0 + 6862 : 1 +state 6230 observe2Greater1 observeIGreater1 + action 0 + 6863 : 0.833 + 6864 : 0.167 +state 6231 observe2Greater1 observeIGreater1 + action 0 + 6865 : 1 +state 6232 deadlock observe2Greater1 observeIGreater1 + action 0 + 6232 : 1 +state 6233 deadlock observe2Greater1 observeIGreater1 + action 0 + 6233 : 1 +state 6234 deadlock observe2Greater1 observeIGreater1 + action 0 + 6234 : 1 +state 6235 deadlock observe2Greater1 observeIGreater1 + action 0 + 6235 : 1 +state 6236 deadlock observe2Greater1 observeIGreater1 + action 0 + 6236 : 1 +state 6237 observe3Greater1 observeIGreater1 + action 0 + 6866 : 1 +state 6238 observe3Greater1 observeIGreater1 + action 0 + 6867 : 0.833 + 6868 : 0.167 +state 6239 observe3Greater1 observeIGreater1 + action 0 + 6869 : 1 +state 6240 observe3Greater1 observeIGreater1 + action 0 + 6870 : 0.833 + 6871 : 0.167 +state 6241 observe3Greater1 observeIGreater1 + action 0 + 6872 : 1 +state 6242 observe3Greater1 observeIGreater1 + action 0 + 6873 : 0.833 + 6874 : 0.167 +state 6243 observe3Greater1 observeIGreater1 + action 0 + 6875 : 1 +state 6244 observe3Greater1 observeIGreater1 + action 0 + 6876 : 0.833 + 6877 : 0.167 +state 6245 observe3Greater1 observeIGreater1 + action 0 + 6878 : 1 +state 6246 deadlock observe3Greater1 observeIGreater1 + action 0 + 6246 : 1 +state 6247 + action 0 + 6879 : 1 +state 6248 + action 0 + 6880 : 0.833 + 6881 : 0.167 +state 6249 + action 0 + 6882 : 1 +state 6250 + action 0 + 6883 : 0.833 + 6884 : 0.167 +state 6251 + action 0 + 6885 : 1 +state 6252 + action 0 + 6886 : 0.833 + 6887 : 0.167 +state 6253 + action 0 + 6888 : 1 +state 6254 + action 0 + 6889 : 0.833 + 6890 : 0.167 +state 6255 + action 0 + 6891 : 1 +state 6256 deadlock + action 0 + 6256 : 1 +state 6257 deadlock + action 0 + 6257 : 1 +state 6258 deadlock observe2Greater1 observeIGreater1 + action 0 + 6258 : 1 +state 6259 deadlock observe3Greater1 observeIGreater1 + action 0 + 6259 : 1 +state 6260 deadlock + action 0 + 6260 : 1 +state 6261 observe4Greater1 observeIGreater1 + action 0 + 6892 : 1 +state 6262 observe4Greater1 observeIGreater1 + action 0 + 6893 : 0.833 + 6894 : 0.167 +state 6263 observe4Greater1 observeIGreater1 + action 0 + 6895 : 1 +state 6264 observe4Greater1 observeIGreater1 + action 0 + 6896 : 0.833 + 6897 : 0.167 +state 6265 observe4Greater1 observeIGreater1 + action 0 + 6898 : 1 +state 6266 observe4Greater1 observeIGreater1 + action 0 + 6899 : 0.833 + 6900 : 0.167 +state 6267 observe4Greater1 observeIGreater1 + action 0 + 6901 : 1 +state 6268 observe4Greater1 observeIGreater1 + action 0 + 6902 : 0.833 + 6903 : 0.167 +state 6269 observe4Greater1 observeIGreater1 + action 0 + 6904 : 1 +state 6270 deadlock observe4Greater1 observeIGreater1 + action 0 + 6270 : 1 +state 6271 deadlock + action 0 + 6271 : 1 +state 6272 deadlock observe2Greater1 observeIGreater1 + action 0 + 6272 : 1 +state 6273 deadlock + action 0 + 6273 : 1 +state 6274 deadlock observe4Greater1 observeIGreater1 + action 0 + 6274 : 1 +state 6275 observe3Greater1 observeIGreater1 + action 0 + 6905 : 1 +state 6276 observe3Greater1 observeIGreater1 + action 0 + 6906 : 0.833 + 6907 : 0.167 +state 6277 observe3Greater1 observeIGreater1 + action 0 + 6908 : 1 +state 6278 observe3Greater1 observeIGreater1 + action 0 + 6909 : 0.833 + 6910 : 0.167 +state 6279 observe3Greater1 observeIGreater1 + action 0 + 6911 : 1 +state 6280 observe3Greater1 observeIGreater1 + action 0 + 6912 : 0.833 + 6913 : 0.167 +state 6281 observe3Greater1 observeIGreater1 + action 0 + 6914 : 1 +state 6282 observe3Greater1 observeIGreater1 + action 0 + 6915 : 0.833 + 6916 : 0.167 +state 6283 observe3Greater1 observeIGreater1 + action 0 + 6917 : 1 +state 6284 deadlock observe3Greater1 observeIGreater1 + action 0 + 6284 : 1 +state 6285 observe3Greater1 observeIGreater1 + action 0 + 6918 : 1 +state 6286 observe3Greater1 observeIGreater1 + action 0 + 6919 : 0.833 + 6920 : 0.167 +state 6287 observe3Greater1 observeIGreater1 + action 0 + 6921 : 1 +state 6288 observe3Greater1 observeIGreater1 + action 0 + 6922 : 0.833 + 6923 : 0.167 +state 6289 observe3Greater1 observeIGreater1 + action 0 + 6924 : 1 +state 6290 observe3Greater1 observeIGreater1 + action 0 + 6925 : 0.833 + 6926 : 0.167 +state 6291 observe3Greater1 observeIGreater1 + action 0 + 6927 : 1 +state 6292 observe3Greater1 observeIGreater1 + action 0 + 6928 : 0.833 + 6929 : 0.167 +state 6293 observe3Greater1 observeIGreater1 + action 0 + 6930 : 1 +state 6294 deadlock observe3Greater1 observeIGreater1 + action 0 + 6294 : 1 +state 6295 deadlock observe3Greater1 observeIGreater1 + action 0 + 6295 : 1 +state 6296 deadlock observe3Greater1 observeIGreater1 + action 0 + 6296 : 1 +state 6297 deadlock observe3Greater1 observeIGreater1 + action 0 + 6297 : 1 +state 6298 deadlock observe3Greater1 observeIGreater1 + action 0 + 6298 : 1 +state 6299 observe4Greater1 observeIGreater1 + action 0 + 6931 : 1 +state 6300 observe4Greater1 observeIGreater1 + action 0 + 6932 : 0.833 + 6933 : 0.167 +state 6301 observe4Greater1 observeIGreater1 + action 0 + 6934 : 1 +state 6302 observe4Greater1 observeIGreater1 + action 0 + 6935 : 0.833 + 6936 : 0.167 +state 6303 observe4Greater1 observeIGreater1 + action 0 + 6937 : 1 +state 6304 observe4Greater1 observeIGreater1 + action 0 + 6938 : 0.833 + 6939 : 0.167 +state 6305 observe4Greater1 observeIGreater1 + action 0 + 6940 : 1 +state 6306 observe4Greater1 observeIGreater1 + action 0 + 6941 : 0.833 + 6942 : 0.167 +state 6307 observe4Greater1 observeIGreater1 + action 0 + 6943 : 1 +state 6308 deadlock observe4Greater1 observeIGreater1 + action 0 + 6308 : 1 +state 6309 deadlock + action 0 + 6309 : 1 +state 6310 deadlock + action 0 + 6310 : 1 +state 6311 deadlock observe3Greater1 observeIGreater1 + action 0 + 6311 : 1 +state 6312 deadlock observe4Greater1 observeIGreater1 + action 0 + 6312 : 1 +state 6313 observe4Greater1 observeIGreater1 + action 0 + 6944 : 1 +state 6314 observe4Greater1 observeIGreater1 + action 0 + 6945 : 0.833 + 6946 : 0.167 +state 6315 observe4Greater1 observeIGreater1 + action 0 + 6947 : 1 +state 6316 observe4Greater1 observeIGreater1 + action 0 + 6948 : 0.833 + 6949 : 0.167 +state 6317 observe4Greater1 observeIGreater1 + action 0 + 6950 : 1 +state 6318 observe4Greater1 observeIGreater1 + action 0 + 6951 : 0.833 + 6952 : 0.167 +state 6319 observe4Greater1 observeIGreater1 + action 0 + 6953 : 1 +state 6320 observe4Greater1 observeIGreater1 + action 0 + 6954 : 0.833 + 6955 : 0.167 +state 6321 observe4Greater1 observeIGreater1 + action 0 + 6956 : 1 +state 6322 deadlock observe4Greater1 observeIGreater1 + action 0 + 6322 : 1 +state 6323 deadlock observe4Greater1 observeIGreater1 + action 0 + 6323 : 1 +state 6324 deadlock observe4Greater1 observeIGreater1 + action 0 + 6324 : 1 +state 6325 deadlock observe4Greater1 observeIGreater1 + action 0 + 6325 : 1 +state 6326 deadlock observe4Greater1 observeIGreater1 + action 0 + 6326 : 1 +state 6327 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 6328 observe1Greater1 observeIGreater1 + action 0 + 6962 : 1 +state 6329 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 6330 observe1Greater1 observeIGreater1 + action 0 + 6968 : 1 +state 6331 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 6332 observe1Greater1 observeIGreater1 + action 0 + 6974 : 1 +state 6333 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 6334 observe1Greater1 observeIGreater1 + action 0 + 6980 : 1 +state 6335 deadlock observe1Greater1 observeIGreater1 + action 0 + 6335 : 1 +state 6336 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6337 observe1Greater1 observeIGreater1 + action 0 + 6981 : 1 +state 6338 deadlock observe1Greater1 observeIGreater1 + action 0 + 6338 : 1 +state 6339 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6340 observe1Greater1 observeIGreater1 + action 0 + 6982 : 1 +state 6341 deadlock observe1Greater1 observeIGreater1 + action 0 + 6341 : 1 +state 6342 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6343 observe1Greater1 observeIGreater1 + action 0 + 6983 : 1 +state 6344 deadlock observe1Greater1 observeIGreater1 + action 0 + 6344 : 1 +state 6345 observe1Greater1 observeIGreater1 + action 0 + 5210 : 0.2 + 5211 : 0.2 + 5212 : 0.2 + 5213 : 0.2 + 5214 : 0.2 +state 6346 observe1Greater1 observeIGreater1 + action 0 + 6984 : 1 +state 6347 deadlock observe1Greater1 observeIGreater1 + action 0 + 6347 : 1 +state 6348 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 6349 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6990 : 1 +state 6350 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 6351 observe1Greater1 observeIGreater1 + action 0 + 6996 : 1 +state 6352 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 6353 observe1Greater1 observeIGreater1 + action 0 + 7002 : 1 +state 6354 deadlock observe1Greater1 observeIGreater1 + action 0 + 6354 : 1 +state 6355 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6356 observe1Greater1 observeIGreater1 + action 0 + 7003 : 1 +state 6357 deadlock observe1Greater1 observeIGreater1 + action 0 + 6357 : 1 +state 6358 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6359 observe1Greater1 observeIGreater1 + action 0 + 7004 : 1 +state 6360 deadlock observe1Greater1 observeIGreater1 + action 0 + 6360 : 1 +state 6361 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6362 observe1Greater1 observeIGreater1 + action 0 + 7005 : 1 +state 6363 deadlock observe1Greater1 observeIGreater1 + action 0 + 6363 : 1 +state 6364 observe1Greater1 observeIGreater1 + action 0 + 5220 : 0.2 + 5221 : 0.2 + 5222 : 0.2 + 5223 : 0.2 + 5224 : 0.2 +state 6365 observe1Greater1 observeIGreater1 + action 0 + 7006 : 1 +state 6366 deadlock observe1Greater1 observeIGreater1 + action 0 + 6366 : 1 +state 6367 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 6368 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7012 : 1 +state 6369 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 6370 observe1Greater1 observeIGreater1 + action 0 + 7018 : 1 +state 6371 deadlock observe1Greater1 observeIGreater1 + action 0 + 6371 : 1 +state 6372 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6373 observe1Greater1 observeIGreater1 + action 0 + 7019 : 1 +state 6374 deadlock observe1Greater1 observeIGreater1 + action 0 + 6374 : 1 +state 6375 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6376 observe1Greater1 observeIGreater1 + action 0 + 7020 : 1 +state 6377 deadlock observe1Greater1 observeIGreater1 + action 0 + 6377 : 1 +state 6378 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6379 observe1Greater1 observeIGreater1 + action 0 + 7021 : 1 +state 6380 deadlock observe1Greater1 observeIGreater1 + action 0 + 6380 : 1 +state 6381 observe1Greater1 observeIGreater1 + action 0 + 5230 : 0.2 + 5231 : 0.2 + 5232 : 0.2 + 5233 : 0.2 + 5234 : 0.2 +state 6382 observe1Greater1 observeIGreater1 + action 0 + 7022 : 1 +state 6383 deadlock observe1Greater1 observeIGreater1 + action 0 + 6383 : 1 +state 6384 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 6385 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7028 : 1 +state 6386 deadlock observe1Greater1 observeIGreater1 + action 0 + 6386 : 1 +state 6387 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6388 observe1Greater1 observeIGreater1 + action 0 + 7029 : 1 +state 6389 deadlock observe1Greater1 observeIGreater1 + action 0 + 6389 : 1 +state 6390 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6391 observe1Greater1 observeIGreater1 + action 0 + 7030 : 1 +state 6392 deadlock observe1Greater1 observeIGreater1 + action 0 + 6392 : 1 +state 6393 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6394 observe1Greater1 observeIGreater1 + action 0 + 7031 : 1 +state 6395 deadlock observe1Greater1 observeIGreater1 + action 0 + 6395 : 1 +state 6396 observe1Greater1 observeIGreater1 + action 0 + 5240 : 0.2 + 5241 : 0.2 + 5242 : 0.2 + 5243 : 0.2 + 5244 : 0.2 +state 6397 observe1Greater1 observeIGreater1 + action 0 + 7032 : 1 +state 6398 deadlock observe1Greater1 observeIGreater1 + action 0 + 6398 : 1 +state 6399 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 6400 observe2Greater1 observeIGreater1 + action 0 + 7038 : 1 +state 6401 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 6402 observe2Greater1 observeIGreater1 + action 0 + 7044 : 1 +state 6403 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 6404 observe2Greater1 observeIGreater1 + action 0 + 7050 : 1 +state 6405 deadlock observe2Greater1 observeIGreater1 + action 0 + 6405 : 1 +state 6406 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6407 observe2Greater1 observeIGreater1 + action 0 + 7051 : 1 +state 6408 deadlock observe2Greater1 observeIGreater1 + action 0 + 6408 : 1 +state 6409 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6410 observe2Greater1 observeIGreater1 + action 0 + 7052 : 1 +state 6411 deadlock observe2Greater1 observeIGreater1 + action 0 + 6411 : 1 +state 6412 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6413 observe2Greater1 observeIGreater1 + action 0 + 7053 : 1 +state 6414 deadlock observe2Greater1 observeIGreater1 + action 0 + 6414 : 1 +state 6415 observe2Greater1 observeIGreater1 + action 0 + 5254 : 0.2 + 5255 : 0.2 + 5256 : 0.2 + 5257 : 0.2 + 5258 : 0.2 +state 6416 observe2Greater1 observeIGreater1 + action 0 + 7054 : 1 +state 6417 deadlock observe2Greater1 observeIGreater1 + action 0 + 6417 : 1 +state 6418 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 6419 observe3Greater1 observeIGreater1 + action 0 + 7060 : 1 +state 6420 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 6421 + action 0 + 7066 : 1 +state 6422 deadlock + action 0 + 6422 : 1 +state 6423 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6424 + action 0 + 7067 : 1 +state 6425 deadlock + action 0 + 6425 : 1 +state 6426 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6427 + action 0 + 7068 : 1 +state 6428 deadlock + action 0 + 6428 : 1 +state 6429 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6430 + action 0 + 7069 : 1 +state 6431 deadlock + action 0 + 6431 : 1 +state 6432 + action 0 + 5264 : 0.2 + 5265 : 0.2 + 5266 : 0.2 + 5267 : 0.2 + 5268 : 0.2 +state 6433 + action 0 + 7070 : 1 +state 6434 deadlock + action 0 + 6434 : 1 +state 6435 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 6436 observe4Greater1 observeIGreater1 + action 0 + 7076 : 1 +state 6437 deadlock + action 0 + 6437 : 1 +state 6438 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6439 + action 0 + 7077 : 1 +state 6440 deadlock + action 0 + 6440 : 1 +state 6441 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6442 + action 0 + 7078 : 1 +state 6443 deadlock + action 0 + 6443 : 1 +state 6444 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6445 + action 0 + 7079 : 1 +state 6446 deadlock + action 0 + 6446 : 1 +state 6447 + action 0 + 5274 : 0.2 + 5275 : 0.2 + 5276 : 0.2 + 5277 : 0.2 + 5278 : 0.2 +state 6448 + action 0 + 7080 : 1 +state 6449 deadlock + action 0 + 6449 : 1 +state 6450 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 6451 observe3Greater1 observeIGreater1 + action 0 + 7086 : 1 +state 6452 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 6453 observe3Greater1 observeIGreater1 + action 0 + 7092 : 1 +state 6454 deadlock observe3Greater1 observeIGreater1 + action 0 + 6454 : 1 +state 6455 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6456 observe3Greater1 observeIGreater1 + action 0 + 7093 : 1 +state 6457 deadlock observe3Greater1 observeIGreater1 + action 0 + 6457 : 1 +state 6458 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6459 observe3Greater1 observeIGreater1 + action 0 + 7094 : 1 +state 6460 deadlock observe3Greater1 observeIGreater1 + action 0 + 6460 : 1 +state 6461 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6462 observe3Greater1 observeIGreater1 + action 0 + 7095 : 1 +state 6463 deadlock observe3Greater1 observeIGreater1 + action 0 + 6463 : 1 +state 6464 observe3Greater1 observeIGreater1 + action 0 + 5288 : 0.2 + 5289 : 0.2 + 5290 : 0.2 + 5291 : 0.2 + 5292 : 0.2 +state 6465 observe3Greater1 observeIGreater1 + action 0 + 7096 : 1 +state 6466 deadlock observe3Greater1 observeIGreater1 + action 0 + 6466 : 1 +state 6467 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 6468 observe4Greater1 observeIGreater1 + action 0 + 7102 : 1 +state 6469 deadlock + action 0 + 6469 : 1 +state 6470 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6471 + action 0 + 7103 : 1 +state 6472 deadlock + action 0 + 6472 : 1 +state 6473 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6474 + action 0 + 7104 : 1 +state 6475 deadlock + action 0 + 6475 : 1 +state 6476 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6477 + action 0 + 7105 : 1 +state 6478 deadlock + action 0 + 6478 : 1 +state 6479 + action 0 + 5298 : 0.2 + 5299 : 0.2 + 5300 : 0.2 + 5301 : 0.2 + 5302 : 0.2 +state 6480 + action 0 + 7106 : 1 +state 6481 deadlock + action 0 + 6481 : 1 +state 6482 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 6483 observe4Greater1 observeIGreater1 + action 0 + 7112 : 1 +state 6484 deadlock observe4Greater1 observeIGreater1 + action 0 + 6484 : 1 +state 6485 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6486 observe4Greater1 observeIGreater1 + action 0 + 7113 : 1 +state 6487 deadlock observe4Greater1 observeIGreater1 + action 0 + 6487 : 1 +state 6488 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6489 observe4Greater1 observeIGreater1 + action 0 + 7114 : 1 +state 6490 deadlock observe4Greater1 observeIGreater1 + action 0 + 6490 : 1 +state 6491 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6492 observe4Greater1 observeIGreater1 + action 0 + 7115 : 1 +state 6493 deadlock observe4Greater1 observeIGreater1 + action 0 + 6493 : 1 +state 6494 observe4Greater1 observeIGreater1 + action 0 + 5312 : 0.2 + 5313 : 0.2 + 5314 : 0.2 + 5315 : 0.2 + 5316 : 0.2 +state 6495 observe4Greater1 observeIGreater1 + action 0 + 7116 : 1 +state 6496 deadlock observe4Greater1 observeIGreater1 + action 0 + 6496 : 1 +state 6497 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 6498 observe2Greater1 observeIGreater1 + action 0 + 7122 : 1 +state 6499 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 6500 observe2Greater1 observeIGreater1 + action 0 + 7128 : 1 +state 6501 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 6502 observe2Greater1 observeIGreater1 + action 0 + 7134 : 1 +state 6503 deadlock observe2Greater1 observeIGreater1 + action 0 + 6503 : 1 +state 6504 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6505 observe2Greater1 observeIGreater1 + action 0 + 7135 : 1 +state 6506 deadlock observe2Greater1 observeIGreater1 + action 0 + 6506 : 1 +state 6507 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6508 observe2Greater1 observeIGreater1 + action 0 + 7136 : 1 +state 6509 deadlock observe2Greater1 observeIGreater1 + action 0 + 6509 : 1 +state 6510 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6511 observe2Greater1 observeIGreater1 + action 0 + 7137 : 1 +state 6512 deadlock observe2Greater1 observeIGreater1 + action 0 + 6512 : 1 +state 6513 observe2Greater1 observeIGreater1 + action 0 + 5326 : 0.2 + 5327 : 0.2 + 5328 : 0.2 + 5329 : 0.2 + 5330 : 0.2 +state 6514 observe2Greater1 observeIGreater1 + action 0 + 7138 : 1 +state 6515 deadlock observe2Greater1 observeIGreater1 + action 0 + 6515 : 1 +state 6516 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 6517 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7144 : 1 +state 6518 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 6519 observe2Greater1 observeIGreater1 + action 0 + 7150 : 1 +state 6520 deadlock observe2Greater1 observeIGreater1 + action 0 + 6520 : 1 +state 6521 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6522 observe2Greater1 observeIGreater1 + action 0 + 7151 : 1 +state 6523 deadlock observe2Greater1 observeIGreater1 + action 0 + 6523 : 1 +state 6524 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6525 observe2Greater1 observeIGreater1 + action 0 + 7152 : 1 +state 6526 deadlock observe2Greater1 observeIGreater1 + action 0 + 6526 : 1 +state 6527 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6528 observe2Greater1 observeIGreater1 + action 0 + 7153 : 1 +state 6529 deadlock observe2Greater1 observeIGreater1 + action 0 + 6529 : 1 +state 6530 observe2Greater1 observeIGreater1 + action 0 + 5336 : 0.2 + 5337 : 0.2 + 5338 : 0.2 + 5339 : 0.2 + 5340 : 0.2 +state 6531 observe2Greater1 observeIGreater1 + action 0 + 7154 : 1 +state 6532 deadlock observe2Greater1 observeIGreater1 + action 0 + 6532 : 1 +state 6533 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 6534 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7160 : 1 +state 6535 deadlock observe2Greater1 observeIGreater1 + action 0 + 6535 : 1 +state 6536 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6537 observe2Greater1 observeIGreater1 + action 0 + 7161 : 1 +state 6538 deadlock observe2Greater1 observeIGreater1 + action 0 + 6538 : 1 +state 6539 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6540 observe2Greater1 observeIGreater1 + action 0 + 7162 : 1 +state 6541 deadlock observe2Greater1 observeIGreater1 + action 0 + 6541 : 1 +state 6542 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6543 observe2Greater1 observeIGreater1 + action 0 + 7163 : 1 +state 6544 deadlock observe2Greater1 observeIGreater1 + action 0 + 6544 : 1 +state 6545 observe2Greater1 observeIGreater1 + action 0 + 5346 : 0.2 + 5347 : 0.2 + 5348 : 0.2 + 5349 : 0.2 + 5350 : 0.2 +state 6546 observe2Greater1 observeIGreater1 + action 0 + 7164 : 1 +state 6547 deadlock observe2Greater1 observeIGreater1 + action 0 + 6547 : 1 +state 6548 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 6549 observe3Greater1 observeIGreater1 + action 0 + 7170 : 1 +state 6550 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 6551 observe3Greater1 observeIGreater1 + action 0 + 7176 : 1 +state 6552 deadlock observe3Greater1 observeIGreater1 + action 0 + 6552 : 1 +state 6553 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6554 observe3Greater1 observeIGreater1 + action 0 + 7177 : 1 +state 6555 deadlock observe3Greater1 observeIGreater1 + action 0 + 6555 : 1 +state 6556 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6557 observe3Greater1 observeIGreater1 + action 0 + 7178 : 1 +state 6558 deadlock observe3Greater1 observeIGreater1 + action 0 + 6558 : 1 +state 6559 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6560 observe3Greater1 observeIGreater1 + action 0 + 7179 : 1 +state 6561 deadlock observe3Greater1 observeIGreater1 + action 0 + 6561 : 1 +state 6562 observe3Greater1 observeIGreater1 + action 0 + 5360 : 0.2 + 5361 : 0.2 + 5362 : 0.2 + 5363 : 0.2 + 5364 : 0.2 +state 6563 observe3Greater1 observeIGreater1 + action 0 + 7180 : 1 +state 6564 deadlock observe3Greater1 observeIGreater1 + action 0 + 6564 : 1 +state 6565 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 6566 observe4Greater1 observeIGreater1 + action 0 + 7186 : 1 +state 6567 deadlock + action 0 + 6567 : 1 +state 6568 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6569 + action 0 + 7187 : 1 +state 6570 deadlock + action 0 + 6570 : 1 +state 6571 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6572 + action 0 + 7188 : 1 +state 6573 deadlock + action 0 + 6573 : 1 +state 6574 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6575 + action 0 + 7189 : 1 +state 6576 deadlock + action 0 + 6576 : 1 +state 6577 + action 0 + 5370 : 0.2 + 5371 : 0.2 + 5372 : 0.2 + 5373 : 0.2 + 5374 : 0.2 +state 6578 + action 0 + 7190 : 1 +state 6579 deadlock + action 0 + 6579 : 1 +state 6580 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 6581 observe4Greater1 observeIGreater1 + action 0 + 7196 : 1 +state 6582 deadlock observe4Greater1 observeIGreater1 + action 0 + 6582 : 1 +state 6583 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6584 observe4Greater1 observeIGreater1 + action 0 + 7197 : 1 +state 6585 deadlock observe4Greater1 observeIGreater1 + action 0 + 6585 : 1 +state 6586 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6587 observe4Greater1 observeIGreater1 + action 0 + 7198 : 1 +state 6588 deadlock observe4Greater1 observeIGreater1 + action 0 + 6588 : 1 +state 6589 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6590 observe4Greater1 observeIGreater1 + action 0 + 7199 : 1 +state 6591 deadlock observe4Greater1 observeIGreater1 + action 0 + 6591 : 1 +state 6592 observe4Greater1 observeIGreater1 + action 0 + 5384 : 0.2 + 5385 : 0.2 + 5386 : 0.2 + 5387 : 0.2 + 5388 : 0.2 +state 6593 observe4Greater1 observeIGreater1 + action 0 + 7200 : 1 +state 6594 deadlock observe4Greater1 observeIGreater1 + action 0 + 6594 : 1 +state 6595 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 6596 observe3Greater1 observeIGreater1 + action 0 + 7206 : 1 +state 6597 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 6598 observe3Greater1 observeIGreater1 + action 0 + 7212 : 1 +state 6599 deadlock observe3Greater1 observeIGreater1 + action 0 + 6599 : 1 +state 6600 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6601 observe3Greater1 observeIGreater1 + action 0 + 7213 : 1 +state 6602 deadlock observe3Greater1 observeIGreater1 + action 0 + 6602 : 1 +state 6603 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6604 observe3Greater1 observeIGreater1 + action 0 + 7214 : 1 +state 6605 deadlock observe3Greater1 observeIGreater1 + action 0 + 6605 : 1 +state 6606 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6607 observe3Greater1 observeIGreater1 + action 0 + 7215 : 1 +state 6608 deadlock observe3Greater1 observeIGreater1 + action 0 + 6608 : 1 +state 6609 observe3Greater1 observeIGreater1 + action 0 + 5398 : 0.2 + 5399 : 0.2 + 5400 : 0.2 + 5401 : 0.2 + 5402 : 0.2 +state 6610 observe3Greater1 observeIGreater1 + action 0 + 7216 : 1 +state 6611 deadlock observe3Greater1 observeIGreater1 + action 0 + 6611 : 1 +state 6612 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 6613 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7222 : 1 +state 6614 deadlock observe3Greater1 observeIGreater1 + action 0 + 6614 : 1 +state 6615 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6616 observe3Greater1 observeIGreater1 + action 0 + 7223 : 1 +state 6617 deadlock observe3Greater1 observeIGreater1 + action 0 + 6617 : 1 +state 6618 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6619 observe3Greater1 observeIGreater1 + action 0 + 7224 : 1 +state 6620 deadlock observe3Greater1 observeIGreater1 + action 0 + 6620 : 1 +state 6621 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6622 observe3Greater1 observeIGreater1 + action 0 + 7225 : 1 +state 6623 deadlock observe3Greater1 observeIGreater1 + action 0 + 6623 : 1 +state 6624 observe3Greater1 observeIGreater1 + action 0 + 5408 : 0.2 + 5409 : 0.2 + 5410 : 0.2 + 5411 : 0.2 + 5412 : 0.2 +state 6625 observe3Greater1 observeIGreater1 + action 0 + 7226 : 1 +state 6626 deadlock observe3Greater1 observeIGreater1 + action 0 + 6626 : 1 +state 6627 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 6628 observe4Greater1 observeIGreater1 + action 0 + 7232 : 1 +state 6629 deadlock observe4Greater1 observeIGreater1 + action 0 + 6629 : 1 +state 6630 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6631 observe4Greater1 observeIGreater1 + action 0 + 7233 : 1 +state 6632 deadlock observe4Greater1 observeIGreater1 + action 0 + 6632 : 1 +state 6633 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6634 observe4Greater1 observeIGreater1 + action 0 + 7234 : 1 +state 6635 deadlock observe4Greater1 observeIGreater1 + action 0 + 6635 : 1 +state 6636 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6637 observe4Greater1 observeIGreater1 + action 0 + 7235 : 1 +state 6638 deadlock observe4Greater1 observeIGreater1 + action 0 + 6638 : 1 +state 6639 observe4Greater1 observeIGreater1 + action 0 + 5422 : 0.2 + 5423 : 0.2 + 5424 : 0.2 + 5425 : 0.2 + 5426 : 0.2 +state 6640 observe4Greater1 observeIGreater1 + action 0 + 7236 : 1 +state 6641 deadlock observe4Greater1 observeIGreater1 + action 0 + 6641 : 1 +state 6642 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 6643 observe4Greater1 observeIGreater1 + action 0 + 7242 : 1 +state 6644 deadlock observe4Greater1 observeIGreater1 + action 0 + 6644 : 1 +state 6645 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6646 observe4Greater1 observeIGreater1 + action 0 + 7243 : 1 +state 6647 deadlock observe4Greater1 observeIGreater1 + action 0 + 6647 : 1 +state 6648 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6649 observe4Greater1 observeIGreater1 + action 0 + 7244 : 1 +state 6650 deadlock observe4Greater1 observeIGreater1 + action 0 + 6650 : 1 +state 6651 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6652 observe4Greater1 observeIGreater1 + action 0 + 7245 : 1 +state 6653 deadlock observe4Greater1 observeIGreater1 + action 0 + 6653 : 1 +state 6654 observe4Greater1 observeIGreater1 + action 0 + 5436 : 0.2 + 5437 : 0.2 + 5438 : 0.2 + 5439 : 0.2 + 5440 : 0.2 +state 6655 observe4Greater1 observeIGreater1 + action 0 + 7246 : 1 +state 6656 deadlock observe4Greater1 observeIGreater1 + action 0 + 6656 : 1 +state 6657 deadlock observe1Greater1 observeIGreater1 + action 0 + 6657 : 1 +state 6658 deadlock observe1Greater1 observeIGreater1 + action 0 + 6658 : 1 +state 6659 deadlock observe1Greater1 observeIGreater1 + action 0 + 6659 : 1 +state 6660 deadlock observe1Greater1 observeIGreater1 + action 0 + 6660 : 1 +state 6661 deadlock observe1Greater1 observeIGreater1 + action 0 + 6661 : 1 +state 6662 deadlock observe2Greater1 observeIGreater1 + action 0 + 6662 : 1 +state 6663 deadlock + action 0 + 6663 : 1 +state 6664 deadlock + action 0 + 6664 : 1 +state 6665 deadlock observe1Greater1 observeIGreater1 + action 0 + 6665 : 1 +state 6666 deadlock + action 0 + 6666 : 1 +state 6667 deadlock observe3Greater1 observeIGreater1 + action 0 + 6667 : 1 +state 6668 deadlock + action 0 + 6668 : 1 +state 6669 deadlock observe1Greater1 observeIGreater1 + action 0 + 6669 : 1 +state 6670 deadlock + action 0 + 6670 : 1 +state 6671 deadlock + action 0 + 6671 : 1 +state 6672 deadlock observe4Greater1 observeIGreater1 + action 0 + 6672 : 1 +state 6673 deadlock observe2Greater1 observeIGreater1 + action 0 + 6673 : 1 +state 6674 deadlock observe2Greater1 observeIGreater1 + action 0 + 6674 : 1 +state 6675 deadlock observe2Greater1 observeIGreater1 + action 0 + 6675 : 1 +state 6676 deadlock observe2Greater1 observeIGreater1 + action 0 + 6676 : 1 +state 6677 deadlock + action 0 + 6677 : 1 +state 6678 deadlock observe2Greater1 observeIGreater1 + action 0 + 6678 : 1 +state 6679 deadlock observe3Greater1 observeIGreater1 + action 0 + 6679 : 1 +state 6680 deadlock + action 0 + 6680 : 1 +state 6681 deadlock + action 0 + 6681 : 1 +state 6682 deadlock observe2Greater1 observeIGreater1 + action 0 + 6682 : 1 +state 6683 deadlock + action 0 + 6683 : 1 +state 6684 deadlock observe4Greater1 observeIGreater1 + action 0 + 6684 : 1 +state 6685 deadlock observe3Greater1 observeIGreater1 + action 0 + 6685 : 1 +state 6686 deadlock observe3Greater1 observeIGreater1 + action 0 + 6686 : 1 +state 6687 deadlock observe3Greater1 observeIGreater1 + action 0 + 6687 : 1 +state 6688 deadlock observe3Greater1 observeIGreater1 + action 0 + 6688 : 1 +state 6689 deadlock + action 0 + 6689 : 1 +state 6690 deadlock + action 0 + 6690 : 1 +state 6691 deadlock observe3Greater1 observeIGreater1 + action 0 + 6691 : 1 +state 6692 deadlock observe4Greater1 observeIGreater1 + action 0 + 6692 : 1 +state 6693 deadlock observe4Greater1 observeIGreater1 + action 0 + 6693 : 1 +state 6694 deadlock observe4Greater1 observeIGreater1 + action 0 + 6694 : 1 +state 6695 deadlock observe4Greater1 observeIGreater1 + action 0 + 6695 : 1 +state 6696 deadlock observe4Greater1 observeIGreater1 + action 0 + 6696 : 1 +state 6697 deadlock observe1Greater1 observeIGreater1 + action 0 + 6697 : 1 +state 6698 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6699 observe1Greater1 observeIGreater1 + action 0 + 7247 : 1 +state 6700 deadlock observe1Greater1 observeIGreater1 + action 0 + 6700 : 1 +state 6701 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6702 observe1Greater1 observeIGreater1 + action 0 + 7248 : 1 +state 6703 deadlock observe1Greater1 observeIGreater1 + action 0 + 6703 : 1 +state 6704 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6705 observe1Greater1 observeIGreater1 + action 0 + 7249 : 1 +state 6706 deadlock observe1Greater1 observeIGreater1 + action 0 + 6706 : 1 +state 6707 observe1Greater1 observeIGreater1 + action 0 + 5592 : 0.2 + 5593 : 0.2 + 5594 : 0.2 + 5595 : 0.2 + 5596 : 0.2 +state 6708 observe1Greater1 observeIGreater1 + action 0 + 7250 : 1 +state 6709 deadlock observe1Greater1 observeIGreater1 + action 0 + 6709 : 1 +state 6710 deadlock observe1Greater1 observeIGreater1 + action 0 + 6710 : 1 +state 6711 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6712 observe1Greater1 observeIGreater1 + action 0 + 7251 : 1 +state 6713 deadlock observe1Greater1 observeIGreater1 + action 0 + 6713 : 1 +state 6714 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6715 observe1Greater1 observeIGreater1 + action 0 + 7252 : 1 +state 6716 deadlock observe1Greater1 observeIGreater1 + action 0 + 6716 : 1 +state 6717 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6718 observe1Greater1 observeIGreater1 + action 0 + 7253 : 1 +state 6719 deadlock observe1Greater1 observeIGreater1 + action 0 + 6719 : 1 +state 6720 observe1Greater1 observeIGreater1 + action 0 + 5598 : 0.2 + 5599 : 0.2 + 5600 : 0.2 + 5601 : 0.2 + 5602 : 0.2 +state 6721 observe1Greater1 observeIGreater1 + action 0 + 7254 : 1 +state 6722 deadlock observe1Greater1 observeIGreater1 + action 0 + 6722 : 1 +state 6723 deadlock observe1Greater1 observeIGreater1 + action 0 + 6723 : 1 +state 6724 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6725 observe1Greater1 observeIGreater1 + action 0 + 7255 : 1 +state 6726 deadlock observe1Greater1 observeIGreater1 + action 0 + 6726 : 1 +state 6727 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6728 observe1Greater1 observeIGreater1 + action 0 + 7256 : 1 +state 6729 deadlock observe1Greater1 observeIGreater1 + action 0 + 6729 : 1 +state 6730 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6731 observe1Greater1 observeIGreater1 + action 0 + 7257 : 1 +state 6732 deadlock observe1Greater1 observeIGreater1 + action 0 + 6732 : 1 +state 6733 observe1Greater1 observeIGreater1 + action 0 + 5604 : 0.2 + 5605 : 0.2 + 5606 : 0.2 + 5607 : 0.2 + 5608 : 0.2 +state 6734 observe1Greater1 observeIGreater1 + action 0 + 7258 : 1 +state 6735 deadlock observe1Greater1 observeIGreater1 + action 0 + 6735 : 1 +state 6736 deadlock observe1Greater1 observeIGreater1 + action 0 + 6736 : 1 +state 6737 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6738 observe1Greater1 observeIGreater1 + action 0 + 7259 : 1 +state 6739 deadlock observe1Greater1 observeIGreater1 + action 0 + 6739 : 1 +state 6740 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6741 observe1Greater1 observeIGreater1 + action 0 + 7260 : 1 +state 6742 deadlock observe1Greater1 observeIGreater1 + action 0 + 6742 : 1 +state 6743 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6744 observe1Greater1 observeIGreater1 + action 0 + 7261 : 1 +state 6745 deadlock observe1Greater1 observeIGreater1 + action 0 + 6745 : 1 +state 6746 observe1Greater1 observeIGreater1 + action 0 + 5610 : 0.2 + 5611 : 0.2 + 5612 : 0.2 + 5613 : 0.2 + 5614 : 0.2 +state 6747 observe1Greater1 observeIGreater1 + action 0 + 7262 : 1 +state 6748 deadlock observe1Greater1 observeIGreater1 + action 0 + 6748 : 1 +state 6749 deadlock observe2Greater1 observeIGreater1 + action 0 + 6749 : 1 +state 6750 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6751 observe2Greater1 observeIGreater1 + action 0 + 7263 : 1 +state 6752 deadlock observe2Greater1 observeIGreater1 + action 0 + 6752 : 1 +state 6753 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6754 observe2Greater1 observeIGreater1 + action 0 + 7264 : 1 +state 6755 deadlock observe2Greater1 observeIGreater1 + action 0 + 6755 : 1 +state 6756 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6757 observe2Greater1 observeIGreater1 + action 0 + 7265 : 1 +state 6758 deadlock observe2Greater1 observeIGreater1 + action 0 + 6758 : 1 +state 6759 observe2Greater1 observeIGreater1 + action 0 + 5620 : 0.2 + 5621 : 0.2 + 5622 : 0.2 + 5623 : 0.2 + 5624 : 0.2 +state 6760 observe2Greater1 observeIGreater1 + action 0 + 7266 : 1 +state 6761 deadlock observe2Greater1 observeIGreater1 + action 0 + 6761 : 1 +state 6762 deadlock + action 0 + 6762 : 1 +state 6763 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6764 + action 0 + 7267 : 1 +state 6765 deadlock + action 0 + 6765 : 1 +state 6766 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6767 + action 0 + 7268 : 1 +state 6768 deadlock + action 0 + 6768 : 1 +state 6769 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6770 + action 0 + 7269 : 1 +state 6771 deadlock + action 0 + 6771 : 1 +state 6772 + action 0 + 5626 : 0.2 + 5627 : 0.2 + 5628 : 0.2 + 5629 : 0.2 + 5630 : 0.2 +state 6773 + action 0 + 7270 : 1 +state 6774 deadlock + action 0 + 6774 : 1 +state 6775 deadlock + action 0 + 6775 : 1 +state 6776 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6777 + action 0 + 7271 : 1 +state 6778 deadlock + action 0 + 6778 : 1 +state 6779 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6780 + action 0 + 7272 : 1 +state 6781 deadlock + action 0 + 6781 : 1 +state 6782 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6783 + action 0 + 7273 : 1 +state 6784 deadlock + action 0 + 6784 : 1 +state 6785 + action 0 + 5632 : 0.2 + 5633 : 0.2 + 5634 : 0.2 + 5635 : 0.2 + 5636 : 0.2 +state 6786 + action 0 + 7274 : 1 +state 6787 deadlock + action 0 + 6787 : 1 +state 6788 deadlock observe3Greater1 observeIGreater1 + action 0 + 6788 : 1 +state 6789 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6790 observe3Greater1 observeIGreater1 + action 0 + 7275 : 1 +state 6791 deadlock observe3Greater1 observeIGreater1 + action 0 + 6791 : 1 +state 6792 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6793 observe3Greater1 observeIGreater1 + action 0 + 7276 : 1 +state 6794 deadlock observe3Greater1 observeIGreater1 + action 0 + 6794 : 1 +state 6795 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6796 observe3Greater1 observeIGreater1 + action 0 + 7277 : 1 +state 6797 deadlock observe3Greater1 observeIGreater1 + action 0 + 6797 : 1 +state 6798 observe3Greater1 observeIGreater1 + action 0 + 5642 : 0.2 + 5643 : 0.2 + 5644 : 0.2 + 5645 : 0.2 + 5646 : 0.2 +state 6799 observe3Greater1 observeIGreater1 + action 0 + 7278 : 1 +state 6800 deadlock observe3Greater1 observeIGreater1 + action 0 + 6800 : 1 +state 6801 deadlock + action 0 + 6801 : 1 +state 6802 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6803 + action 0 + 7279 : 1 +state 6804 deadlock + action 0 + 6804 : 1 +state 6805 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6806 + action 0 + 7280 : 1 +state 6807 deadlock + action 0 + 6807 : 1 +state 6808 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6809 + action 0 + 7281 : 1 +state 6810 deadlock + action 0 + 6810 : 1 +state 6811 + action 0 + 5648 : 0.2 + 5649 : 0.2 + 5650 : 0.2 + 5651 : 0.2 + 5652 : 0.2 +state 6812 + action 0 + 7282 : 1 +state 6813 deadlock + action 0 + 6813 : 1 +state 6814 deadlock observe4Greater1 observeIGreater1 + action 0 + 6814 : 1 +state 6815 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6816 observe4Greater1 observeIGreater1 + action 0 + 7283 : 1 +state 6817 deadlock observe4Greater1 observeIGreater1 + action 0 + 6817 : 1 +state 6818 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6819 observe4Greater1 observeIGreater1 + action 0 + 7284 : 1 +state 6820 deadlock observe4Greater1 observeIGreater1 + action 0 + 6820 : 1 +state 6821 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6822 observe4Greater1 observeIGreater1 + action 0 + 7285 : 1 +state 6823 deadlock observe4Greater1 observeIGreater1 + action 0 + 6823 : 1 +state 6824 observe4Greater1 observeIGreater1 + action 0 + 5658 : 0.2 + 5659 : 0.2 + 5660 : 0.2 + 5661 : 0.2 + 5662 : 0.2 +state 6825 observe4Greater1 observeIGreater1 + action 0 + 7286 : 1 +state 6826 deadlock observe4Greater1 observeIGreater1 + action 0 + 6826 : 1 +state 6827 deadlock observe2Greater1 observeIGreater1 + action 0 + 6827 : 1 +state 6828 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6829 observe2Greater1 observeIGreater1 + action 0 + 7287 : 1 +state 6830 deadlock observe2Greater1 observeIGreater1 + action 0 + 6830 : 1 +state 6831 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6832 observe2Greater1 observeIGreater1 + action 0 + 7288 : 1 +state 6833 deadlock observe2Greater1 observeIGreater1 + action 0 + 6833 : 1 +state 6834 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6835 observe2Greater1 observeIGreater1 + action 0 + 7289 : 1 +state 6836 deadlock observe2Greater1 observeIGreater1 + action 0 + 6836 : 1 +state 6837 observe2Greater1 observeIGreater1 + action 0 + 5668 : 0.2 + 5669 : 0.2 + 5670 : 0.2 + 5671 : 0.2 + 5672 : 0.2 +state 6838 observe2Greater1 observeIGreater1 + action 0 + 7290 : 1 +state 6839 deadlock observe2Greater1 observeIGreater1 + action 0 + 6839 : 1 +state 6840 deadlock observe2Greater1 observeIGreater1 + action 0 + 6840 : 1 +state 6841 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6842 observe2Greater1 observeIGreater1 + action 0 + 7291 : 1 +state 6843 deadlock observe2Greater1 observeIGreater1 + action 0 + 6843 : 1 +state 6844 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6845 observe2Greater1 observeIGreater1 + action 0 + 7292 : 1 +state 6846 deadlock observe2Greater1 observeIGreater1 + action 0 + 6846 : 1 +state 6847 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6848 observe2Greater1 observeIGreater1 + action 0 + 7293 : 1 +state 6849 deadlock observe2Greater1 observeIGreater1 + action 0 + 6849 : 1 +state 6850 observe2Greater1 observeIGreater1 + action 0 + 5674 : 0.2 + 5675 : 0.2 + 5676 : 0.2 + 5677 : 0.2 + 5678 : 0.2 +state 6851 observe2Greater1 observeIGreater1 + action 0 + 7294 : 1 +state 6852 deadlock observe2Greater1 observeIGreater1 + action 0 + 6852 : 1 +state 6853 deadlock observe2Greater1 observeIGreater1 + action 0 + 6853 : 1 +state 6854 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6855 observe2Greater1 observeIGreater1 + action 0 + 7295 : 1 +state 6856 deadlock observe2Greater1 observeIGreater1 + action 0 + 6856 : 1 +state 6857 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6858 observe2Greater1 observeIGreater1 + action 0 + 7296 : 1 +state 6859 deadlock observe2Greater1 observeIGreater1 + action 0 + 6859 : 1 +state 6860 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6861 observe2Greater1 observeIGreater1 + action 0 + 7297 : 1 +state 6862 deadlock observe2Greater1 observeIGreater1 + action 0 + 6862 : 1 +state 6863 observe2Greater1 observeIGreater1 + action 0 + 5680 : 0.2 + 5681 : 0.2 + 5682 : 0.2 + 5683 : 0.2 + 5684 : 0.2 +state 6864 observe2Greater1 observeIGreater1 + action 0 + 7298 : 1 +state 6865 deadlock observe2Greater1 observeIGreater1 + action 0 + 6865 : 1 +state 6866 deadlock observe3Greater1 observeIGreater1 + action 0 + 6866 : 1 +state 6867 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6868 observe3Greater1 observeIGreater1 + action 0 + 7299 : 1 +state 6869 deadlock observe3Greater1 observeIGreater1 + action 0 + 6869 : 1 +state 6870 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6871 observe3Greater1 observeIGreater1 + action 0 + 7300 : 1 +state 6872 deadlock observe3Greater1 observeIGreater1 + action 0 + 6872 : 1 +state 6873 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6874 observe3Greater1 observeIGreater1 + action 0 + 7301 : 1 +state 6875 deadlock observe3Greater1 observeIGreater1 + action 0 + 6875 : 1 +state 6876 observe3Greater1 observeIGreater1 + action 0 + 5690 : 0.2 + 5691 : 0.2 + 5692 : 0.2 + 5693 : 0.2 + 5694 : 0.2 +state 6877 observe3Greater1 observeIGreater1 + action 0 + 7302 : 1 +state 6878 deadlock observe3Greater1 observeIGreater1 + action 0 + 6878 : 1 +state 6879 deadlock + action 0 + 6879 : 1 +state 6880 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6881 + action 0 + 7303 : 1 +state 6882 deadlock + action 0 + 6882 : 1 +state 6883 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6884 + action 0 + 7304 : 1 +state 6885 deadlock + action 0 + 6885 : 1 +state 6886 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6887 + action 0 + 7305 : 1 +state 6888 deadlock + action 0 + 6888 : 1 +state 6889 + action 0 + 5696 : 0.2 + 5697 : 0.2 + 5698 : 0.2 + 5699 : 0.2 + 5700 : 0.2 +state 6890 + action 0 + 7306 : 1 +state 6891 deadlock + action 0 + 6891 : 1 +state 6892 deadlock observe4Greater1 observeIGreater1 + action 0 + 6892 : 1 +state 6893 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6894 observe4Greater1 observeIGreater1 + action 0 + 7307 : 1 +state 6895 deadlock observe4Greater1 observeIGreater1 + action 0 + 6895 : 1 +state 6896 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6897 observe4Greater1 observeIGreater1 + action 0 + 7308 : 1 +state 6898 deadlock observe4Greater1 observeIGreater1 + action 0 + 6898 : 1 +state 6899 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6900 observe4Greater1 observeIGreater1 + action 0 + 7309 : 1 +state 6901 deadlock observe4Greater1 observeIGreater1 + action 0 + 6901 : 1 +state 6902 observe4Greater1 observeIGreater1 + action 0 + 5706 : 0.2 + 5707 : 0.2 + 5708 : 0.2 + 5709 : 0.2 + 5710 : 0.2 +state 6903 observe4Greater1 observeIGreater1 + action 0 + 7310 : 1 +state 6904 deadlock observe4Greater1 observeIGreater1 + action 0 + 6904 : 1 +state 6905 deadlock observe3Greater1 observeIGreater1 + action 0 + 6905 : 1 +state 6906 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6907 observe3Greater1 observeIGreater1 + action 0 + 7311 : 1 +state 6908 deadlock observe3Greater1 observeIGreater1 + action 0 + 6908 : 1 +state 6909 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6910 observe3Greater1 observeIGreater1 + action 0 + 7312 : 1 +state 6911 deadlock observe3Greater1 observeIGreater1 + action 0 + 6911 : 1 +state 6912 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6913 observe3Greater1 observeIGreater1 + action 0 + 7313 : 1 +state 6914 deadlock observe3Greater1 observeIGreater1 + action 0 + 6914 : 1 +state 6915 observe3Greater1 observeIGreater1 + action 0 + 5716 : 0.2 + 5717 : 0.2 + 5718 : 0.2 + 5719 : 0.2 + 5720 : 0.2 +state 6916 observe3Greater1 observeIGreater1 + action 0 + 7314 : 1 +state 6917 deadlock observe3Greater1 observeIGreater1 + action 0 + 6917 : 1 +state 6918 deadlock observe3Greater1 observeIGreater1 + action 0 + 6918 : 1 +state 6919 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6920 observe3Greater1 observeIGreater1 + action 0 + 7315 : 1 +state 6921 deadlock observe3Greater1 observeIGreater1 + action 0 + 6921 : 1 +state 6922 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6923 observe3Greater1 observeIGreater1 + action 0 + 7316 : 1 +state 6924 deadlock observe3Greater1 observeIGreater1 + action 0 + 6924 : 1 +state 6925 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6926 observe3Greater1 observeIGreater1 + action 0 + 7317 : 1 +state 6927 deadlock observe3Greater1 observeIGreater1 + action 0 + 6927 : 1 +state 6928 observe3Greater1 observeIGreater1 + action 0 + 5722 : 0.2 + 5723 : 0.2 + 5724 : 0.2 + 5725 : 0.2 + 5726 : 0.2 +state 6929 observe3Greater1 observeIGreater1 + action 0 + 7318 : 1 +state 6930 deadlock observe3Greater1 observeIGreater1 + action 0 + 6930 : 1 +state 6931 deadlock observe4Greater1 observeIGreater1 + action 0 + 6931 : 1 +state 6932 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6933 observe4Greater1 observeIGreater1 + action 0 + 7319 : 1 +state 6934 deadlock observe4Greater1 observeIGreater1 + action 0 + 6934 : 1 +state 6935 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6936 observe4Greater1 observeIGreater1 + action 0 + 7320 : 1 +state 6937 deadlock observe4Greater1 observeIGreater1 + action 0 + 6937 : 1 +state 6938 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6939 observe4Greater1 observeIGreater1 + action 0 + 7321 : 1 +state 6940 deadlock observe4Greater1 observeIGreater1 + action 0 + 6940 : 1 +state 6941 observe4Greater1 observeIGreater1 + action 0 + 5732 : 0.2 + 5733 : 0.2 + 5734 : 0.2 + 5735 : 0.2 + 5736 : 0.2 +state 6942 observe4Greater1 observeIGreater1 + action 0 + 7322 : 1 +state 6943 deadlock observe4Greater1 observeIGreater1 + action 0 + 6943 : 1 +state 6944 deadlock observe4Greater1 observeIGreater1 + action 0 + 6944 : 1 +state 6945 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6946 observe4Greater1 observeIGreater1 + action 0 + 7323 : 1 +state 6947 deadlock observe4Greater1 observeIGreater1 + action 0 + 6947 : 1 +state 6948 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6949 observe4Greater1 observeIGreater1 + action 0 + 7324 : 1 +state 6950 deadlock observe4Greater1 observeIGreater1 + action 0 + 6950 : 1 +state 6951 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6952 observe4Greater1 observeIGreater1 + action 0 + 7325 : 1 +state 6953 deadlock observe4Greater1 observeIGreater1 + action 0 + 6953 : 1 +state 6954 observe4Greater1 observeIGreater1 + action 0 + 5742 : 0.2 + 5743 : 0.2 + 5744 : 0.2 + 5745 : 0.2 + 5746 : 0.2 +state 6955 observe4Greater1 observeIGreater1 + action 0 + 7326 : 1 +state 6956 deadlock observe4Greater1 observeIGreater1 + action 0 + 6956 : 1 +state 6957 observe1Greater1 observeIGreater1 + action 0 + 7327 : 0.8 + 7328 : 0.2 +state 6958 observe1Greater1 observeIGreater1 + action 0 + 7329 : 0.8 + 7330 : 0.2 +state 6959 observe1Greater1 observeIGreater1 + action 0 + 7331 : 0.8 + 7332 : 0.2 +state 6960 observe1Greater1 observeIGreater1 + action 0 + 7333 : 0.8 + 7334 : 0.2 +state 6961 observe1Greater1 observeIGreater1 + action 0 + 7335 : 0.8 + 7336 : 0.2 +state 6962 observe1Greater1 observeIGreater1 + action 0 + 7337 : 1 +state 6963 observe1Greater1 observeIGreater1 + action 0 + 7338 : 0.8 + 7339 : 0.2 +state 6964 observe1Greater1 observeIGreater1 + action 0 + 7340 : 0.8 + 7341 : 0.2 +state 6965 observe1Greater1 observeIGreater1 + action 0 + 7342 : 0.8 + 7343 : 0.2 +state 6966 observe1Greater1 observeIGreater1 + action 0 + 7344 : 0.8 + 7345 : 0.2 +state 6967 observe1Greater1 observeIGreater1 + action 0 + 7346 : 0.8 + 7347 : 0.2 +state 6968 observe1Greater1 observeIGreater1 + action 0 + 7348 : 1 +state 6969 observe1Greater1 observeIGreater1 + action 0 + 7349 : 0.8 + 7350 : 0.2 +state 6970 observe1Greater1 observeIGreater1 + action 0 + 7351 : 0.8 + 7352 : 0.2 +state 6971 observe1Greater1 observeIGreater1 + action 0 + 7353 : 0.8 + 7354 : 0.2 +state 6972 observe1Greater1 observeIGreater1 + action 0 + 7355 : 0.8 + 7356 : 0.2 +state 6973 observe1Greater1 observeIGreater1 + action 0 + 7357 : 0.8 + 7358 : 0.2 +state 6974 observe1Greater1 observeIGreater1 + action 0 + 7359 : 1 +state 6975 observe1Greater1 observeIGreater1 + action 0 + 7360 : 0.8 + 7361 : 0.2 +state 6976 observe1Greater1 observeIGreater1 + action 0 + 7362 : 0.8 + 7363 : 0.2 +state 6977 observe1Greater1 observeIGreater1 + action 0 + 7364 : 0.8 + 7365 : 0.2 +state 6978 observe1Greater1 observeIGreater1 + action 0 + 7366 : 0.8 + 7367 : 0.2 +state 6979 observe1Greater1 observeIGreater1 + action 0 + 7368 : 0.8 + 7369 : 0.2 +state 6980 observe1Greater1 observeIGreater1 + action 0 + 7370 : 1 +state 6981 observe1Greater1 observeIGreater1 + action 0 + 7371 : 1 +state 6982 observe1Greater1 observeIGreater1 + action 0 + 7372 : 1 +state 6983 observe1Greater1 observeIGreater1 + action 0 + 7373 : 1 +state 6984 observe1Greater1 observeIGreater1 + action 0 + 7374 : 1 +state 6985 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7375 : 0.8 + 7376 : 0.2 +state 6986 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7377 : 0.8 + 7378 : 0.2 +state 6987 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7379 : 0.8 + 7380 : 0.2 +state 6988 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7381 : 0.8 + 7382 : 0.2 +state 6989 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7383 : 0.8 + 7384 : 0.2 +state 6990 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7385 : 1 +state 6991 observe1Greater1 observeIGreater1 + action 0 + 7386 : 0.8 + 7387 : 0.2 +state 6992 observe1Greater1 observeIGreater1 + action 0 + 7388 : 0.8 + 7389 : 0.2 +state 6993 observe1Greater1 observeIGreater1 + action 0 + 7390 : 0.8 + 7391 : 0.2 +state 6994 observe1Greater1 observeIGreater1 + action 0 + 7392 : 0.8 + 7393 : 0.2 +state 6995 observe1Greater1 observeIGreater1 + action 0 + 7394 : 0.8 + 7395 : 0.2 +state 6996 observe1Greater1 observeIGreater1 + action 0 + 7396 : 1 +state 6997 observe1Greater1 observeIGreater1 + action 0 + 7397 : 0.8 + 7398 : 0.2 +state 6998 observe1Greater1 observeIGreater1 + action 0 + 7399 : 0.8 + 7400 : 0.2 +state 6999 observe1Greater1 observeIGreater1 + action 0 + 7401 : 0.8 + 7402 : 0.2 +state 7000 observe1Greater1 observeIGreater1 + action 0 + 7403 : 0.8 + 7404 : 0.2 +state 7001 observe1Greater1 observeIGreater1 + action 0 + 7405 : 0.8 + 7406 : 0.2 +state 7002 observe1Greater1 observeIGreater1 + action 0 + 7407 : 1 +state 7003 observe1Greater1 observeIGreater1 + action 0 + 7408 : 1 +state 7004 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7409 : 1 +state 7005 observe1Greater1 observeIGreater1 + action 0 + 7410 : 1 +state 7006 observe1Greater1 observeIGreater1 + action 0 + 7411 : 1 +state 7007 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7412 : 0.8 + 7413 : 0.2 +state 7008 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7414 : 0.8 + 7415 : 0.2 +state 7009 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7416 : 0.8 + 7417 : 0.2 +state 7010 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7418 : 0.8 + 7419 : 0.2 +state 7011 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7420 : 0.8 + 7421 : 0.2 +state 7012 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7422 : 1 +state 7013 observe1Greater1 observeIGreater1 + action 0 + 7423 : 0.8 + 7424 : 0.2 +state 7014 observe1Greater1 observeIGreater1 + action 0 + 7425 : 0.8 + 7426 : 0.2 +state 7015 observe1Greater1 observeIGreater1 + action 0 + 7427 : 0.8 + 7428 : 0.2 +state 7016 observe1Greater1 observeIGreater1 + action 0 + 7429 : 0.8 + 7430 : 0.2 +state 7017 observe1Greater1 observeIGreater1 + action 0 + 7431 : 0.8 + 7432 : 0.2 +state 7018 observe1Greater1 observeIGreater1 + action 0 + 7433 : 1 +state 7019 observe1Greater1 observeIGreater1 + action 0 + 7434 : 1 +state 7020 observe1Greater1 observeIGreater1 + action 0 + 7435 : 1 +state 7021 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7436 : 1 +state 7022 observe1Greater1 observeIGreater1 + action 0 + 7437 : 1 +state 7023 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7438 : 0.8 + 7439 : 0.2 +state 7024 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7440 : 0.8 + 7441 : 0.2 +state 7025 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7442 : 0.8 + 7443 : 0.2 +state 7026 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7444 : 0.8 + 7445 : 0.2 +state 7027 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7446 : 0.8 + 7447 : 0.2 +state 7028 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7448 : 1 +state 7029 observe1Greater1 observeIGreater1 + action 0 + 7449 : 1 +state 7030 observe1Greater1 observeIGreater1 + action 0 + 7450 : 1 +state 7031 observe1Greater1 observeIGreater1 + action 0 + 7451 : 1 +state 7032 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7452 : 1 +state 7033 observe2Greater1 observeIGreater1 + action 0 + 7453 : 0.8 + 7454 : 0.2 +state 7034 observe2Greater1 observeIGreater1 + action 0 + 7455 : 0.8 + 7456 : 0.2 +state 7035 observe2Greater1 observeIGreater1 + action 0 + 7457 : 0.8 + 7458 : 0.2 +state 7036 observe2Greater1 observeIGreater1 + action 0 + 7459 : 0.8 + 7460 : 0.2 +state 7037 observe2Greater1 observeIGreater1 + action 0 + 7461 : 0.8 + 7462 : 0.2 +state 7038 observe2Greater1 observeIGreater1 + action 0 + 7463 : 1 +state 7039 observe2Greater1 observeIGreater1 + action 0 + 7464 : 0.8 + 7465 : 0.2 +state 7040 observe2Greater1 observeIGreater1 + action 0 + 7466 : 0.8 + 7467 : 0.2 +state 7041 observe2Greater1 observeIGreater1 + action 0 + 7468 : 0.8 + 7469 : 0.2 +state 7042 observe2Greater1 observeIGreater1 + action 0 + 7470 : 0.8 + 7471 : 0.2 +state 7043 observe2Greater1 observeIGreater1 + action 0 + 7472 : 0.8 + 7473 : 0.2 +state 7044 observe2Greater1 observeIGreater1 + action 0 + 7474 : 1 +state 7045 observe2Greater1 observeIGreater1 + action 0 + 7475 : 0.8 + 7476 : 0.2 +state 7046 observe2Greater1 observeIGreater1 + action 0 + 7477 : 0.8 + 7478 : 0.2 +state 7047 observe2Greater1 observeIGreater1 + action 0 + 7479 : 0.8 + 7480 : 0.2 +state 7048 observe2Greater1 observeIGreater1 + action 0 + 7481 : 0.8 + 7482 : 0.2 +state 7049 observe2Greater1 observeIGreater1 + action 0 + 7483 : 0.8 + 7484 : 0.2 +state 7050 observe2Greater1 observeIGreater1 + action 0 + 7485 : 1 +state 7051 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7486 : 1 +state 7052 observe2Greater1 observeIGreater1 + action 0 + 7487 : 1 +state 7053 observe2Greater1 observeIGreater1 + action 0 + 7488 : 1 +state 7054 observe2Greater1 observeIGreater1 + action 0 + 7489 : 1 +state 7055 observe3Greater1 observeIGreater1 + action 0 + 7490 : 0.8 + 7491 : 0.2 +state 7056 observe3Greater1 observeIGreater1 + action 0 + 7492 : 0.8 + 7493 : 0.2 +state 7057 observe3Greater1 observeIGreater1 + action 0 + 7494 : 0.8 + 7495 : 0.2 +state 7058 observe3Greater1 observeIGreater1 + action 0 + 7496 : 0.8 + 7497 : 0.2 +state 7059 observe3Greater1 observeIGreater1 + action 0 + 7498 : 0.8 + 7499 : 0.2 +state 7060 observe3Greater1 observeIGreater1 + action 0 + 7500 : 1 +state 7061 + action 0 + 7501 : 0.8 + 7502 : 0.2 +state 7062 + action 0 + 7503 : 0.8 + 7504 : 0.2 +state 7063 + action 0 + 7505 : 0.8 + 7506 : 0.2 +state 7064 + action 0 + 7507 : 0.8 + 7508 : 0.2 +state 7065 + action 0 + 7509 : 0.8 + 7510 : 0.2 +state 7066 + action 0 + 7511 : 1 +state 7067 observe1Greater1 observeIGreater1 + action 0 + 7512 : 1 +state 7068 observe2Greater1 observeIGreater1 + action 0 + 7513 : 1 +state 7069 observe3Greater1 observeIGreater1 + action 0 + 7514 : 1 +state 7070 + action 0 + 7515 : 1 +state 7071 observe4Greater1 observeIGreater1 + action 0 + 7516 : 0.8 + 7517 : 0.2 +state 7072 observe4Greater1 observeIGreater1 + action 0 + 7518 : 0.8 + 7519 : 0.2 +state 7073 observe4Greater1 observeIGreater1 + action 0 + 7520 : 0.8 + 7521 : 0.2 +state 7074 observe4Greater1 observeIGreater1 + action 0 + 7522 : 0.8 + 7523 : 0.2 +state 7075 observe4Greater1 observeIGreater1 + action 0 + 7524 : 0.8 + 7525 : 0.2 +state 7076 observe4Greater1 observeIGreater1 + action 0 + 7526 : 1 +state 7077 observe1Greater1 observeIGreater1 + action 0 + 7527 : 1 +state 7078 observe2Greater1 observeIGreater1 + action 0 + 7528 : 1 +state 7079 + action 0 + 7529 : 1 +state 7080 observe4Greater1 observeIGreater1 + action 0 + 7530 : 1 +state 7081 observe3Greater1 observeIGreater1 + action 0 + 7531 : 0.8 + 7532 : 0.2 +state 7082 observe3Greater1 observeIGreater1 + action 0 + 7533 : 0.8 + 7534 : 0.2 +state 7083 observe3Greater1 observeIGreater1 + action 0 + 7535 : 0.8 + 7536 : 0.2 +state 7084 observe3Greater1 observeIGreater1 + action 0 + 7537 : 0.8 + 7538 : 0.2 +state 7085 observe3Greater1 observeIGreater1 + action 0 + 7539 : 0.8 + 7540 : 0.2 +state 7086 observe3Greater1 observeIGreater1 + action 0 + 7541 : 1 +state 7087 observe3Greater1 observeIGreater1 + action 0 + 7542 : 0.8 + 7543 : 0.2 +state 7088 observe3Greater1 observeIGreater1 + action 0 + 7544 : 0.8 + 7545 : 0.2 +state 7089 observe3Greater1 observeIGreater1 + action 0 + 7546 : 0.8 + 7547 : 0.2 +state 7090 observe3Greater1 observeIGreater1 + action 0 + 7548 : 0.8 + 7549 : 0.2 +state 7091 observe3Greater1 observeIGreater1 + action 0 + 7550 : 0.8 + 7551 : 0.2 +state 7092 observe3Greater1 observeIGreater1 + action 0 + 7552 : 1 +state 7093 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7553 : 1 +state 7094 observe3Greater1 observeIGreater1 + action 0 + 7554 : 1 +state 7095 observe3Greater1 observeIGreater1 + action 0 + 7555 : 1 +state 7096 observe3Greater1 observeIGreater1 + action 0 + 7556 : 1 +state 7097 observe4Greater1 observeIGreater1 + action 0 + 7557 : 0.8 + 7558 : 0.2 +state 7098 observe4Greater1 observeIGreater1 + action 0 + 7559 : 0.8 + 7560 : 0.2 +state 7099 observe4Greater1 observeIGreater1 + action 0 + 7561 : 0.8 + 7562 : 0.2 +state 7100 observe4Greater1 observeIGreater1 + action 0 + 7563 : 0.8 + 7564 : 0.2 +state 7101 observe4Greater1 observeIGreater1 + action 0 + 7565 : 0.8 + 7566 : 0.2 +state 7102 observe4Greater1 observeIGreater1 + action 0 + 7567 : 1 +state 7103 observe1Greater1 observeIGreater1 + action 0 + 7568 : 1 +state 7104 + action 0 + 7569 : 1 +state 7105 observe3Greater1 observeIGreater1 + action 0 + 7570 : 1 +state 7106 observe4Greater1 observeIGreater1 + action 0 + 7571 : 1 +state 7107 observe4Greater1 observeIGreater1 + action 0 + 7572 : 0.8 + 7573 : 0.2 +state 7108 observe4Greater1 observeIGreater1 + action 0 + 7574 : 0.8 + 7575 : 0.2 +state 7109 observe4Greater1 observeIGreater1 + action 0 + 7576 : 0.8 + 7577 : 0.2 +state 7110 observe4Greater1 observeIGreater1 + action 0 + 7578 : 0.8 + 7579 : 0.2 +state 7111 observe4Greater1 observeIGreater1 + action 0 + 7580 : 0.8 + 7581 : 0.2 +state 7112 observe4Greater1 observeIGreater1 + action 0 + 7582 : 1 +state 7113 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7583 : 1 +state 7114 observe4Greater1 observeIGreater1 + action 0 + 7584 : 1 +state 7115 observe4Greater1 observeIGreater1 + action 0 + 7585 : 1 +state 7116 observe4Greater1 observeIGreater1 + action 0 + 7586 : 1 +state 7117 observe2Greater1 observeIGreater1 + action 0 + 7587 : 0.8 + 7588 : 0.2 +state 7118 observe2Greater1 observeIGreater1 + action 0 + 7589 : 0.8 + 7590 : 0.2 +state 7119 observe2Greater1 observeIGreater1 + action 0 + 7591 : 0.8 + 7592 : 0.2 +state 7120 observe2Greater1 observeIGreater1 + action 0 + 7593 : 0.8 + 7594 : 0.2 +state 7121 observe2Greater1 observeIGreater1 + action 0 + 7595 : 0.8 + 7596 : 0.2 +state 7122 observe2Greater1 observeIGreater1 + action 0 + 7597 : 1 +state 7123 observe2Greater1 observeIGreater1 + action 0 + 7598 : 0.8 + 7599 : 0.2 +state 7124 observe2Greater1 observeIGreater1 + action 0 + 7600 : 0.8 + 7601 : 0.2 +state 7125 observe2Greater1 observeIGreater1 + action 0 + 7602 : 0.8 + 7603 : 0.2 +state 7126 observe2Greater1 observeIGreater1 + action 0 + 7604 : 0.8 + 7605 : 0.2 +state 7127 observe2Greater1 observeIGreater1 + action 0 + 7606 : 0.8 + 7607 : 0.2 +state 7128 observe2Greater1 observeIGreater1 + action 0 + 7608 : 1 +state 7129 observe2Greater1 observeIGreater1 + action 0 + 7609 : 0.8 + 7610 : 0.2 +state 7130 observe2Greater1 observeIGreater1 + action 0 + 7611 : 0.8 + 7612 : 0.2 +state 7131 observe2Greater1 observeIGreater1 + action 0 + 7613 : 0.8 + 7614 : 0.2 +state 7132 observe2Greater1 observeIGreater1 + action 0 + 7615 : 0.8 + 7616 : 0.2 +state 7133 observe2Greater1 observeIGreater1 + action 0 + 7617 : 0.8 + 7618 : 0.2 +state 7134 observe2Greater1 observeIGreater1 + action 0 + 7619 : 1 +state 7135 observe2Greater1 observeIGreater1 + action 0 + 7620 : 1 +state 7136 observe2Greater1 observeIGreater1 + action 0 + 7621 : 1 +state 7137 observe2Greater1 observeIGreater1 + action 0 + 7622 : 1 +state 7138 observe2Greater1 observeIGreater1 + action 0 + 7623 : 1 +state 7139 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7624 : 0.8 + 7625 : 0.2 +state 7140 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7626 : 0.8 + 7627 : 0.2 +state 7141 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7628 : 0.8 + 7629 : 0.2 +state 7142 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7630 : 0.8 + 7631 : 0.2 +state 7143 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7632 : 0.8 + 7633 : 0.2 +state 7144 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7634 : 1 +state 7145 observe2Greater1 observeIGreater1 + action 0 + 7635 : 0.8 + 7636 : 0.2 +state 7146 observe2Greater1 observeIGreater1 + action 0 + 7637 : 0.8 + 7638 : 0.2 +state 7147 observe2Greater1 observeIGreater1 + action 0 + 7639 : 0.8 + 7640 : 0.2 +state 7148 observe2Greater1 observeIGreater1 + action 0 + 7641 : 0.8 + 7642 : 0.2 +state 7149 observe2Greater1 observeIGreater1 + action 0 + 7643 : 0.8 + 7644 : 0.2 +state 7150 observe2Greater1 observeIGreater1 + action 0 + 7645 : 1 +state 7151 observe2Greater1 observeIGreater1 + action 0 + 7646 : 1 +state 7152 observe2Greater1 observeIGreater1 + action 0 + 7647 : 1 +state 7153 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7648 : 1 +state 7154 observe2Greater1 observeIGreater1 + action 0 + 7649 : 1 +state 7155 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7650 : 0.8 + 7651 : 0.2 +state 7156 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7652 : 0.8 + 7653 : 0.2 +state 7157 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7654 : 0.8 + 7655 : 0.2 +state 7158 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7656 : 0.8 + 7657 : 0.2 +state 7159 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7658 : 0.8 + 7659 : 0.2 +state 7160 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7660 : 1 +state 7161 observe2Greater1 observeIGreater1 + action 0 + 7661 : 1 +state 7162 observe2Greater1 observeIGreater1 + action 0 + 7662 : 1 +state 7163 observe2Greater1 observeIGreater1 + action 0 + 7663 : 1 +state 7164 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7664 : 1 +state 7165 observe3Greater1 observeIGreater1 + action 0 + 7665 : 0.8 + 7666 : 0.2 +state 7166 observe3Greater1 observeIGreater1 + action 0 + 7667 : 0.8 + 7668 : 0.2 +state 7167 observe3Greater1 observeIGreater1 + action 0 + 7669 : 0.8 + 7670 : 0.2 +state 7168 observe3Greater1 observeIGreater1 + action 0 + 7671 : 0.8 + 7672 : 0.2 +state 7169 observe3Greater1 observeIGreater1 + action 0 + 7673 : 0.8 + 7674 : 0.2 +state 7170 observe3Greater1 observeIGreater1 + action 0 + 7675 : 1 +state 7171 observe3Greater1 observeIGreater1 + action 0 + 7676 : 0.8 + 7677 : 0.2 +state 7172 observe3Greater1 observeIGreater1 + action 0 + 7678 : 0.8 + 7679 : 0.2 +state 7173 observe3Greater1 observeIGreater1 + action 0 + 7680 : 0.8 + 7681 : 0.2 +state 7174 observe3Greater1 observeIGreater1 + action 0 + 7682 : 0.8 + 7683 : 0.2 +state 7175 observe3Greater1 observeIGreater1 + action 0 + 7684 : 0.8 + 7685 : 0.2 +state 7176 observe3Greater1 observeIGreater1 + action 0 + 7686 : 1 +state 7177 observe3Greater1 observeIGreater1 + action 0 + 7687 : 1 +state 7178 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7688 : 1 +state 7179 observe3Greater1 observeIGreater1 + action 0 + 7689 : 1 +state 7180 observe3Greater1 observeIGreater1 + action 0 + 7690 : 1 +state 7181 observe4Greater1 observeIGreater1 + action 0 + 7691 : 0.8 + 7692 : 0.2 +state 7182 observe4Greater1 observeIGreater1 + action 0 + 7693 : 0.8 + 7694 : 0.2 +state 7183 observe4Greater1 observeIGreater1 + action 0 + 7695 : 0.8 + 7696 : 0.2 +state 7184 observe4Greater1 observeIGreater1 + action 0 + 7697 : 0.8 + 7698 : 0.2 +state 7185 observe4Greater1 observeIGreater1 + action 0 + 7699 : 0.8 + 7700 : 0.2 +state 7186 observe4Greater1 observeIGreater1 + action 0 + 7701 : 1 +state 7187 + action 0 + 7702 : 1 +state 7188 observe2Greater1 observeIGreater1 + action 0 + 7703 : 1 +state 7189 observe3Greater1 observeIGreater1 + action 0 + 7704 : 1 +state 7190 observe4Greater1 observeIGreater1 + action 0 + 7705 : 1 +state 7191 observe4Greater1 observeIGreater1 + action 0 + 7706 : 0.8 + 7707 : 0.2 +state 7192 observe4Greater1 observeIGreater1 + action 0 + 7708 : 0.8 + 7709 : 0.2 +state 7193 observe4Greater1 observeIGreater1 + action 0 + 7710 : 0.8 + 7711 : 0.2 +state 7194 observe4Greater1 observeIGreater1 + action 0 + 7712 : 0.8 + 7713 : 0.2 +state 7195 observe4Greater1 observeIGreater1 + action 0 + 7714 : 0.8 + 7715 : 0.2 +state 7196 observe4Greater1 observeIGreater1 + action 0 + 7716 : 1 +state 7197 observe4Greater1 observeIGreater1 + action 0 + 7717 : 1 +state 7198 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7718 : 1 +state 7199 observe4Greater1 observeIGreater1 + action 0 + 7719 : 1 +state 7200 observe4Greater1 observeIGreater1 + action 0 + 7720 : 1 +state 7201 observe3Greater1 observeIGreater1 + action 0 + 7721 : 0.8 + 7722 : 0.2 +state 7202 observe3Greater1 observeIGreater1 + action 0 + 7723 : 0.8 + 7724 : 0.2 +state 7203 observe3Greater1 observeIGreater1 + action 0 + 7725 : 0.8 + 7726 : 0.2 +state 7204 observe3Greater1 observeIGreater1 + action 0 + 7727 : 0.8 + 7728 : 0.2 +state 7205 observe3Greater1 observeIGreater1 + action 0 + 7729 : 0.8 + 7730 : 0.2 +state 7206 observe3Greater1 observeIGreater1 + action 0 + 7731 : 1 +state 7207 observe3Greater1 observeIGreater1 + action 0 + 7732 : 0.8 + 7733 : 0.2 +state 7208 observe3Greater1 observeIGreater1 + action 0 + 7734 : 0.8 + 7735 : 0.2 +state 7209 observe3Greater1 observeIGreater1 + action 0 + 7736 : 0.8 + 7737 : 0.2 +state 7210 observe3Greater1 observeIGreater1 + action 0 + 7738 : 0.8 + 7739 : 0.2 +state 7211 observe3Greater1 observeIGreater1 + action 0 + 7740 : 0.8 + 7741 : 0.2 +state 7212 observe3Greater1 observeIGreater1 + action 0 + 7742 : 1 +state 7213 observe3Greater1 observeIGreater1 + action 0 + 7743 : 1 +state 7214 observe3Greater1 observeIGreater1 + action 0 + 7744 : 1 +state 7215 observe3Greater1 observeIGreater1 + action 0 + 7745 : 1 +state 7216 observe3Greater1 observeIGreater1 + action 0 + 7746 : 1 +state 7217 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7747 : 0.8 + 7748 : 0.2 +state 7218 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7749 : 0.8 + 7750 : 0.2 +state 7219 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7751 : 0.8 + 7752 : 0.2 +state 7220 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7753 : 0.8 + 7754 : 0.2 +state 7221 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7755 : 0.8 + 7756 : 0.2 +state 7222 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7757 : 1 +state 7223 observe3Greater1 observeIGreater1 + action 0 + 7758 : 1 +state 7224 observe3Greater1 observeIGreater1 + action 0 + 7759 : 1 +state 7225 observe3Greater1 observeIGreater1 + action 0 + 7760 : 1 +state 7226 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7761 : 1 +state 7227 observe4Greater1 observeIGreater1 + action 0 + 7762 : 0.8 + 7763 : 0.2 +state 7228 observe4Greater1 observeIGreater1 + action 0 + 7764 : 0.8 + 7765 : 0.2 +state 7229 observe4Greater1 observeIGreater1 + action 0 + 7766 : 0.8 + 7767 : 0.2 +state 7230 observe4Greater1 observeIGreater1 + action 0 + 7768 : 0.8 + 7769 : 0.2 +state 7231 observe4Greater1 observeIGreater1 + action 0 + 7770 : 0.8 + 7771 : 0.2 +state 7232 observe4Greater1 observeIGreater1 + action 0 + 7772 : 1 +state 7233 observe4Greater1 observeIGreater1 + action 0 + 7773 : 1 +state 7234 observe4Greater1 observeIGreater1 + action 0 + 7774 : 1 +state 7235 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7775 : 1 +state 7236 observe4Greater1 observeIGreater1 + action 0 + 7776 : 1 +state 7237 observe4Greater1 observeIGreater1 + action 0 + 7777 : 0.8 + 7778 : 0.2 +state 7238 observe4Greater1 observeIGreater1 + action 0 + 7779 : 0.8 + 7780 : 0.2 +state 7239 observe4Greater1 observeIGreater1 + action 0 + 7781 : 0.8 + 7782 : 0.2 +state 7240 observe4Greater1 observeIGreater1 + action 0 + 7783 : 0.8 + 7784 : 0.2 +state 7241 observe4Greater1 observeIGreater1 + action 0 + 7785 : 0.8 + 7786 : 0.2 +state 7242 observe4Greater1 observeIGreater1 + action 0 + 7787 : 1 +state 7243 observe4Greater1 observeIGreater1 + action 0 + 7788 : 1 +state 7244 observe4Greater1 observeIGreater1 + action 0 + 7789 : 1 +state 7245 observe4Greater1 observeIGreater1 + action 0 + 7790 : 1 +state 7246 observe4Greater1 observeIGreater1 + action 0 + 7791 : 1 +state 7247 observe1Greater1 observeIGreater1 + action 0 + 7792 : 1 +state 7248 observe1Greater1 observeIGreater1 + action 0 + 7793 : 1 +state 7249 observe1Greater1 observeIGreater1 + action 0 + 7794 : 1 +state 7250 observe1Greater1 observeIGreater1 + action 0 + 7795 : 1 +state 7251 observe1Greater1 observeIGreater1 + action 0 + 7796 : 1 +state 7252 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7797 : 1 +state 7253 observe1Greater1 observeIGreater1 + action 0 + 7798 : 1 +state 7254 observe1Greater1 observeIGreater1 + action 0 + 7799 : 1 +state 7255 observe1Greater1 observeIGreater1 + action 0 + 7800 : 1 +state 7256 observe1Greater1 observeIGreater1 + action 0 + 7801 : 1 +state 7257 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7802 : 1 +state 7258 observe1Greater1 observeIGreater1 + action 0 + 7803 : 1 +state 7259 observe1Greater1 observeIGreater1 + action 0 + 7804 : 1 +state 7260 observe1Greater1 observeIGreater1 + action 0 + 7805 : 1 +state 7261 observe1Greater1 observeIGreater1 + action 0 + 7806 : 1 +state 7262 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7807 : 1 +state 7263 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7808 : 1 +state 7264 observe2Greater1 observeIGreater1 + action 0 + 7809 : 1 +state 7265 observe2Greater1 observeIGreater1 + action 0 + 7810 : 1 +state 7266 observe2Greater1 observeIGreater1 + action 0 + 7811 : 1 +state 7267 observe1Greater1 observeIGreater1 + action 0 + 7812 : 1 +state 7268 observe2Greater1 observeIGreater1 + action 0 + 7813 : 1 +state 7269 observe3Greater1 observeIGreater1 + action 0 + 7814 : 1 +state 7270 + action 0 + 7815 : 1 +state 7271 observe1Greater1 observeIGreater1 + action 0 + 7816 : 1 +state 7272 observe2Greater1 observeIGreater1 + action 0 + 7817 : 1 +state 7273 + action 0 + 7818 : 1 +state 7274 observe4Greater1 observeIGreater1 + action 0 + 7819 : 1 +state 7275 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7820 : 1 +state 7276 observe3Greater1 observeIGreater1 + action 0 + 7821 : 1 +state 7277 observe3Greater1 observeIGreater1 + action 0 + 7822 : 1 +state 7278 observe3Greater1 observeIGreater1 + action 0 + 7823 : 1 +state 7279 observe1Greater1 observeIGreater1 + action 0 + 7824 : 1 +state 7280 + action 0 + 7825 : 1 +state 7281 observe3Greater1 observeIGreater1 + action 0 + 7826 : 1 +state 7282 observe4Greater1 observeIGreater1 + action 0 + 7827 : 1 +state 7283 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7828 : 1 +state 7284 observe4Greater1 observeIGreater1 + action 0 + 7829 : 1 +state 7285 observe4Greater1 observeIGreater1 + action 0 + 7830 : 1 +state 7286 observe4Greater1 observeIGreater1 + action 0 + 7831 : 1 +state 7287 observe2Greater1 observeIGreater1 + action 0 + 7832 : 1 +state 7288 observe2Greater1 observeIGreater1 + action 0 + 7833 : 1 +state 7289 observe2Greater1 observeIGreater1 + action 0 + 7834 : 1 +state 7290 observe2Greater1 observeIGreater1 + action 0 + 7835 : 1 +state 7291 observe2Greater1 observeIGreater1 + action 0 + 7836 : 1 +state 7292 observe2Greater1 observeIGreater1 + action 0 + 7837 : 1 +state 7293 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7838 : 1 +state 7294 observe2Greater1 observeIGreater1 + action 0 + 7839 : 1 +state 7295 observe2Greater1 observeIGreater1 + action 0 + 7840 : 1 +state 7296 observe2Greater1 observeIGreater1 + action 0 + 7841 : 1 +state 7297 observe2Greater1 observeIGreater1 + action 0 + 7842 : 1 +state 7298 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7843 : 1 +state 7299 observe3Greater1 observeIGreater1 + action 0 + 7844 : 1 +state 7300 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7845 : 1 +state 7301 observe3Greater1 observeIGreater1 + action 0 + 7846 : 1 +state 7302 observe3Greater1 observeIGreater1 + action 0 + 7847 : 1 +state 7303 + action 0 + 7848 : 1 +state 7304 observe2Greater1 observeIGreater1 + action 0 + 7849 : 1 +state 7305 observe3Greater1 observeIGreater1 + action 0 + 7850 : 1 +state 7306 observe4Greater1 observeIGreater1 + action 0 + 7851 : 1 +state 7307 observe4Greater1 observeIGreater1 + action 0 + 7852 : 1 +state 7308 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7853 : 1 +state 7309 observe4Greater1 observeIGreater1 + action 0 + 7854 : 1 +state 7310 observe4Greater1 observeIGreater1 + action 0 + 7855 : 1 +state 7311 observe3Greater1 observeIGreater1 + action 0 + 7856 : 1 +state 7312 observe3Greater1 observeIGreater1 + action 0 + 7857 : 1 +state 7313 observe3Greater1 observeIGreater1 + action 0 + 7858 : 1 +state 7314 observe3Greater1 observeIGreater1 + action 0 + 7859 : 1 +state 7315 observe3Greater1 observeIGreater1 + action 0 + 7860 : 1 +state 7316 observe3Greater1 observeIGreater1 + action 0 + 7861 : 1 +state 7317 observe3Greater1 observeIGreater1 + action 0 + 7862 : 1 +state 7318 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7863 : 1 +state 7319 observe4Greater1 observeIGreater1 + action 0 + 7864 : 1 +state 7320 observe4Greater1 observeIGreater1 + action 0 + 7865 : 1 +state 7321 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7866 : 1 +state 7322 observe4Greater1 observeIGreater1 + action 0 + 7867 : 1 +state 7323 observe4Greater1 observeIGreater1 + action 0 + 7868 : 1 +state 7324 observe4Greater1 observeIGreater1 + action 0 + 7869 : 1 +state 7325 observe4Greater1 observeIGreater1 + action 0 + 7870 : 1 +state 7326 observe4Greater1 observeIGreater1 + action 0 + 7871 : 1 +state 7327 observe1Greater1 observeIGreater1 + action 0 + 6327 : 0.833 + 6328 : 0.167 +state 7328 observe1Greater1 observeIGreater1 + action 0 + 7872 : 1 +state 7329 observe1Greater1 observeIGreater1 + action 0 + 7873 : 0.833 + 7874 : 0.167 +state 7330 observe1Greater1 observeIGreater1 + action 0 + 7875 : 1 +state 7331 observe1Greater1 observeIGreater1 + action 0 + 7876 : 0.833 + 7877 : 0.167 +state 7332 observe1Greater1 observeIGreater1 + action 0 + 7878 : 1 +state 7333 observe1Greater1 observeIGreater1 + action 0 + 7879 : 0.833 + 7880 : 0.167 +state 7334 observe1Greater1 observeIGreater1 + action 0 + 7881 : 1 +state 7335 observe1Greater1 observeIGreater1 + action 0 + 7882 : 0.833 + 7883 : 0.167 +state 7336 observe1Greater1 observeIGreater1 + action 0 + 7884 : 1 +state 7337 deadlock observe1Greater1 observeIGreater1 + action 0 + 7337 : 1 +state 7338 observe1Greater1 observeIGreater1 + action 0 + 6329 : 0.833 + 6330 : 0.167 +state 7339 observe1Greater1 observeIGreater1 + action 0 + 7885 : 1 +state 7340 observe1Greater1 observeIGreater1 + action 0 + 7886 : 0.833 + 7887 : 0.167 +state 7341 observe1Greater1 observeIGreater1 + action 0 + 7888 : 1 +state 7342 observe1Greater1 observeIGreater1 + action 0 + 7889 : 0.833 + 7890 : 0.167 +state 7343 observe1Greater1 observeIGreater1 + action 0 + 7891 : 1 +state 7344 observe1Greater1 observeIGreater1 + action 0 + 7892 : 0.833 + 7893 : 0.167 +state 7345 observe1Greater1 observeIGreater1 + action 0 + 7894 : 1 +state 7346 observe1Greater1 observeIGreater1 + action 0 + 7895 : 0.833 + 7896 : 0.167 +state 7347 observe1Greater1 observeIGreater1 + action 0 + 7897 : 1 +state 7348 deadlock observe1Greater1 observeIGreater1 + action 0 + 7348 : 1 +state 7349 observe1Greater1 observeIGreater1 + action 0 + 6331 : 0.833 + 6332 : 0.167 +state 7350 observe1Greater1 observeIGreater1 + action 0 + 7898 : 1 +state 7351 observe1Greater1 observeIGreater1 + action 0 + 7899 : 0.833 + 7900 : 0.167 +state 7352 observe1Greater1 observeIGreater1 + action 0 + 7901 : 1 +state 7353 observe1Greater1 observeIGreater1 + action 0 + 7902 : 0.833 + 7903 : 0.167 +state 7354 observe1Greater1 observeIGreater1 + action 0 + 7904 : 1 +state 7355 observe1Greater1 observeIGreater1 + action 0 + 7905 : 0.833 + 7906 : 0.167 +state 7356 observe1Greater1 observeIGreater1 + action 0 + 7907 : 1 +state 7357 observe1Greater1 observeIGreater1 + action 0 + 7908 : 0.833 + 7909 : 0.167 +state 7358 observe1Greater1 observeIGreater1 + action 0 + 7910 : 1 +state 7359 deadlock observe1Greater1 observeIGreater1 + action 0 + 7359 : 1 +state 7360 observe1Greater1 observeIGreater1 + action 0 + 6333 : 0.833 + 6334 : 0.167 +state 7361 observe1Greater1 observeIGreater1 + action 0 + 7911 : 1 +state 7362 observe1Greater1 observeIGreater1 + action 0 + 7912 : 0.833 + 7913 : 0.167 +state 7363 observe1Greater1 observeIGreater1 + action 0 + 7914 : 1 +state 7364 observe1Greater1 observeIGreater1 + action 0 + 7915 : 0.833 + 7916 : 0.167 +state 7365 observe1Greater1 observeIGreater1 + action 0 + 7917 : 1 +state 7366 observe1Greater1 observeIGreater1 + action 0 + 7918 : 0.833 + 7919 : 0.167 +state 7367 observe1Greater1 observeIGreater1 + action 0 + 7920 : 1 +state 7368 observe1Greater1 observeIGreater1 + action 0 + 7921 : 0.833 + 7922 : 0.167 +state 7369 observe1Greater1 observeIGreater1 + action 0 + 7923 : 1 +state 7370 deadlock observe1Greater1 observeIGreater1 + action 0 + 7370 : 1 +state 7371 deadlock observe1Greater1 observeIGreater1 + action 0 + 7371 : 1 +state 7372 deadlock observe1Greater1 observeIGreater1 + action 0 + 7372 : 1 +state 7373 deadlock observe1Greater1 observeIGreater1 + action 0 + 7373 : 1 +state 7374 deadlock observe1Greater1 observeIGreater1 + action 0 + 7374 : 1 +state 7375 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6348 : 0.833 + 6349 : 0.167 +state 7376 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7924 : 1 +state 7377 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7925 : 0.833 + 7926 : 0.167 +state 7378 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7927 : 1 +state 7379 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7928 : 0.833 + 7929 : 0.167 +state 7380 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7930 : 1 +state 7381 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7931 : 0.833 + 7932 : 0.167 +state 7382 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7933 : 1 +state 7383 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7934 : 0.833 + 7935 : 0.167 +state 7384 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7936 : 1 +state 7385 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7385 : 1 +state 7386 observe1Greater1 observeIGreater1 + action 0 + 6350 : 0.833 + 6351 : 0.167 +state 7387 observe1Greater1 observeIGreater1 + action 0 + 7937 : 1 +state 7388 observe1Greater1 observeIGreater1 + action 0 + 7938 : 0.833 + 7939 : 0.167 +state 7389 observe1Greater1 observeIGreater1 + action 0 + 7940 : 1 +state 7390 observe1Greater1 observeIGreater1 + action 0 + 7941 : 0.833 + 7942 : 0.167 +state 7391 observe1Greater1 observeIGreater1 + action 0 + 7943 : 1 +state 7392 observe1Greater1 observeIGreater1 + action 0 + 7944 : 0.833 + 7945 : 0.167 +state 7393 observe1Greater1 observeIGreater1 + action 0 + 7946 : 1 +state 7394 observe1Greater1 observeIGreater1 + action 0 + 7947 : 0.833 + 7948 : 0.167 +state 7395 observe1Greater1 observeIGreater1 + action 0 + 7949 : 1 +state 7396 deadlock observe1Greater1 observeIGreater1 + action 0 + 7396 : 1 +state 7397 observe1Greater1 observeIGreater1 + action 0 + 6352 : 0.833 + 6353 : 0.167 +state 7398 observe1Greater1 observeIGreater1 + action 0 + 7950 : 1 +state 7399 observe1Greater1 observeIGreater1 + action 0 + 7951 : 0.833 + 7952 : 0.167 +state 7400 observe1Greater1 observeIGreater1 + action 0 + 7953 : 1 +state 7401 observe1Greater1 observeIGreater1 + action 0 + 7954 : 0.833 + 7955 : 0.167 +state 7402 observe1Greater1 observeIGreater1 + action 0 + 7956 : 1 +state 7403 observe1Greater1 observeIGreater1 + action 0 + 7957 : 0.833 + 7958 : 0.167 +state 7404 observe1Greater1 observeIGreater1 + action 0 + 7959 : 1 +state 7405 observe1Greater1 observeIGreater1 + action 0 + 7960 : 0.833 + 7961 : 0.167 +state 7406 observe1Greater1 observeIGreater1 + action 0 + 7962 : 1 +state 7407 deadlock observe1Greater1 observeIGreater1 + action 0 + 7407 : 1 +state 7408 deadlock observe1Greater1 observeIGreater1 + action 0 + 7408 : 1 +state 7409 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7409 : 1 +state 7410 deadlock observe1Greater1 observeIGreater1 + action 0 + 7410 : 1 +state 7411 deadlock observe1Greater1 observeIGreater1 + action 0 + 7411 : 1 +state 7412 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 6367 : 0.833 + 6368 : 0.167 +state 7413 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7963 : 1 +state 7414 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7964 : 0.833 + 7965 : 0.167 +state 7415 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7966 : 1 +state 7416 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7967 : 0.833 + 7968 : 0.167 +state 7417 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7969 : 1 +state 7418 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7970 : 0.833 + 7971 : 0.167 +state 7419 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7972 : 1 +state 7420 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7973 : 0.833 + 7974 : 0.167 +state 7421 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7975 : 1 +state 7422 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7422 : 1 +state 7423 observe1Greater1 observeIGreater1 + action 0 + 6369 : 0.833 + 6370 : 0.167 +state 7424 observe1Greater1 observeIGreater1 + action 0 + 7976 : 1 +state 7425 observe1Greater1 observeIGreater1 + action 0 + 7977 : 0.833 + 7978 : 0.167 +state 7426 observe1Greater1 observeIGreater1 + action 0 + 7979 : 1 +state 7427 observe1Greater1 observeIGreater1 + action 0 + 7980 : 0.833 + 7981 : 0.167 +state 7428 observe1Greater1 observeIGreater1 + action 0 + 7982 : 1 +state 7429 observe1Greater1 observeIGreater1 + action 0 + 7983 : 0.833 + 7984 : 0.167 +state 7430 observe1Greater1 observeIGreater1 + action 0 + 7985 : 1 +state 7431 observe1Greater1 observeIGreater1 + action 0 + 7986 : 0.833 + 7987 : 0.167 +state 7432 observe1Greater1 observeIGreater1 + action 0 + 7988 : 1 +state 7433 deadlock observe1Greater1 observeIGreater1 + action 0 + 7433 : 1 +state 7434 deadlock observe1Greater1 observeIGreater1 + action 0 + 7434 : 1 +state 7435 deadlock observe1Greater1 observeIGreater1 + action 0 + 7435 : 1 +state 7436 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7436 : 1 +state 7437 deadlock observe1Greater1 observeIGreater1 + action 0 + 7437 : 1 +state 7438 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 6384 : 0.833 + 6385 : 0.167 +state 7439 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7989 : 1 +state 7440 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7990 : 0.833 + 7991 : 0.167 +state 7441 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7992 : 1 +state 7442 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7993 : 0.833 + 7994 : 0.167 +state 7443 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7995 : 1 +state 7444 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7996 : 0.833 + 7997 : 0.167 +state 7445 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7998 : 1 +state 7446 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7999 : 0.833 + 8000 : 0.167 +state 7447 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8001 : 1 +state 7448 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7448 : 1 +state 7449 deadlock observe1Greater1 observeIGreater1 + action 0 + 7449 : 1 +state 7450 deadlock observe1Greater1 observeIGreater1 + action 0 + 7450 : 1 +state 7451 deadlock observe1Greater1 observeIGreater1 + action 0 + 7451 : 1 +state 7452 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7452 : 1 +state 7453 observe2Greater1 observeIGreater1 + action 0 + 6399 : 0.833 + 6400 : 0.167 +state 7454 observe2Greater1 observeIGreater1 + action 0 + 8002 : 1 +state 7455 observe2Greater1 observeIGreater1 + action 0 + 8003 : 0.833 + 8004 : 0.167 +state 7456 observe2Greater1 observeIGreater1 + action 0 + 8005 : 1 +state 7457 observe2Greater1 observeIGreater1 + action 0 + 8006 : 0.833 + 8007 : 0.167 +state 7458 observe2Greater1 observeIGreater1 + action 0 + 8008 : 1 +state 7459 observe2Greater1 observeIGreater1 + action 0 + 8009 : 0.833 + 8010 : 0.167 +state 7460 observe2Greater1 observeIGreater1 + action 0 + 8011 : 1 +state 7461 observe2Greater1 observeIGreater1 + action 0 + 8012 : 0.833 + 8013 : 0.167 +state 7462 observe2Greater1 observeIGreater1 + action 0 + 8014 : 1 +state 7463 deadlock observe2Greater1 observeIGreater1 + action 0 + 7463 : 1 +state 7464 observe2Greater1 observeIGreater1 + action 0 + 6401 : 0.833 + 6402 : 0.167 +state 7465 observe2Greater1 observeIGreater1 + action 0 + 8015 : 1 +state 7466 observe2Greater1 observeIGreater1 + action 0 + 8016 : 0.833 + 8017 : 0.167 +state 7467 observe2Greater1 observeIGreater1 + action 0 + 8018 : 1 +state 7468 observe2Greater1 observeIGreater1 + action 0 + 8019 : 0.833 + 8020 : 0.167 +state 7469 observe2Greater1 observeIGreater1 + action 0 + 8021 : 1 +state 7470 observe2Greater1 observeIGreater1 + action 0 + 8022 : 0.833 + 8023 : 0.167 +state 7471 observe2Greater1 observeIGreater1 + action 0 + 8024 : 1 +state 7472 observe2Greater1 observeIGreater1 + action 0 + 8025 : 0.833 + 8026 : 0.167 +state 7473 observe2Greater1 observeIGreater1 + action 0 + 8027 : 1 +state 7474 deadlock observe2Greater1 observeIGreater1 + action 0 + 7474 : 1 +state 7475 observe2Greater1 observeIGreater1 + action 0 + 6403 : 0.833 + 6404 : 0.167 +state 7476 observe2Greater1 observeIGreater1 + action 0 + 8028 : 1 +state 7477 observe2Greater1 observeIGreater1 + action 0 + 8029 : 0.833 + 8030 : 0.167 +state 7478 observe2Greater1 observeIGreater1 + action 0 + 8031 : 1 +state 7479 observe2Greater1 observeIGreater1 + action 0 + 8032 : 0.833 + 8033 : 0.167 +state 7480 observe2Greater1 observeIGreater1 + action 0 + 8034 : 1 +state 7481 observe2Greater1 observeIGreater1 + action 0 + 8035 : 0.833 + 8036 : 0.167 +state 7482 observe2Greater1 observeIGreater1 + action 0 + 8037 : 1 +state 7483 observe2Greater1 observeIGreater1 + action 0 + 8038 : 0.833 + 8039 : 0.167 +state 7484 observe2Greater1 observeIGreater1 + action 0 + 8040 : 1 +state 7485 deadlock observe2Greater1 observeIGreater1 + action 0 + 7485 : 1 +state 7486 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7486 : 1 +state 7487 deadlock observe2Greater1 observeIGreater1 + action 0 + 7487 : 1 +state 7488 deadlock observe2Greater1 observeIGreater1 + action 0 + 7488 : 1 +state 7489 deadlock observe2Greater1 observeIGreater1 + action 0 + 7489 : 1 +state 7490 observe3Greater1 observeIGreater1 + action 0 + 6418 : 0.833 + 6419 : 0.167 +state 7491 observe3Greater1 observeIGreater1 + action 0 + 8041 : 1 +state 7492 observe3Greater1 observeIGreater1 + action 0 + 8042 : 0.833 + 8043 : 0.167 +state 7493 observe3Greater1 observeIGreater1 + action 0 + 8044 : 1 +state 7494 observe3Greater1 observeIGreater1 + action 0 + 8045 : 0.833 + 8046 : 0.167 +state 7495 observe3Greater1 observeIGreater1 + action 0 + 8047 : 1 +state 7496 observe3Greater1 observeIGreater1 + action 0 + 8048 : 0.833 + 8049 : 0.167 +state 7497 observe3Greater1 observeIGreater1 + action 0 + 8050 : 1 +state 7498 observe3Greater1 observeIGreater1 + action 0 + 8051 : 0.833 + 8052 : 0.167 +state 7499 observe3Greater1 observeIGreater1 + action 0 + 8053 : 1 +state 7500 deadlock observe3Greater1 observeIGreater1 + action 0 + 7500 : 1 +state 7501 + action 0 + 6420 : 0.833 + 6421 : 0.167 +state 7502 + action 0 + 8054 : 1 +state 7503 + action 0 + 8055 : 0.833 + 8056 : 0.167 +state 7504 + action 0 + 8057 : 1 +state 7505 + action 0 + 8058 : 0.833 + 8059 : 0.167 +state 7506 + action 0 + 8060 : 1 +state 7507 + action 0 + 8061 : 0.833 + 8062 : 0.167 +state 7508 + action 0 + 8063 : 1 +state 7509 + action 0 + 8064 : 0.833 + 8065 : 0.167 +state 7510 + action 0 + 8066 : 1 +state 7511 deadlock + action 0 + 7511 : 1 +state 7512 deadlock observe1Greater1 observeIGreater1 + action 0 + 7512 : 1 +state 7513 deadlock observe2Greater1 observeIGreater1 + action 0 + 7513 : 1 +state 7514 deadlock observe3Greater1 observeIGreater1 + action 0 + 7514 : 1 +state 7515 deadlock + action 0 + 7515 : 1 +state 7516 observe4Greater1 observeIGreater1 + action 0 + 6435 : 0.833 + 6436 : 0.167 +state 7517 observe4Greater1 observeIGreater1 + action 0 + 8067 : 1 +state 7518 observe4Greater1 observeIGreater1 + action 0 + 8068 : 0.833 + 8069 : 0.167 +state 7519 observe4Greater1 observeIGreater1 + action 0 + 8070 : 1 +state 7520 observe4Greater1 observeIGreater1 + action 0 + 8071 : 0.833 + 8072 : 0.167 +state 7521 observe4Greater1 observeIGreater1 + action 0 + 8073 : 1 +state 7522 observe4Greater1 observeIGreater1 + action 0 + 8074 : 0.833 + 8075 : 0.167 +state 7523 observe4Greater1 observeIGreater1 + action 0 + 8076 : 1 +state 7524 observe4Greater1 observeIGreater1 + action 0 + 8077 : 0.833 + 8078 : 0.167 +state 7525 observe4Greater1 observeIGreater1 + action 0 + 8079 : 1 +state 7526 deadlock observe4Greater1 observeIGreater1 + action 0 + 7526 : 1 +state 7527 deadlock observe1Greater1 observeIGreater1 + action 0 + 7527 : 1 +state 7528 deadlock observe2Greater1 observeIGreater1 + action 0 + 7528 : 1 +state 7529 deadlock + action 0 + 7529 : 1 +state 7530 deadlock observe4Greater1 observeIGreater1 + action 0 + 7530 : 1 +state 7531 observe3Greater1 observeIGreater1 + action 0 + 6450 : 0.833 + 6451 : 0.167 +state 7532 observe3Greater1 observeIGreater1 + action 0 + 8080 : 1 +state 7533 observe3Greater1 observeIGreater1 + action 0 + 8081 : 0.833 + 8082 : 0.167 +state 7534 observe3Greater1 observeIGreater1 + action 0 + 8083 : 1 +state 7535 observe3Greater1 observeIGreater1 + action 0 + 8084 : 0.833 + 8085 : 0.167 +state 7536 observe3Greater1 observeIGreater1 + action 0 + 8086 : 1 +state 7537 observe3Greater1 observeIGreater1 + action 0 + 8087 : 0.833 + 8088 : 0.167 +state 7538 observe3Greater1 observeIGreater1 + action 0 + 8089 : 1 +state 7539 observe3Greater1 observeIGreater1 + action 0 + 8090 : 0.833 + 8091 : 0.167 +state 7540 observe3Greater1 observeIGreater1 + action 0 + 8092 : 1 +state 7541 deadlock observe3Greater1 observeIGreater1 + action 0 + 7541 : 1 +state 7542 observe3Greater1 observeIGreater1 + action 0 + 6452 : 0.833 + 6453 : 0.167 +state 7543 observe3Greater1 observeIGreater1 + action 0 + 8093 : 1 +state 7544 observe3Greater1 observeIGreater1 + action 0 + 8094 : 0.833 + 8095 : 0.167 +state 7545 observe3Greater1 observeIGreater1 + action 0 + 8096 : 1 +state 7546 observe3Greater1 observeIGreater1 + action 0 + 8097 : 0.833 + 8098 : 0.167 +state 7547 observe3Greater1 observeIGreater1 + action 0 + 8099 : 1 +state 7548 observe3Greater1 observeIGreater1 + action 0 + 8100 : 0.833 + 8101 : 0.167 +state 7549 observe3Greater1 observeIGreater1 + action 0 + 8102 : 1 +state 7550 observe3Greater1 observeIGreater1 + action 0 + 8103 : 0.833 + 8104 : 0.167 +state 7551 observe3Greater1 observeIGreater1 + action 0 + 8105 : 1 +state 7552 deadlock observe3Greater1 observeIGreater1 + action 0 + 7552 : 1 +state 7553 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7553 : 1 +state 7554 deadlock observe3Greater1 observeIGreater1 + action 0 + 7554 : 1 +state 7555 deadlock observe3Greater1 observeIGreater1 + action 0 + 7555 : 1 +state 7556 deadlock observe3Greater1 observeIGreater1 + action 0 + 7556 : 1 +state 7557 observe4Greater1 observeIGreater1 + action 0 + 6467 : 0.833 + 6468 : 0.167 +state 7558 observe4Greater1 observeIGreater1 + action 0 + 8106 : 1 +state 7559 observe4Greater1 observeIGreater1 + action 0 + 8107 : 0.833 + 8108 : 0.167 +state 7560 observe4Greater1 observeIGreater1 + action 0 + 8109 : 1 +state 7561 observe4Greater1 observeIGreater1 + action 0 + 8110 : 0.833 + 8111 : 0.167 +state 7562 observe4Greater1 observeIGreater1 + action 0 + 8112 : 1 +state 7563 observe4Greater1 observeIGreater1 + action 0 + 8113 : 0.833 + 8114 : 0.167 +state 7564 observe4Greater1 observeIGreater1 + action 0 + 8115 : 1 +state 7565 observe4Greater1 observeIGreater1 + action 0 + 8116 : 0.833 + 8117 : 0.167 +state 7566 observe4Greater1 observeIGreater1 + action 0 + 8118 : 1 +state 7567 deadlock observe4Greater1 observeIGreater1 + action 0 + 7567 : 1 +state 7568 deadlock observe1Greater1 observeIGreater1 + action 0 + 7568 : 1 +state 7569 deadlock + action 0 + 7569 : 1 +state 7570 deadlock observe3Greater1 observeIGreater1 + action 0 + 7570 : 1 +state 7571 deadlock observe4Greater1 observeIGreater1 + action 0 + 7571 : 1 +state 7572 observe4Greater1 observeIGreater1 + action 0 + 6482 : 0.833 + 6483 : 0.167 +state 7573 observe4Greater1 observeIGreater1 + action 0 + 8119 : 1 +state 7574 observe4Greater1 observeIGreater1 + action 0 + 8120 : 0.833 + 8121 : 0.167 +state 7575 observe4Greater1 observeIGreater1 + action 0 + 8122 : 1 +state 7576 observe4Greater1 observeIGreater1 + action 0 + 8123 : 0.833 + 8124 : 0.167 +state 7577 observe4Greater1 observeIGreater1 + action 0 + 8125 : 1 +state 7578 observe4Greater1 observeIGreater1 + action 0 + 8126 : 0.833 + 8127 : 0.167 +state 7579 observe4Greater1 observeIGreater1 + action 0 + 8128 : 1 +state 7580 observe4Greater1 observeIGreater1 + action 0 + 8129 : 0.833 + 8130 : 0.167 +state 7581 observe4Greater1 observeIGreater1 + action 0 + 8131 : 1 +state 7582 deadlock observe4Greater1 observeIGreater1 + action 0 + 7582 : 1 +state 7583 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7583 : 1 +state 7584 deadlock observe4Greater1 observeIGreater1 + action 0 + 7584 : 1 +state 7585 deadlock observe4Greater1 observeIGreater1 + action 0 + 7585 : 1 +state 7586 deadlock observe4Greater1 observeIGreater1 + action 0 + 7586 : 1 +state 7587 observe2Greater1 observeIGreater1 + action 0 + 6497 : 0.833 + 6498 : 0.167 +state 7588 observe2Greater1 observeIGreater1 + action 0 + 8132 : 1 +state 7589 observe2Greater1 observeIGreater1 + action 0 + 8133 : 0.833 + 8134 : 0.167 +state 7590 observe2Greater1 observeIGreater1 + action 0 + 8135 : 1 +state 7591 observe2Greater1 observeIGreater1 + action 0 + 8136 : 0.833 + 8137 : 0.167 +state 7592 observe2Greater1 observeIGreater1 + action 0 + 8138 : 1 +state 7593 observe2Greater1 observeIGreater1 + action 0 + 8139 : 0.833 + 8140 : 0.167 +state 7594 observe2Greater1 observeIGreater1 + action 0 + 8141 : 1 +state 7595 observe2Greater1 observeIGreater1 + action 0 + 8142 : 0.833 + 8143 : 0.167 +state 7596 observe2Greater1 observeIGreater1 + action 0 + 8144 : 1 +state 7597 deadlock observe2Greater1 observeIGreater1 + action 0 + 7597 : 1 +state 7598 observe2Greater1 observeIGreater1 + action 0 + 6499 : 0.833 + 6500 : 0.167 +state 7599 observe2Greater1 observeIGreater1 + action 0 + 8145 : 1 +state 7600 observe2Greater1 observeIGreater1 + action 0 + 8146 : 0.833 + 8147 : 0.167 +state 7601 observe2Greater1 observeIGreater1 + action 0 + 8148 : 1 +state 7602 observe2Greater1 observeIGreater1 + action 0 + 8149 : 0.833 + 8150 : 0.167 +state 7603 observe2Greater1 observeIGreater1 + action 0 + 8151 : 1 +state 7604 observe2Greater1 observeIGreater1 + action 0 + 8152 : 0.833 + 8153 : 0.167 +state 7605 observe2Greater1 observeIGreater1 + action 0 + 8154 : 1 +state 7606 observe2Greater1 observeIGreater1 + action 0 + 8155 : 0.833 + 8156 : 0.167 +state 7607 observe2Greater1 observeIGreater1 + action 0 + 8157 : 1 +state 7608 deadlock observe2Greater1 observeIGreater1 + action 0 + 7608 : 1 +state 7609 observe2Greater1 observeIGreater1 + action 0 + 6501 : 0.833 + 6502 : 0.167 +state 7610 observe2Greater1 observeIGreater1 + action 0 + 8158 : 1 +state 7611 observe2Greater1 observeIGreater1 + action 0 + 8159 : 0.833 + 8160 : 0.167 +state 7612 observe2Greater1 observeIGreater1 + action 0 + 8161 : 1 +state 7613 observe2Greater1 observeIGreater1 + action 0 + 8162 : 0.833 + 8163 : 0.167 +state 7614 observe2Greater1 observeIGreater1 + action 0 + 8164 : 1 +state 7615 observe2Greater1 observeIGreater1 + action 0 + 8165 : 0.833 + 8166 : 0.167 +state 7616 observe2Greater1 observeIGreater1 + action 0 + 8167 : 1 +state 7617 observe2Greater1 observeIGreater1 + action 0 + 8168 : 0.833 + 8169 : 0.167 +state 7618 observe2Greater1 observeIGreater1 + action 0 + 8170 : 1 +state 7619 deadlock observe2Greater1 observeIGreater1 + action 0 + 7619 : 1 +state 7620 deadlock observe2Greater1 observeIGreater1 + action 0 + 7620 : 1 +state 7621 deadlock observe2Greater1 observeIGreater1 + action 0 + 7621 : 1 +state 7622 deadlock observe2Greater1 observeIGreater1 + action 0 + 7622 : 1 +state 7623 deadlock observe2Greater1 observeIGreater1 + action 0 + 7623 : 1 +state 7624 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 6516 : 0.833 + 6517 : 0.167 +state 7625 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8171 : 1 +state 7626 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8172 : 0.833 + 8173 : 0.167 +state 7627 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8174 : 1 +state 7628 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8175 : 0.833 + 8176 : 0.167 +state 7629 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8177 : 1 +state 7630 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8178 : 0.833 + 8179 : 0.167 +state 7631 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8180 : 1 +state 7632 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8181 : 0.833 + 8182 : 0.167 +state 7633 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8183 : 1 +state 7634 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7634 : 1 +state 7635 observe2Greater1 observeIGreater1 + action 0 + 6518 : 0.833 + 6519 : 0.167 +state 7636 observe2Greater1 observeIGreater1 + action 0 + 8184 : 1 +state 7637 observe2Greater1 observeIGreater1 + action 0 + 8185 : 0.833 + 8186 : 0.167 +state 7638 observe2Greater1 observeIGreater1 + action 0 + 8187 : 1 +state 7639 observe2Greater1 observeIGreater1 + action 0 + 8188 : 0.833 + 8189 : 0.167 +state 7640 observe2Greater1 observeIGreater1 + action 0 + 8190 : 1 +state 7641 observe2Greater1 observeIGreater1 + action 0 + 8191 : 0.833 + 8192 : 0.167 +state 7642 observe2Greater1 observeIGreater1 + action 0 + 8193 : 1 +state 7643 observe2Greater1 observeIGreater1 + action 0 + 8194 : 0.833 + 8195 : 0.167 +state 7644 observe2Greater1 observeIGreater1 + action 0 + 8196 : 1 +state 7645 deadlock observe2Greater1 observeIGreater1 + action 0 + 7645 : 1 +state 7646 deadlock observe2Greater1 observeIGreater1 + action 0 + 7646 : 1 +state 7647 deadlock observe2Greater1 observeIGreater1 + action 0 + 7647 : 1 +state 7648 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7648 : 1 +state 7649 deadlock observe2Greater1 observeIGreater1 + action 0 + 7649 : 1 +state 7650 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 6533 : 0.833 + 6534 : 0.167 +state 7651 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8197 : 1 +state 7652 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8198 : 0.833 + 8199 : 0.167 +state 7653 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8200 : 1 +state 7654 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8201 : 0.833 + 8202 : 0.167 +state 7655 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8203 : 1 +state 7656 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8204 : 0.833 + 8205 : 0.167 +state 7657 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8206 : 1 +state 7658 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8207 : 0.833 + 8208 : 0.167 +state 7659 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8209 : 1 +state 7660 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7660 : 1 +state 7661 deadlock observe2Greater1 observeIGreater1 + action 0 + 7661 : 1 +state 7662 deadlock observe2Greater1 observeIGreater1 + action 0 + 7662 : 1 +state 7663 deadlock observe2Greater1 observeIGreater1 + action 0 + 7663 : 1 +state 7664 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7664 : 1 +state 7665 observe3Greater1 observeIGreater1 + action 0 + 6548 : 0.833 + 6549 : 0.167 +state 7666 observe3Greater1 observeIGreater1 + action 0 + 8210 : 1 +state 7667 observe3Greater1 observeIGreater1 + action 0 + 8211 : 0.833 + 8212 : 0.167 +state 7668 observe3Greater1 observeIGreater1 + action 0 + 8213 : 1 +state 7669 observe3Greater1 observeIGreater1 + action 0 + 8214 : 0.833 + 8215 : 0.167 +state 7670 observe3Greater1 observeIGreater1 + action 0 + 8216 : 1 +state 7671 observe3Greater1 observeIGreater1 + action 0 + 8217 : 0.833 + 8218 : 0.167 +state 7672 observe3Greater1 observeIGreater1 + action 0 + 8219 : 1 +state 7673 observe3Greater1 observeIGreater1 + action 0 + 8220 : 0.833 + 8221 : 0.167 +state 7674 observe3Greater1 observeIGreater1 + action 0 + 8222 : 1 +state 7675 deadlock observe3Greater1 observeIGreater1 + action 0 + 7675 : 1 +state 7676 observe3Greater1 observeIGreater1 + action 0 + 6550 : 0.833 + 6551 : 0.167 +state 7677 observe3Greater1 observeIGreater1 + action 0 + 8223 : 1 +state 7678 observe3Greater1 observeIGreater1 + action 0 + 8224 : 0.833 + 8225 : 0.167 +state 7679 observe3Greater1 observeIGreater1 + action 0 + 8226 : 1 +state 7680 observe3Greater1 observeIGreater1 + action 0 + 8227 : 0.833 + 8228 : 0.167 +state 7681 observe3Greater1 observeIGreater1 + action 0 + 8229 : 1 +state 7682 observe3Greater1 observeIGreater1 + action 0 + 8230 : 0.833 + 8231 : 0.167 +state 7683 observe3Greater1 observeIGreater1 + action 0 + 8232 : 1 +state 7684 observe3Greater1 observeIGreater1 + action 0 + 8233 : 0.833 + 8234 : 0.167 +state 7685 observe3Greater1 observeIGreater1 + action 0 + 8235 : 1 +state 7686 deadlock observe3Greater1 observeIGreater1 + action 0 + 7686 : 1 +state 7687 deadlock observe3Greater1 observeIGreater1 + action 0 + 7687 : 1 +state 7688 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7688 : 1 +state 7689 deadlock observe3Greater1 observeIGreater1 + action 0 + 7689 : 1 +state 7690 deadlock observe3Greater1 observeIGreater1 + action 0 + 7690 : 1 +state 7691 observe4Greater1 observeIGreater1 + action 0 + 6565 : 0.833 + 6566 : 0.167 +state 7692 observe4Greater1 observeIGreater1 + action 0 + 8236 : 1 +state 7693 observe4Greater1 observeIGreater1 + action 0 + 8237 : 0.833 + 8238 : 0.167 +state 7694 observe4Greater1 observeIGreater1 + action 0 + 8239 : 1 +state 7695 observe4Greater1 observeIGreater1 + action 0 + 8240 : 0.833 + 8241 : 0.167 +state 7696 observe4Greater1 observeIGreater1 + action 0 + 8242 : 1 +state 7697 observe4Greater1 observeIGreater1 + action 0 + 8243 : 0.833 + 8244 : 0.167 +state 7698 observe4Greater1 observeIGreater1 + action 0 + 8245 : 1 +state 7699 observe4Greater1 observeIGreater1 + action 0 + 8246 : 0.833 + 8247 : 0.167 +state 7700 observe4Greater1 observeIGreater1 + action 0 + 8248 : 1 +state 7701 deadlock observe4Greater1 observeIGreater1 + action 0 + 7701 : 1 +state 7702 deadlock + action 0 + 7702 : 1 +state 7703 deadlock observe2Greater1 observeIGreater1 + action 0 + 7703 : 1 +state 7704 deadlock observe3Greater1 observeIGreater1 + action 0 + 7704 : 1 +state 7705 deadlock observe4Greater1 observeIGreater1 + action 0 + 7705 : 1 +state 7706 observe4Greater1 observeIGreater1 + action 0 + 6580 : 0.833 + 6581 : 0.167 +state 7707 observe4Greater1 observeIGreater1 + action 0 + 8249 : 1 +state 7708 observe4Greater1 observeIGreater1 + action 0 + 8250 : 0.833 + 8251 : 0.167 +state 7709 observe4Greater1 observeIGreater1 + action 0 + 8252 : 1 +state 7710 observe4Greater1 observeIGreater1 + action 0 + 8253 : 0.833 + 8254 : 0.167 +state 7711 observe4Greater1 observeIGreater1 + action 0 + 8255 : 1 +state 7712 observe4Greater1 observeIGreater1 + action 0 + 8256 : 0.833 + 8257 : 0.167 +state 7713 observe4Greater1 observeIGreater1 + action 0 + 8258 : 1 +state 7714 observe4Greater1 observeIGreater1 + action 0 + 8259 : 0.833 + 8260 : 0.167 +state 7715 observe4Greater1 observeIGreater1 + action 0 + 8261 : 1 +state 7716 deadlock observe4Greater1 observeIGreater1 + action 0 + 7716 : 1 +state 7717 deadlock observe4Greater1 observeIGreater1 + action 0 + 7717 : 1 +state 7718 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7718 : 1 +state 7719 deadlock observe4Greater1 observeIGreater1 + action 0 + 7719 : 1 +state 7720 deadlock observe4Greater1 observeIGreater1 + action 0 + 7720 : 1 +state 7721 observe3Greater1 observeIGreater1 + action 0 + 6595 : 0.833 + 6596 : 0.167 +state 7722 observe3Greater1 observeIGreater1 + action 0 + 8262 : 1 +state 7723 observe3Greater1 observeIGreater1 + action 0 + 8263 : 0.833 + 8264 : 0.167 +state 7724 observe3Greater1 observeIGreater1 + action 0 + 8265 : 1 +state 7725 observe3Greater1 observeIGreater1 + action 0 + 8266 : 0.833 + 8267 : 0.167 +state 7726 observe3Greater1 observeIGreater1 + action 0 + 8268 : 1 +state 7727 observe3Greater1 observeIGreater1 + action 0 + 8269 : 0.833 + 8270 : 0.167 +state 7728 observe3Greater1 observeIGreater1 + action 0 + 8271 : 1 +state 7729 observe3Greater1 observeIGreater1 + action 0 + 8272 : 0.833 + 8273 : 0.167 +state 7730 observe3Greater1 observeIGreater1 + action 0 + 8274 : 1 +state 7731 deadlock observe3Greater1 observeIGreater1 + action 0 + 7731 : 1 +state 7732 observe3Greater1 observeIGreater1 + action 0 + 6597 : 0.833 + 6598 : 0.167 +state 7733 observe3Greater1 observeIGreater1 + action 0 + 8275 : 1 +state 7734 observe3Greater1 observeIGreater1 + action 0 + 8276 : 0.833 + 8277 : 0.167 +state 7735 observe3Greater1 observeIGreater1 + action 0 + 8278 : 1 +state 7736 observe3Greater1 observeIGreater1 + action 0 + 8279 : 0.833 + 8280 : 0.167 +state 7737 observe3Greater1 observeIGreater1 + action 0 + 8281 : 1 +state 7738 observe3Greater1 observeIGreater1 + action 0 + 8282 : 0.833 + 8283 : 0.167 +state 7739 observe3Greater1 observeIGreater1 + action 0 + 8284 : 1 +state 7740 observe3Greater1 observeIGreater1 + action 0 + 8285 : 0.833 + 8286 : 0.167 +state 7741 observe3Greater1 observeIGreater1 + action 0 + 8287 : 1 +state 7742 deadlock observe3Greater1 observeIGreater1 + action 0 + 7742 : 1 +state 7743 deadlock observe3Greater1 observeIGreater1 + action 0 + 7743 : 1 +state 7744 deadlock observe3Greater1 observeIGreater1 + action 0 + 7744 : 1 +state 7745 deadlock observe3Greater1 observeIGreater1 + action 0 + 7745 : 1 +state 7746 deadlock observe3Greater1 observeIGreater1 + action 0 + 7746 : 1 +state 7747 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 6612 : 0.833 + 6613 : 0.167 +state 7748 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8288 : 1 +state 7749 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8289 : 0.833 + 8290 : 0.167 +state 7750 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8291 : 1 +state 7751 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8292 : 0.833 + 8293 : 0.167 +state 7752 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8294 : 1 +state 7753 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8295 : 0.833 + 8296 : 0.167 +state 7754 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8297 : 1 +state 7755 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8298 : 0.833 + 8299 : 0.167 +state 7756 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8300 : 1 +state 7757 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7757 : 1 +state 7758 deadlock observe3Greater1 observeIGreater1 + action 0 + 7758 : 1 +state 7759 deadlock observe3Greater1 observeIGreater1 + action 0 + 7759 : 1 +state 7760 deadlock observe3Greater1 observeIGreater1 + action 0 + 7760 : 1 +state 7761 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7761 : 1 +state 7762 observe4Greater1 observeIGreater1 + action 0 + 6627 : 0.833 + 6628 : 0.167 +state 7763 observe4Greater1 observeIGreater1 + action 0 + 8301 : 1 +state 7764 observe4Greater1 observeIGreater1 + action 0 + 8302 : 0.833 + 8303 : 0.167 +state 7765 observe4Greater1 observeIGreater1 + action 0 + 8304 : 1 +state 7766 observe4Greater1 observeIGreater1 + action 0 + 8305 : 0.833 + 8306 : 0.167 +state 7767 observe4Greater1 observeIGreater1 + action 0 + 8307 : 1 +state 7768 observe4Greater1 observeIGreater1 + action 0 + 8308 : 0.833 + 8309 : 0.167 +state 7769 observe4Greater1 observeIGreater1 + action 0 + 8310 : 1 +state 7770 observe4Greater1 observeIGreater1 + action 0 + 8311 : 0.833 + 8312 : 0.167 +state 7771 observe4Greater1 observeIGreater1 + action 0 + 8313 : 1 +state 7772 deadlock observe4Greater1 observeIGreater1 + action 0 + 7772 : 1 +state 7773 deadlock observe4Greater1 observeIGreater1 + action 0 + 7773 : 1 +state 7774 deadlock observe4Greater1 observeIGreater1 + action 0 + 7774 : 1 +state 7775 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7775 : 1 +state 7776 deadlock observe4Greater1 observeIGreater1 + action 0 + 7776 : 1 +state 7777 observe4Greater1 observeIGreater1 + action 0 + 6642 : 0.833 + 6643 : 0.167 +state 7778 observe4Greater1 observeIGreater1 + action 0 + 8314 : 1 +state 7779 observe4Greater1 observeIGreater1 + action 0 + 8315 : 0.833 + 8316 : 0.167 +state 7780 observe4Greater1 observeIGreater1 + action 0 + 8317 : 1 +state 7781 observe4Greater1 observeIGreater1 + action 0 + 8318 : 0.833 + 8319 : 0.167 +state 7782 observe4Greater1 observeIGreater1 + action 0 + 8320 : 1 +state 7783 observe4Greater1 observeIGreater1 + action 0 + 8321 : 0.833 + 8322 : 0.167 +state 7784 observe4Greater1 observeIGreater1 + action 0 + 8323 : 1 +state 7785 observe4Greater1 observeIGreater1 + action 0 + 8324 : 0.833 + 8325 : 0.167 +state 7786 observe4Greater1 observeIGreater1 + action 0 + 8326 : 1 +state 7787 deadlock observe4Greater1 observeIGreater1 + action 0 + 7787 : 1 +state 7788 deadlock observe4Greater1 observeIGreater1 + action 0 + 7788 : 1 +state 7789 deadlock observe4Greater1 observeIGreater1 + action 0 + 7789 : 1 +state 7790 deadlock observe4Greater1 observeIGreater1 + action 0 + 7790 : 1 +state 7791 deadlock observe4Greater1 observeIGreater1 + action 0 + 7791 : 1 +state 7792 deadlock observe1Greater1 observeIGreater1 + action 0 + 7792 : 1 +state 7793 deadlock observe1Greater1 observeIGreater1 + action 0 + 7793 : 1 +state 7794 deadlock observe1Greater1 observeIGreater1 + action 0 + 7794 : 1 +state 7795 deadlock observe1Greater1 observeIGreater1 + action 0 + 7795 : 1 +state 7796 deadlock observe1Greater1 observeIGreater1 + action 0 + 7796 : 1 +state 7797 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7797 : 1 +state 7798 deadlock observe1Greater1 observeIGreater1 + action 0 + 7798 : 1 +state 7799 deadlock observe1Greater1 observeIGreater1 + action 0 + 7799 : 1 +state 7800 deadlock observe1Greater1 observeIGreater1 + action 0 + 7800 : 1 +state 7801 deadlock observe1Greater1 observeIGreater1 + action 0 + 7801 : 1 +state 7802 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7802 : 1 +state 7803 deadlock observe1Greater1 observeIGreater1 + action 0 + 7803 : 1 +state 7804 deadlock observe1Greater1 observeIGreater1 + action 0 + 7804 : 1 +state 7805 deadlock observe1Greater1 observeIGreater1 + action 0 + 7805 : 1 +state 7806 deadlock observe1Greater1 observeIGreater1 + action 0 + 7806 : 1 +state 7807 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7807 : 1 +state 7808 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7808 : 1 +state 7809 deadlock observe2Greater1 observeIGreater1 + action 0 + 7809 : 1 +state 7810 deadlock observe2Greater1 observeIGreater1 + action 0 + 7810 : 1 +state 7811 deadlock observe2Greater1 observeIGreater1 + action 0 + 7811 : 1 +state 7812 deadlock observe1Greater1 observeIGreater1 + action 0 + 7812 : 1 +state 7813 deadlock observe2Greater1 observeIGreater1 + action 0 + 7813 : 1 +state 7814 deadlock observe3Greater1 observeIGreater1 + action 0 + 7814 : 1 +state 7815 deadlock + action 0 + 7815 : 1 +state 7816 deadlock observe1Greater1 observeIGreater1 + action 0 + 7816 : 1 +state 7817 deadlock observe2Greater1 observeIGreater1 + action 0 + 7817 : 1 +state 7818 deadlock + action 0 + 7818 : 1 +state 7819 deadlock observe4Greater1 observeIGreater1 + action 0 + 7819 : 1 +state 7820 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7820 : 1 +state 7821 deadlock observe3Greater1 observeIGreater1 + action 0 + 7821 : 1 +state 7822 deadlock observe3Greater1 observeIGreater1 + action 0 + 7822 : 1 +state 7823 deadlock observe3Greater1 observeIGreater1 + action 0 + 7823 : 1 +state 7824 deadlock observe1Greater1 observeIGreater1 + action 0 + 7824 : 1 +state 7825 deadlock + action 0 + 7825 : 1 +state 7826 deadlock observe3Greater1 observeIGreater1 + action 0 + 7826 : 1 +state 7827 deadlock observe4Greater1 observeIGreater1 + action 0 + 7827 : 1 +state 7828 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7828 : 1 +state 7829 deadlock observe4Greater1 observeIGreater1 + action 0 + 7829 : 1 +state 7830 deadlock observe4Greater1 observeIGreater1 + action 0 + 7830 : 1 +state 7831 deadlock observe4Greater1 observeIGreater1 + action 0 + 7831 : 1 +state 7832 deadlock observe2Greater1 observeIGreater1 + action 0 + 7832 : 1 +state 7833 deadlock observe2Greater1 observeIGreater1 + action 0 + 7833 : 1 +state 7834 deadlock observe2Greater1 observeIGreater1 + action 0 + 7834 : 1 +state 7835 deadlock observe2Greater1 observeIGreater1 + action 0 + 7835 : 1 +state 7836 deadlock observe2Greater1 observeIGreater1 + action 0 + 7836 : 1 +state 7837 deadlock observe2Greater1 observeIGreater1 + action 0 + 7837 : 1 +state 7838 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7838 : 1 +state 7839 deadlock observe2Greater1 observeIGreater1 + action 0 + 7839 : 1 +state 7840 deadlock observe2Greater1 observeIGreater1 + action 0 + 7840 : 1 +state 7841 deadlock observe2Greater1 observeIGreater1 + action 0 + 7841 : 1 +state 7842 deadlock observe2Greater1 observeIGreater1 + action 0 + 7842 : 1 +state 7843 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7843 : 1 +state 7844 deadlock observe3Greater1 observeIGreater1 + action 0 + 7844 : 1 +state 7845 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7845 : 1 +state 7846 deadlock observe3Greater1 observeIGreater1 + action 0 + 7846 : 1 +state 7847 deadlock observe3Greater1 observeIGreater1 + action 0 + 7847 : 1 +state 7848 deadlock + action 0 + 7848 : 1 +state 7849 deadlock observe2Greater1 observeIGreater1 + action 0 + 7849 : 1 +state 7850 deadlock observe3Greater1 observeIGreater1 + action 0 + 7850 : 1 +state 7851 deadlock observe4Greater1 observeIGreater1 + action 0 + 7851 : 1 +state 7852 deadlock observe4Greater1 observeIGreater1 + action 0 + 7852 : 1 +state 7853 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7853 : 1 +state 7854 deadlock observe4Greater1 observeIGreater1 + action 0 + 7854 : 1 +state 7855 deadlock observe4Greater1 observeIGreater1 + action 0 + 7855 : 1 +state 7856 deadlock observe3Greater1 observeIGreater1 + action 0 + 7856 : 1 +state 7857 deadlock observe3Greater1 observeIGreater1 + action 0 + 7857 : 1 +state 7858 deadlock observe3Greater1 observeIGreater1 + action 0 + 7858 : 1 +state 7859 deadlock observe3Greater1 observeIGreater1 + action 0 + 7859 : 1 +state 7860 deadlock observe3Greater1 observeIGreater1 + action 0 + 7860 : 1 +state 7861 deadlock observe3Greater1 observeIGreater1 + action 0 + 7861 : 1 +state 7862 deadlock observe3Greater1 observeIGreater1 + action 0 + 7862 : 1 +state 7863 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7863 : 1 +state 7864 deadlock observe4Greater1 observeIGreater1 + action 0 + 7864 : 1 +state 7865 deadlock observe4Greater1 observeIGreater1 + action 0 + 7865 : 1 +state 7866 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7866 : 1 +state 7867 deadlock observe4Greater1 observeIGreater1 + action 0 + 7867 : 1 +state 7868 deadlock observe4Greater1 observeIGreater1 + action 0 + 7868 : 1 +state 7869 deadlock observe4Greater1 observeIGreater1 + action 0 + 7869 : 1 +state 7870 deadlock observe4Greater1 observeIGreater1 + action 0 + 7870 : 1 +state 7871 deadlock observe4Greater1 observeIGreater1 + action 0 + 7871 : 1 +state 7872 deadlock observe1Greater1 observeIGreater1 + action 0 + 7872 : 1 +state 7873 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7874 observe1Greater1 observeIGreater1 + action 0 + 8327 : 1 +state 7875 deadlock observe1Greater1 observeIGreater1 + action 0 + 7875 : 1 +state 7876 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7877 observe1Greater1 observeIGreater1 + action 0 + 8328 : 1 +state 7878 deadlock observe1Greater1 observeIGreater1 + action 0 + 7878 : 1 +state 7879 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7880 observe1Greater1 observeIGreater1 + action 0 + 8329 : 1 +state 7881 deadlock observe1Greater1 observeIGreater1 + action 0 + 7881 : 1 +state 7882 observe1Greater1 observeIGreater1 + action 0 + 6957 : 0.2 + 6958 : 0.2 + 6959 : 0.2 + 6960 : 0.2 + 6961 : 0.2 +state 7883 observe1Greater1 observeIGreater1 + action 0 + 8330 : 1 +state 7884 deadlock observe1Greater1 observeIGreater1 + action 0 + 7884 : 1 +state 7885 deadlock observe1Greater1 observeIGreater1 + action 0 + 7885 : 1 +state 7886 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7887 observe1Greater1 observeIGreater1 + action 0 + 8331 : 1 +state 7888 deadlock observe1Greater1 observeIGreater1 + action 0 + 7888 : 1 +state 7889 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7890 observe1Greater1 observeIGreater1 + action 0 + 8332 : 1 +state 7891 deadlock observe1Greater1 observeIGreater1 + action 0 + 7891 : 1 +state 7892 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7893 observe1Greater1 observeIGreater1 + action 0 + 8333 : 1 +state 7894 deadlock observe1Greater1 observeIGreater1 + action 0 + 7894 : 1 +state 7895 observe1Greater1 observeIGreater1 + action 0 + 6963 : 0.2 + 6964 : 0.2 + 6965 : 0.2 + 6966 : 0.2 + 6967 : 0.2 +state 7896 observe1Greater1 observeIGreater1 + action 0 + 8334 : 1 +state 7897 deadlock observe1Greater1 observeIGreater1 + action 0 + 7897 : 1 +state 7898 deadlock observe1Greater1 observeIGreater1 + action 0 + 7898 : 1 +state 7899 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7900 observe1Greater1 observeIGreater1 + action 0 + 8335 : 1 +state 7901 deadlock observe1Greater1 observeIGreater1 + action 0 + 7901 : 1 +state 7902 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7903 observe1Greater1 observeIGreater1 + action 0 + 8336 : 1 +state 7904 deadlock observe1Greater1 observeIGreater1 + action 0 + 7904 : 1 +state 7905 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7906 observe1Greater1 observeIGreater1 + action 0 + 8337 : 1 +state 7907 deadlock observe1Greater1 observeIGreater1 + action 0 + 7907 : 1 +state 7908 observe1Greater1 observeIGreater1 + action 0 + 6969 : 0.2 + 6970 : 0.2 + 6971 : 0.2 + 6972 : 0.2 + 6973 : 0.2 +state 7909 observe1Greater1 observeIGreater1 + action 0 + 8338 : 1 +state 7910 deadlock observe1Greater1 observeIGreater1 + action 0 + 7910 : 1 +state 7911 deadlock observe1Greater1 observeIGreater1 + action 0 + 7911 : 1 +state 7912 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7913 observe1Greater1 observeIGreater1 + action 0 + 8339 : 1 +state 7914 deadlock observe1Greater1 observeIGreater1 + action 0 + 7914 : 1 +state 7915 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7916 observe1Greater1 observeIGreater1 + action 0 + 8340 : 1 +state 7917 deadlock observe1Greater1 observeIGreater1 + action 0 + 7917 : 1 +state 7918 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7919 observe1Greater1 observeIGreater1 + action 0 + 8341 : 1 +state 7920 deadlock observe1Greater1 observeIGreater1 + action 0 + 7920 : 1 +state 7921 observe1Greater1 observeIGreater1 + action 0 + 6975 : 0.2 + 6976 : 0.2 + 6977 : 0.2 + 6978 : 0.2 + 6979 : 0.2 +state 7922 observe1Greater1 observeIGreater1 + action 0 + 8342 : 1 +state 7923 deadlock observe1Greater1 observeIGreater1 + action 0 + 7923 : 1 +state 7924 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7924 : 1 +state 7925 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7926 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8343 : 1 +state 7927 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7927 : 1 +state 7928 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7929 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8344 : 1 +state 7930 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7930 : 1 +state 7931 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7932 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8345 : 1 +state 7933 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7933 : 1 +state 7934 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 6985 : 0.2 + 6986 : 0.2 + 6987 : 0.2 + 6988 : 0.2 + 6989 : 0.2 +state 7935 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8346 : 1 +state 7936 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 7936 : 1 +state 7937 deadlock observe1Greater1 observeIGreater1 + action 0 + 7937 : 1 +state 7938 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7939 observe1Greater1 observeIGreater1 + action 0 + 8347 : 1 +state 7940 deadlock observe1Greater1 observeIGreater1 + action 0 + 7940 : 1 +state 7941 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7942 observe1Greater1 observeIGreater1 + action 0 + 8348 : 1 +state 7943 deadlock observe1Greater1 observeIGreater1 + action 0 + 7943 : 1 +state 7944 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7945 observe1Greater1 observeIGreater1 + action 0 + 8349 : 1 +state 7946 deadlock observe1Greater1 observeIGreater1 + action 0 + 7946 : 1 +state 7947 observe1Greater1 observeIGreater1 + action 0 + 6991 : 0.2 + 6992 : 0.2 + 6993 : 0.2 + 6994 : 0.2 + 6995 : 0.2 +state 7948 observe1Greater1 observeIGreater1 + action 0 + 8350 : 1 +state 7949 deadlock observe1Greater1 observeIGreater1 + action 0 + 7949 : 1 +state 7950 deadlock observe1Greater1 observeIGreater1 + action 0 + 7950 : 1 +state 7951 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7952 observe1Greater1 observeIGreater1 + action 0 + 8351 : 1 +state 7953 deadlock observe1Greater1 observeIGreater1 + action 0 + 7953 : 1 +state 7954 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7955 observe1Greater1 observeIGreater1 + action 0 + 8352 : 1 +state 7956 deadlock observe1Greater1 observeIGreater1 + action 0 + 7956 : 1 +state 7957 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7958 observe1Greater1 observeIGreater1 + action 0 + 8353 : 1 +state 7959 deadlock observe1Greater1 observeIGreater1 + action 0 + 7959 : 1 +state 7960 observe1Greater1 observeIGreater1 + action 0 + 6997 : 0.2 + 6998 : 0.2 + 6999 : 0.2 + 7000 : 0.2 + 7001 : 0.2 +state 7961 observe1Greater1 observeIGreater1 + action 0 + 8354 : 1 +state 7962 deadlock observe1Greater1 observeIGreater1 + action 0 + 7962 : 1 +state 7963 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7963 : 1 +state 7964 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7965 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8355 : 1 +state 7966 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7966 : 1 +state 7967 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7968 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8356 : 1 +state 7969 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7969 : 1 +state 7970 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7971 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8357 : 1 +state 7972 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7972 : 1 +state 7973 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7007 : 0.2 + 7008 : 0.2 + 7009 : 0.2 + 7010 : 0.2 + 7011 : 0.2 +state 7974 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8358 : 1 +state 7975 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 7975 : 1 +state 7976 deadlock observe1Greater1 observeIGreater1 + action 0 + 7976 : 1 +state 7977 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7978 observe1Greater1 observeIGreater1 + action 0 + 8359 : 1 +state 7979 deadlock observe1Greater1 observeIGreater1 + action 0 + 7979 : 1 +state 7980 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7981 observe1Greater1 observeIGreater1 + action 0 + 8360 : 1 +state 7982 deadlock observe1Greater1 observeIGreater1 + action 0 + 7982 : 1 +state 7983 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7984 observe1Greater1 observeIGreater1 + action 0 + 8361 : 1 +state 7985 deadlock observe1Greater1 observeIGreater1 + action 0 + 7985 : 1 +state 7986 observe1Greater1 observeIGreater1 + action 0 + 7013 : 0.2 + 7014 : 0.2 + 7015 : 0.2 + 7016 : 0.2 + 7017 : 0.2 +state 7987 observe1Greater1 observeIGreater1 + action 0 + 8362 : 1 +state 7988 deadlock observe1Greater1 observeIGreater1 + action 0 + 7988 : 1 +state 7989 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7989 : 1 +state 7990 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 7991 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8363 : 1 +state 7992 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7992 : 1 +state 7993 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 7994 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8364 : 1 +state 7995 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7995 : 1 +state 7996 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 7997 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8365 : 1 +state 7998 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7998 : 1 +state 7999 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 7023 : 0.2 + 7024 : 0.2 + 7025 : 0.2 + 7026 : 0.2 + 7027 : 0.2 +state 8000 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8366 : 1 +state 8001 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8001 : 1 +state 8002 deadlock observe2Greater1 observeIGreater1 + action 0 + 8002 : 1 +state 8003 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8004 observe2Greater1 observeIGreater1 + action 0 + 8367 : 1 +state 8005 deadlock observe2Greater1 observeIGreater1 + action 0 + 8005 : 1 +state 8006 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8007 observe2Greater1 observeIGreater1 + action 0 + 8368 : 1 +state 8008 deadlock observe2Greater1 observeIGreater1 + action 0 + 8008 : 1 +state 8009 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8010 observe2Greater1 observeIGreater1 + action 0 + 8369 : 1 +state 8011 deadlock observe2Greater1 observeIGreater1 + action 0 + 8011 : 1 +state 8012 observe2Greater1 observeIGreater1 + action 0 + 7033 : 0.2 + 7034 : 0.2 + 7035 : 0.2 + 7036 : 0.2 + 7037 : 0.2 +state 8013 observe2Greater1 observeIGreater1 + action 0 + 8370 : 1 +state 8014 deadlock observe2Greater1 observeIGreater1 + action 0 + 8014 : 1 +state 8015 deadlock observe2Greater1 observeIGreater1 + action 0 + 8015 : 1 +state 8016 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8017 observe2Greater1 observeIGreater1 + action 0 + 8371 : 1 +state 8018 deadlock observe2Greater1 observeIGreater1 + action 0 + 8018 : 1 +state 8019 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8020 observe2Greater1 observeIGreater1 + action 0 + 8372 : 1 +state 8021 deadlock observe2Greater1 observeIGreater1 + action 0 + 8021 : 1 +state 8022 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8023 observe2Greater1 observeIGreater1 + action 0 + 8373 : 1 +state 8024 deadlock observe2Greater1 observeIGreater1 + action 0 + 8024 : 1 +state 8025 observe2Greater1 observeIGreater1 + action 0 + 7039 : 0.2 + 7040 : 0.2 + 7041 : 0.2 + 7042 : 0.2 + 7043 : 0.2 +state 8026 observe2Greater1 observeIGreater1 + action 0 + 8374 : 1 +state 8027 deadlock observe2Greater1 observeIGreater1 + action 0 + 8027 : 1 +state 8028 deadlock observe2Greater1 observeIGreater1 + action 0 + 8028 : 1 +state 8029 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8030 observe2Greater1 observeIGreater1 + action 0 + 8375 : 1 +state 8031 deadlock observe2Greater1 observeIGreater1 + action 0 + 8031 : 1 +state 8032 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8033 observe2Greater1 observeIGreater1 + action 0 + 8376 : 1 +state 8034 deadlock observe2Greater1 observeIGreater1 + action 0 + 8034 : 1 +state 8035 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8036 observe2Greater1 observeIGreater1 + action 0 + 8377 : 1 +state 8037 deadlock observe2Greater1 observeIGreater1 + action 0 + 8037 : 1 +state 8038 observe2Greater1 observeIGreater1 + action 0 + 7045 : 0.2 + 7046 : 0.2 + 7047 : 0.2 + 7048 : 0.2 + 7049 : 0.2 +state 8039 observe2Greater1 observeIGreater1 + action 0 + 8378 : 1 +state 8040 deadlock observe2Greater1 observeIGreater1 + action 0 + 8040 : 1 +state 8041 deadlock observe3Greater1 observeIGreater1 + action 0 + 8041 : 1 +state 8042 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8043 observe3Greater1 observeIGreater1 + action 0 + 8379 : 1 +state 8044 deadlock observe3Greater1 observeIGreater1 + action 0 + 8044 : 1 +state 8045 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8046 observe3Greater1 observeIGreater1 + action 0 + 8380 : 1 +state 8047 deadlock observe3Greater1 observeIGreater1 + action 0 + 8047 : 1 +state 8048 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8049 observe3Greater1 observeIGreater1 + action 0 + 8381 : 1 +state 8050 deadlock observe3Greater1 observeIGreater1 + action 0 + 8050 : 1 +state 8051 observe3Greater1 observeIGreater1 + action 0 + 7055 : 0.2 + 7056 : 0.2 + 7057 : 0.2 + 7058 : 0.2 + 7059 : 0.2 +state 8052 observe3Greater1 observeIGreater1 + action 0 + 8382 : 1 +state 8053 deadlock observe3Greater1 observeIGreater1 + action 0 + 8053 : 1 +state 8054 deadlock + action 0 + 8054 : 1 +state 8055 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8056 + action 0 + 8383 : 1 +state 8057 deadlock + action 0 + 8057 : 1 +state 8058 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8059 + action 0 + 8384 : 1 +state 8060 deadlock + action 0 + 8060 : 1 +state 8061 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8062 + action 0 + 8385 : 1 +state 8063 deadlock + action 0 + 8063 : 1 +state 8064 + action 0 + 7061 : 0.2 + 7062 : 0.2 + 7063 : 0.2 + 7064 : 0.2 + 7065 : 0.2 +state 8065 + action 0 + 8386 : 1 +state 8066 deadlock + action 0 + 8066 : 1 +state 8067 deadlock observe4Greater1 observeIGreater1 + action 0 + 8067 : 1 +state 8068 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8069 observe4Greater1 observeIGreater1 + action 0 + 8387 : 1 +state 8070 deadlock observe4Greater1 observeIGreater1 + action 0 + 8070 : 1 +state 8071 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8072 observe4Greater1 observeIGreater1 + action 0 + 8388 : 1 +state 8073 deadlock observe4Greater1 observeIGreater1 + action 0 + 8073 : 1 +state 8074 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8075 observe4Greater1 observeIGreater1 + action 0 + 8389 : 1 +state 8076 deadlock observe4Greater1 observeIGreater1 + action 0 + 8076 : 1 +state 8077 observe4Greater1 observeIGreater1 + action 0 + 7071 : 0.2 + 7072 : 0.2 + 7073 : 0.2 + 7074 : 0.2 + 7075 : 0.2 +state 8078 observe4Greater1 observeIGreater1 + action 0 + 8390 : 1 +state 8079 deadlock observe4Greater1 observeIGreater1 + action 0 + 8079 : 1 +state 8080 deadlock observe3Greater1 observeIGreater1 + action 0 + 8080 : 1 +state 8081 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8082 observe3Greater1 observeIGreater1 + action 0 + 8391 : 1 +state 8083 deadlock observe3Greater1 observeIGreater1 + action 0 + 8083 : 1 +state 8084 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8085 observe3Greater1 observeIGreater1 + action 0 + 8392 : 1 +state 8086 deadlock observe3Greater1 observeIGreater1 + action 0 + 8086 : 1 +state 8087 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8088 observe3Greater1 observeIGreater1 + action 0 + 8393 : 1 +state 8089 deadlock observe3Greater1 observeIGreater1 + action 0 + 8089 : 1 +state 8090 observe3Greater1 observeIGreater1 + action 0 + 7081 : 0.2 + 7082 : 0.2 + 7083 : 0.2 + 7084 : 0.2 + 7085 : 0.2 +state 8091 observe3Greater1 observeIGreater1 + action 0 + 8394 : 1 +state 8092 deadlock observe3Greater1 observeIGreater1 + action 0 + 8092 : 1 +state 8093 deadlock observe3Greater1 observeIGreater1 + action 0 + 8093 : 1 +state 8094 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8095 observe3Greater1 observeIGreater1 + action 0 + 8395 : 1 +state 8096 deadlock observe3Greater1 observeIGreater1 + action 0 + 8096 : 1 +state 8097 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8098 observe3Greater1 observeIGreater1 + action 0 + 8396 : 1 +state 8099 deadlock observe3Greater1 observeIGreater1 + action 0 + 8099 : 1 +state 8100 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8101 observe3Greater1 observeIGreater1 + action 0 + 8397 : 1 +state 8102 deadlock observe3Greater1 observeIGreater1 + action 0 + 8102 : 1 +state 8103 observe3Greater1 observeIGreater1 + action 0 + 7087 : 0.2 + 7088 : 0.2 + 7089 : 0.2 + 7090 : 0.2 + 7091 : 0.2 +state 8104 observe3Greater1 observeIGreater1 + action 0 + 8398 : 1 +state 8105 deadlock observe3Greater1 observeIGreater1 + action 0 + 8105 : 1 +state 8106 deadlock observe4Greater1 observeIGreater1 + action 0 + 8106 : 1 +state 8107 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8108 observe4Greater1 observeIGreater1 + action 0 + 8399 : 1 +state 8109 deadlock observe4Greater1 observeIGreater1 + action 0 + 8109 : 1 +state 8110 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8111 observe4Greater1 observeIGreater1 + action 0 + 8400 : 1 +state 8112 deadlock observe4Greater1 observeIGreater1 + action 0 + 8112 : 1 +state 8113 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8114 observe4Greater1 observeIGreater1 + action 0 + 8401 : 1 +state 8115 deadlock observe4Greater1 observeIGreater1 + action 0 + 8115 : 1 +state 8116 observe4Greater1 observeIGreater1 + action 0 + 7097 : 0.2 + 7098 : 0.2 + 7099 : 0.2 + 7100 : 0.2 + 7101 : 0.2 +state 8117 observe4Greater1 observeIGreater1 + action 0 + 8402 : 1 +state 8118 deadlock observe4Greater1 observeIGreater1 + action 0 + 8118 : 1 +state 8119 deadlock observe4Greater1 observeIGreater1 + action 0 + 8119 : 1 +state 8120 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8121 observe4Greater1 observeIGreater1 + action 0 + 8403 : 1 +state 8122 deadlock observe4Greater1 observeIGreater1 + action 0 + 8122 : 1 +state 8123 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8124 observe4Greater1 observeIGreater1 + action 0 + 8404 : 1 +state 8125 deadlock observe4Greater1 observeIGreater1 + action 0 + 8125 : 1 +state 8126 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8127 observe4Greater1 observeIGreater1 + action 0 + 8405 : 1 +state 8128 deadlock observe4Greater1 observeIGreater1 + action 0 + 8128 : 1 +state 8129 observe4Greater1 observeIGreater1 + action 0 + 7107 : 0.2 + 7108 : 0.2 + 7109 : 0.2 + 7110 : 0.2 + 7111 : 0.2 +state 8130 observe4Greater1 observeIGreater1 + action 0 + 8406 : 1 +state 8131 deadlock observe4Greater1 observeIGreater1 + action 0 + 8131 : 1 +state 8132 deadlock observe2Greater1 observeIGreater1 + action 0 + 8132 : 1 +state 8133 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8134 observe2Greater1 observeIGreater1 + action 0 + 8407 : 1 +state 8135 deadlock observe2Greater1 observeIGreater1 + action 0 + 8135 : 1 +state 8136 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8137 observe2Greater1 observeIGreater1 + action 0 + 8408 : 1 +state 8138 deadlock observe2Greater1 observeIGreater1 + action 0 + 8138 : 1 +state 8139 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8140 observe2Greater1 observeIGreater1 + action 0 + 8409 : 1 +state 8141 deadlock observe2Greater1 observeIGreater1 + action 0 + 8141 : 1 +state 8142 observe2Greater1 observeIGreater1 + action 0 + 7117 : 0.2 + 7118 : 0.2 + 7119 : 0.2 + 7120 : 0.2 + 7121 : 0.2 +state 8143 observe2Greater1 observeIGreater1 + action 0 + 8410 : 1 +state 8144 deadlock observe2Greater1 observeIGreater1 + action 0 + 8144 : 1 +state 8145 deadlock observe2Greater1 observeIGreater1 + action 0 + 8145 : 1 +state 8146 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8147 observe2Greater1 observeIGreater1 + action 0 + 8411 : 1 +state 8148 deadlock observe2Greater1 observeIGreater1 + action 0 + 8148 : 1 +state 8149 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8150 observe2Greater1 observeIGreater1 + action 0 + 8412 : 1 +state 8151 deadlock observe2Greater1 observeIGreater1 + action 0 + 8151 : 1 +state 8152 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8153 observe2Greater1 observeIGreater1 + action 0 + 8413 : 1 +state 8154 deadlock observe2Greater1 observeIGreater1 + action 0 + 8154 : 1 +state 8155 observe2Greater1 observeIGreater1 + action 0 + 7123 : 0.2 + 7124 : 0.2 + 7125 : 0.2 + 7126 : 0.2 + 7127 : 0.2 +state 8156 observe2Greater1 observeIGreater1 + action 0 + 8414 : 1 +state 8157 deadlock observe2Greater1 observeIGreater1 + action 0 + 8157 : 1 +state 8158 deadlock observe2Greater1 observeIGreater1 + action 0 + 8158 : 1 +state 8159 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8160 observe2Greater1 observeIGreater1 + action 0 + 8415 : 1 +state 8161 deadlock observe2Greater1 observeIGreater1 + action 0 + 8161 : 1 +state 8162 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8163 observe2Greater1 observeIGreater1 + action 0 + 8416 : 1 +state 8164 deadlock observe2Greater1 observeIGreater1 + action 0 + 8164 : 1 +state 8165 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8166 observe2Greater1 observeIGreater1 + action 0 + 8417 : 1 +state 8167 deadlock observe2Greater1 observeIGreater1 + action 0 + 8167 : 1 +state 8168 observe2Greater1 observeIGreater1 + action 0 + 7129 : 0.2 + 7130 : 0.2 + 7131 : 0.2 + 7132 : 0.2 + 7133 : 0.2 +state 8169 observe2Greater1 observeIGreater1 + action 0 + 8418 : 1 +state 8170 deadlock observe2Greater1 observeIGreater1 + action 0 + 8170 : 1 +state 8171 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8171 : 1 +state 8172 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8173 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8419 : 1 +state 8174 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8174 : 1 +state 8175 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8176 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8420 : 1 +state 8177 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8177 : 1 +state 8178 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8179 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8421 : 1 +state 8180 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8180 : 1 +state 8181 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 7139 : 0.2 + 7140 : 0.2 + 7141 : 0.2 + 7142 : 0.2 + 7143 : 0.2 +state 8182 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8422 : 1 +state 8183 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8183 : 1 +state 8184 deadlock observe2Greater1 observeIGreater1 + action 0 + 8184 : 1 +state 8185 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8186 observe2Greater1 observeIGreater1 + action 0 + 8423 : 1 +state 8187 deadlock observe2Greater1 observeIGreater1 + action 0 + 8187 : 1 +state 8188 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8189 observe2Greater1 observeIGreater1 + action 0 + 8424 : 1 +state 8190 deadlock observe2Greater1 observeIGreater1 + action 0 + 8190 : 1 +state 8191 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8192 observe2Greater1 observeIGreater1 + action 0 + 8425 : 1 +state 8193 deadlock observe2Greater1 observeIGreater1 + action 0 + 8193 : 1 +state 8194 observe2Greater1 observeIGreater1 + action 0 + 7145 : 0.2 + 7146 : 0.2 + 7147 : 0.2 + 7148 : 0.2 + 7149 : 0.2 +state 8195 observe2Greater1 observeIGreater1 + action 0 + 8426 : 1 +state 8196 deadlock observe2Greater1 observeIGreater1 + action 0 + 8196 : 1 +state 8197 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8197 : 1 +state 8198 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8199 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8427 : 1 +state 8200 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8200 : 1 +state 8201 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8202 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8428 : 1 +state 8203 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8203 : 1 +state 8204 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8205 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8429 : 1 +state 8206 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8206 : 1 +state 8207 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 7155 : 0.2 + 7156 : 0.2 + 7157 : 0.2 + 7158 : 0.2 + 7159 : 0.2 +state 8208 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8430 : 1 +state 8209 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8209 : 1 +state 8210 deadlock observe3Greater1 observeIGreater1 + action 0 + 8210 : 1 +state 8211 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8212 observe3Greater1 observeIGreater1 + action 0 + 8431 : 1 +state 8213 deadlock observe3Greater1 observeIGreater1 + action 0 + 8213 : 1 +state 8214 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8215 observe3Greater1 observeIGreater1 + action 0 + 8432 : 1 +state 8216 deadlock observe3Greater1 observeIGreater1 + action 0 + 8216 : 1 +state 8217 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8218 observe3Greater1 observeIGreater1 + action 0 + 8433 : 1 +state 8219 deadlock observe3Greater1 observeIGreater1 + action 0 + 8219 : 1 +state 8220 observe3Greater1 observeIGreater1 + action 0 + 7165 : 0.2 + 7166 : 0.2 + 7167 : 0.2 + 7168 : 0.2 + 7169 : 0.2 +state 8221 observe3Greater1 observeIGreater1 + action 0 + 8434 : 1 +state 8222 deadlock observe3Greater1 observeIGreater1 + action 0 + 8222 : 1 +state 8223 deadlock observe3Greater1 observeIGreater1 + action 0 + 8223 : 1 +state 8224 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8225 observe3Greater1 observeIGreater1 + action 0 + 8435 : 1 +state 8226 deadlock observe3Greater1 observeIGreater1 + action 0 + 8226 : 1 +state 8227 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8228 observe3Greater1 observeIGreater1 + action 0 + 8436 : 1 +state 8229 deadlock observe3Greater1 observeIGreater1 + action 0 + 8229 : 1 +state 8230 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8231 observe3Greater1 observeIGreater1 + action 0 + 8437 : 1 +state 8232 deadlock observe3Greater1 observeIGreater1 + action 0 + 8232 : 1 +state 8233 observe3Greater1 observeIGreater1 + action 0 + 7171 : 0.2 + 7172 : 0.2 + 7173 : 0.2 + 7174 : 0.2 + 7175 : 0.2 +state 8234 observe3Greater1 observeIGreater1 + action 0 + 8438 : 1 +state 8235 deadlock observe3Greater1 observeIGreater1 + action 0 + 8235 : 1 +state 8236 deadlock observe4Greater1 observeIGreater1 + action 0 + 8236 : 1 +state 8237 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8238 observe4Greater1 observeIGreater1 + action 0 + 8439 : 1 +state 8239 deadlock observe4Greater1 observeIGreater1 + action 0 + 8239 : 1 +state 8240 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8241 observe4Greater1 observeIGreater1 + action 0 + 8440 : 1 +state 8242 deadlock observe4Greater1 observeIGreater1 + action 0 + 8242 : 1 +state 8243 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8244 observe4Greater1 observeIGreater1 + action 0 + 8441 : 1 +state 8245 deadlock observe4Greater1 observeIGreater1 + action 0 + 8245 : 1 +state 8246 observe4Greater1 observeIGreater1 + action 0 + 7181 : 0.2 + 7182 : 0.2 + 7183 : 0.2 + 7184 : 0.2 + 7185 : 0.2 +state 8247 observe4Greater1 observeIGreater1 + action 0 + 8442 : 1 +state 8248 deadlock observe4Greater1 observeIGreater1 + action 0 + 8248 : 1 +state 8249 deadlock observe4Greater1 observeIGreater1 + action 0 + 8249 : 1 +state 8250 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8251 observe4Greater1 observeIGreater1 + action 0 + 8443 : 1 +state 8252 deadlock observe4Greater1 observeIGreater1 + action 0 + 8252 : 1 +state 8253 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8254 observe4Greater1 observeIGreater1 + action 0 + 8444 : 1 +state 8255 deadlock observe4Greater1 observeIGreater1 + action 0 + 8255 : 1 +state 8256 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8257 observe4Greater1 observeIGreater1 + action 0 + 8445 : 1 +state 8258 deadlock observe4Greater1 observeIGreater1 + action 0 + 8258 : 1 +state 8259 observe4Greater1 observeIGreater1 + action 0 + 7191 : 0.2 + 7192 : 0.2 + 7193 : 0.2 + 7194 : 0.2 + 7195 : 0.2 +state 8260 observe4Greater1 observeIGreater1 + action 0 + 8446 : 1 +state 8261 deadlock observe4Greater1 observeIGreater1 + action 0 + 8261 : 1 +state 8262 deadlock observe3Greater1 observeIGreater1 + action 0 + 8262 : 1 +state 8263 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8264 observe3Greater1 observeIGreater1 + action 0 + 8447 : 1 +state 8265 deadlock observe3Greater1 observeIGreater1 + action 0 + 8265 : 1 +state 8266 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8267 observe3Greater1 observeIGreater1 + action 0 + 8448 : 1 +state 8268 deadlock observe3Greater1 observeIGreater1 + action 0 + 8268 : 1 +state 8269 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8270 observe3Greater1 observeIGreater1 + action 0 + 8449 : 1 +state 8271 deadlock observe3Greater1 observeIGreater1 + action 0 + 8271 : 1 +state 8272 observe3Greater1 observeIGreater1 + action 0 + 7201 : 0.2 + 7202 : 0.2 + 7203 : 0.2 + 7204 : 0.2 + 7205 : 0.2 +state 8273 observe3Greater1 observeIGreater1 + action 0 + 8450 : 1 +state 8274 deadlock observe3Greater1 observeIGreater1 + action 0 + 8274 : 1 +state 8275 deadlock observe3Greater1 observeIGreater1 + action 0 + 8275 : 1 +state 8276 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8277 observe3Greater1 observeIGreater1 + action 0 + 8451 : 1 +state 8278 deadlock observe3Greater1 observeIGreater1 + action 0 + 8278 : 1 +state 8279 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8280 observe3Greater1 observeIGreater1 + action 0 + 8452 : 1 +state 8281 deadlock observe3Greater1 observeIGreater1 + action 0 + 8281 : 1 +state 8282 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8283 observe3Greater1 observeIGreater1 + action 0 + 8453 : 1 +state 8284 deadlock observe3Greater1 observeIGreater1 + action 0 + 8284 : 1 +state 8285 observe3Greater1 observeIGreater1 + action 0 + 7207 : 0.2 + 7208 : 0.2 + 7209 : 0.2 + 7210 : 0.2 + 7211 : 0.2 +state 8286 observe3Greater1 observeIGreater1 + action 0 + 8454 : 1 +state 8287 deadlock observe3Greater1 observeIGreater1 + action 0 + 8287 : 1 +state 8288 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8288 : 1 +state 8289 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8290 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8455 : 1 +state 8291 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8291 : 1 +state 8292 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8293 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8456 : 1 +state 8294 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8294 : 1 +state 8295 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8296 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8457 : 1 +state 8297 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8297 : 1 +state 8298 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 7217 : 0.2 + 7218 : 0.2 + 7219 : 0.2 + 7220 : 0.2 + 7221 : 0.2 +state 8299 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8458 : 1 +state 8300 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8300 : 1 +state 8301 deadlock observe4Greater1 observeIGreater1 + action 0 + 8301 : 1 +state 8302 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8303 observe4Greater1 observeIGreater1 + action 0 + 8459 : 1 +state 8304 deadlock observe4Greater1 observeIGreater1 + action 0 + 8304 : 1 +state 8305 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8306 observe4Greater1 observeIGreater1 + action 0 + 8460 : 1 +state 8307 deadlock observe4Greater1 observeIGreater1 + action 0 + 8307 : 1 +state 8308 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8309 observe4Greater1 observeIGreater1 + action 0 + 8461 : 1 +state 8310 deadlock observe4Greater1 observeIGreater1 + action 0 + 8310 : 1 +state 8311 observe4Greater1 observeIGreater1 + action 0 + 7227 : 0.2 + 7228 : 0.2 + 7229 : 0.2 + 7230 : 0.2 + 7231 : 0.2 +state 8312 observe4Greater1 observeIGreater1 + action 0 + 8462 : 1 +state 8313 deadlock observe4Greater1 observeIGreater1 + action 0 + 8313 : 1 +state 8314 deadlock observe4Greater1 observeIGreater1 + action 0 + 8314 : 1 +state 8315 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8316 observe4Greater1 observeIGreater1 + action 0 + 8463 : 1 +state 8317 deadlock observe4Greater1 observeIGreater1 + action 0 + 8317 : 1 +state 8318 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8319 observe4Greater1 observeIGreater1 + action 0 + 8464 : 1 +state 8320 deadlock observe4Greater1 observeIGreater1 + action 0 + 8320 : 1 +state 8321 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8322 observe4Greater1 observeIGreater1 + action 0 + 8465 : 1 +state 8323 deadlock observe4Greater1 observeIGreater1 + action 0 + 8323 : 1 +state 8324 observe4Greater1 observeIGreater1 + action 0 + 7237 : 0.2 + 7238 : 0.2 + 7239 : 0.2 + 7240 : 0.2 + 7241 : 0.2 +state 8325 observe4Greater1 observeIGreater1 + action 0 + 8466 : 1 +state 8326 deadlock observe4Greater1 observeIGreater1 + action 0 + 8326 : 1 +state 8327 observe1Greater1 observeIGreater1 + action 0 + 8467 : 1 +state 8328 observe1Greater1 observeIGreater1 + action 0 + 8468 : 1 +state 8329 observe1Greater1 observeIGreater1 + action 0 + 8469 : 1 +state 8330 observe1Greater1 observeIGreater1 + action 0 + 8470 : 1 +state 8331 observe1Greater1 observeIGreater1 + action 0 + 8471 : 1 +state 8332 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8472 : 1 +state 8333 observe1Greater1 observeIGreater1 + action 0 + 8473 : 1 +state 8334 observe1Greater1 observeIGreater1 + action 0 + 8474 : 1 +state 8335 observe1Greater1 observeIGreater1 + action 0 + 8475 : 1 +state 8336 observe1Greater1 observeIGreater1 + action 0 + 8476 : 1 +state 8337 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8477 : 1 +state 8338 observe1Greater1 observeIGreater1 + action 0 + 8478 : 1 +state 8339 observe1Greater1 observeIGreater1 + action 0 + 8479 : 1 +state 8340 observe1Greater1 observeIGreater1 + action 0 + 8480 : 1 +state 8341 observe1Greater1 observeIGreater1 + action 0 + 8481 : 1 +state 8342 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8482 : 1 +state 8343 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8483 : 1 +state 8344 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8484 : 1 +state 8345 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8485 : 1 +state 8346 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8486 : 1 +state 8347 observe1Greater1 observeIGreater1 + action 0 + 8487 : 1 +state 8348 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8488 : 1 +state 8349 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8489 : 1 +state 8350 observe1Greater1 observeIGreater1 + action 0 + 8490 : 1 +state 8351 observe1Greater1 observeIGreater1 + action 0 + 8491 : 1 +state 8352 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8492 : 1 +state 8353 observe1Greater1 observeIGreater1 + action 0 + 8493 : 1 +state 8354 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8494 : 1 +state 8355 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8495 : 1 +state 8356 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8496 : 1 +state 8357 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8497 : 1 +state 8358 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8498 : 1 +state 8359 observe1Greater1 observeIGreater1 + action 0 + 8499 : 1 +state 8360 observe1Greater1 observeIGreater1 + action 0 + 8500 : 1 +state 8361 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8501 : 1 +state 8362 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8502 : 1 +state 8363 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8503 : 1 +state 8364 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8504 : 1 +state 8365 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8505 : 1 +state 8366 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8506 : 1 +state 8367 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8507 : 1 +state 8368 observe2Greater1 observeIGreater1 + action 0 + 8508 : 1 +state 8369 observe2Greater1 observeIGreater1 + action 0 + 8509 : 1 +state 8370 observe2Greater1 observeIGreater1 + action 0 + 8510 : 1 +state 8371 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8511 : 1 +state 8372 observe2Greater1 observeIGreater1 + action 0 + 8512 : 1 +state 8373 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8513 : 1 +state 8374 observe2Greater1 observeIGreater1 + action 0 + 8514 : 1 +state 8375 observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8515 : 1 +state 8376 observe2Greater1 observeIGreater1 + action 0 + 8516 : 1 +state 8377 observe2Greater1 observeIGreater1 + action 0 + 8517 : 1 +state 8378 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8518 : 1 +state 8379 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8519 : 1 +state 8380 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8520 : 1 +state 8381 observe3Greater1 observeIGreater1 + action 0 + 8521 : 1 +state 8382 observe3Greater1 observeIGreater1 + action 0 + 8522 : 1 +state 8383 observe1Greater1 observeIGreater1 + action 0 + 8523 : 1 +state 8384 observe2Greater1 observeIGreater1 + action 0 + 8524 : 1 +state 8385 observe3Greater1 observeIGreater1 + action 0 + 8525 : 1 +state 8386 observe4Greater1 observeIGreater1 + action 0 + 8526 : 1 +state 8387 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8527 : 1 +state 8388 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8528 : 1 +state 8389 observe4Greater1 observeIGreater1 + action 0 + 8529 : 1 +state 8390 observe4Greater1 observeIGreater1 + action 0 + 8530 : 1 +state 8391 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8531 : 1 +state 8392 observe3Greater1 observeIGreater1 + action 0 + 8532 : 1 +state 8393 observe3Greater1 observeIGreater1 + action 0 + 8533 : 1 +state 8394 observe3Greater1 observeIGreater1 + action 0 + 8534 : 1 +state 8395 observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8535 : 1 +state 8396 observe3Greater1 observeIGreater1 + action 0 + 8536 : 1 +state 8397 observe3Greater1 observeIGreater1 + action 0 + 8537 : 1 +state 8398 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8538 : 1 +state 8399 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8539 : 1 +state 8400 observe4Greater1 observeIGreater1 + action 0 + 8540 : 1 +state 8401 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8541 : 1 +state 8402 observe4Greater1 observeIGreater1 + action 0 + 8542 : 1 +state 8403 observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8543 : 1 +state 8404 observe4Greater1 observeIGreater1 + action 0 + 8544 : 1 +state 8405 observe4Greater1 observeIGreater1 + action 0 + 8545 : 1 +state 8406 observe4Greater1 observeIGreater1 + action 0 + 8546 : 1 +state 8407 observe2Greater1 observeIGreater1 + action 0 + 8547 : 1 +state 8408 observe2Greater1 observeIGreater1 + action 0 + 8548 : 1 +state 8409 observe2Greater1 observeIGreater1 + action 0 + 8549 : 1 +state 8410 observe2Greater1 observeIGreater1 + action 0 + 8550 : 1 +state 8411 observe2Greater1 observeIGreater1 + action 0 + 8551 : 1 +state 8412 observe2Greater1 observeIGreater1 + action 0 + 8552 : 1 +state 8413 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8553 : 1 +state 8414 observe2Greater1 observeIGreater1 + action 0 + 8554 : 1 +state 8415 observe2Greater1 observeIGreater1 + action 0 + 8555 : 1 +state 8416 observe2Greater1 observeIGreater1 + action 0 + 8556 : 1 +state 8417 observe2Greater1 observeIGreater1 + action 0 + 8557 : 1 +state 8418 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8558 : 1 +state 8419 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8559 : 1 +state 8420 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8560 : 1 +state 8421 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8561 : 1 +state 8422 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8562 : 1 +state 8423 observe2Greater1 observeIGreater1 + action 0 + 8563 : 1 +state 8424 observe2Greater1 observeIGreater1 + action 0 + 8564 : 1 +state 8425 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8565 : 1 +state 8426 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8566 : 1 +state 8427 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8567 : 1 +state 8428 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8568 : 1 +state 8429 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8569 : 1 +state 8430 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8570 : 1 +state 8431 observe3Greater1 observeIGreater1 + action 0 + 8571 : 1 +state 8432 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8572 : 1 +state 8433 observe3Greater1 observeIGreater1 + action 0 + 8573 : 1 +state 8434 observe3Greater1 observeIGreater1 + action 0 + 8574 : 1 +state 8435 observe3Greater1 observeIGreater1 + action 0 + 8575 : 1 +state 8436 observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8576 : 1 +state 8437 observe3Greater1 observeIGreater1 + action 0 + 8577 : 1 +state 8438 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8578 : 1 +state 8439 observe4Greater1 observeIGreater1 + action 0 + 8579 : 1 +state 8440 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8580 : 1 +state 8441 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8581 : 1 +state 8442 observe4Greater1 observeIGreater1 + action 0 + 8582 : 1 +state 8443 observe4Greater1 observeIGreater1 + action 0 + 8583 : 1 +state 8444 observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8584 : 1 +state 8445 observe4Greater1 observeIGreater1 + action 0 + 8585 : 1 +state 8446 observe4Greater1 observeIGreater1 + action 0 + 8586 : 1 +state 8447 observe3Greater1 observeIGreater1 + action 0 + 8587 : 1 +state 8448 observe3Greater1 observeIGreater1 + action 0 + 8588 : 1 +state 8449 observe3Greater1 observeIGreater1 + action 0 + 8589 : 1 +state 8450 observe3Greater1 observeIGreater1 + action 0 + 8590 : 1 +state 8451 observe3Greater1 observeIGreater1 + action 0 + 8591 : 1 +state 8452 observe3Greater1 observeIGreater1 + action 0 + 8592 : 1 +state 8453 observe3Greater1 observeIGreater1 + action 0 + 8593 : 1 +state 8454 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8594 : 1 +state 8455 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8595 : 1 +state 8456 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8596 : 1 +state 8457 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8597 : 1 +state 8458 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8598 : 1 +state 8459 observe4Greater1 observeIGreater1 + action 0 + 8599 : 1 +state 8460 observe4Greater1 observeIGreater1 + action 0 + 8600 : 1 +state 8461 observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8601 : 1 +state 8462 observe4Greater1 observeIGreater1 + action 0 + 8602 : 1 +state 8463 observe4Greater1 observeIGreater1 + action 0 + 8603 : 1 +state 8464 observe4Greater1 observeIGreater1 + action 0 + 8604 : 1 +state 8465 observe4Greater1 observeIGreater1 + action 0 + 8605 : 1 +state 8466 observe4Greater1 observeIGreater1 + action 0 + 8606 : 1 +state 8467 deadlock observe1Greater1 observeIGreater1 + action 0 + 8467 : 1 +state 8468 deadlock observe1Greater1 observeIGreater1 + action 0 + 8468 : 1 +state 8469 deadlock observe1Greater1 observeIGreater1 + action 0 + 8469 : 1 +state 8470 deadlock observe1Greater1 observeIGreater1 + action 0 + 8470 : 1 +state 8471 deadlock observe1Greater1 observeIGreater1 + action 0 + 8471 : 1 +state 8472 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8472 : 1 +state 8473 deadlock observe1Greater1 observeIGreater1 + action 0 + 8473 : 1 +state 8474 deadlock observe1Greater1 observeIGreater1 + action 0 + 8474 : 1 +state 8475 deadlock observe1Greater1 observeIGreater1 + action 0 + 8475 : 1 +state 8476 deadlock observe1Greater1 observeIGreater1 + action 0 + 8476 : 1 +state 8477 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8477 : 1 +state 8478 deadlock observe1Greater1 observeIGreater1 + action 0 + 8478 : 1 +state 8479 deadlock observe1Greater1 observeIGreater1 + action 0 + 8479 : 1 +state 8480 deadlock observe1Greater1 observeIGreater1 + action 0 + 8480 : 1 +state 8481 deadlock observe1Greater1 observeIGreater1 + action 0 + 8481 : 1 +state 8482 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8482 : 1 +state 8483 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8483 : 1 +state 8484 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8484 : 1 +state 8485 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8485 : 1 +state 8486 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8486 : 1 +state 8487 deadlock observe1Greater1 observeIGreater1 + action 0 + 8487 : 1 +state 8488 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8488 : 1 +state 8489 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8489 : 1 +state 8490 deadlock observe1Greater1 observeIGreater1 + action 0 + 8490 : 1 +state 8491 deadlock observe1Greater1 observeIGreater1 + action 0 + 8491 : 1 +state 8492 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8492 : 1 +state 8493 deadlock observe1Greater1 observeIGreater1 + action 0 + 8493 : 1 +state 8494 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8494 : 1 +state 8495 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8495 : 1 +state 8496 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8496 : 1 +state 8497 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8497 : 1 +state 8498 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8498 : 1 +state 8499 deadlock observe1Greater1 observeIGreater1 + action 0 + 8499 : 1 +state 8500 deadlock observe1Greater1 observeIGreater1 + action 0 + 8500 : 1 +state 8501 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8501 : 1 +state 8502 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8502 : 1 +state 8503 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8503 : 1 +state 8504 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8504 : 1 +state 8505 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8505 : 1 +state 8506 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8506 : 1 +state 8507 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8507 : 1 +state 8508 deadlock observe2Greater1 observeIGreater1 + action 0 + 8508 : 1 +state 8509 deadlock observe2Greater1 observeIGreater1 + action 0 + 8509 : 1 +state 8510 deadlock observe2Greater1 observeIGreater1 + action 0 + 8510 : 1 +state 8511 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8511 : 1 +state 8512 deadlock observe2Greater1 observeIGreater1 + action 0 + 8512 : 1 +state 8513 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8513 : 1 +state 8514 deadlock observe2Greater1 observeIGreater1 + action 0 + 8514 : 1 +state 8515 deadlock observe1Greater1 observe2Greater1 observeIGreater1 + action 0 + 8515 : 1 +state 8516 deadlock observe2Greater1 observeIGreater1 + action 0 + 8516 : 1 +state 8517 deadlock observe2Greater1 observeIGreater1 + action 0 + 8517 : 1 +state 8518 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8518 : 1 +state 8519 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8519 : 1 +state 8520 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8520 : 1 +state 8521 deadlock observe3Greater1 observeIGreater1 + action 0 + 8521 : 1 +state 8522 deadlock observe3Greater1 observeIGreater1 + action 0 + 8522 : 1 +state 8523 deadlock observe1Greater1 observeIGreater1 + action 0 + 8523 : 1 +state 8524 deadlock observe2Greater1 observeIGreater1 + action 0 + 8524 : 1 +state 8525 deadlock observe3Greater1 observeIGreater1 + action 0 + 8525 : 1 +state 8526 deadlock observe4Greater1 observeIGreater1 + action 0 + 8526 : 1 +state 8527 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8527 : 1 +state 8528 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8528 : 1 +state 8529 deadlock observe4Greater1 observeIGreater1 + action 0 + 8529 : 1 +state 8530 deadlock observe4Greater1 observeIGreater1 + action 0 + 8530 : 1 +state 8531 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8531 : 1 +state 8532 deadlock observe3Greater1 observeIGreater1 + action 0 + 8532 : 1 +state 8533 deadlock observe3Greater1 observeIGreater1 + action 0 + 8533 : 1 +state 8534 deadlock observe3Greater1 observeIGreater1 + action 0 + 8534 : 1 +state 8535 deadlock observe1Greater1 observe3Greater1 observeIGreater1 + action 0 + 8535 : 1 +state 8536 deadlock observe3Greater1 observeIGreater1 + action 0 + 8536 : 1 +state 8537 deadlock observe3Greater1 observeIGreater1 + action 0 + 8537 : 1 +state 8538 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8538 : 1 +state 8539 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8539 : 1 +state 8540 deadlock observe4Greater1 observeIGreater1 + action 0 + 8540 : 1 +state 8541 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8541 : 1 +state 8542 deadlock observe4Greater1 observeIGreater1 + action 0 + 8542 : 1 +state 8543 deadlock observe1Greater1 observe4Greater1 observeIGreater1 + action 0 + 8543 : 1 +state 8544 deadlock observe4Greater1 observeIGreater1 + action 0 + 8544 : 1 +state 8545 deadlock observe4Greater1 observeIGreater1 + action 0 + 8545 : 1 +state 8546 deadlock observe4Greater1 observeIGreater1 + action 0 + 8546 : 1 +state 8547 deadlock observe2Greater1 observeIGreater1 + action 0 + 8547 : 1 +state 8548 deadlock observe2Greater1 observeIGreater1 + action 0 + 8548 : 1 +state 8549 deadlock observe2Greater1 observeIGreater1 + action 0 + 8549 : 1 +state 8550 deadlock observe2Greater1 observeIGreater1 + action 0 + 8550 : 1 +state 8551 deadlock observe2Greater1 observeIGreater1 + action 0 + 8551 : 1 +state 8552 deadlock observe2Greater1 observeIGreater1 + action 0 + 8552 : 1 +state 8553 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8553 : 1 +state 8554 deadlock observe2Greater1 observeIGreater1 + action 0 + 8554 : 1 +state 8555 deadlock observe2Greater1 observeIGreater1 + action 0 + 8555 : 1 +state 8556 deadlock observe2Greater1 observeIGreater1 + action 0 + 8556 : 1 +state 8557 deadlock observe2Greater1 observeIGreater1 + action 0 + 8557 : 1 +state 8558 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8558 : 1 +state 8559 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8559 : 1 +state 8560 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8560 : 1 +state 8561 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8561 : 1 +state 8562 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8562 : 1 +state 8563 deadlock observe2Greater1 observeIGreater1 + action 0 + 8563 : 1 +state 8564 deadlock observe2Greater1 observeIGreater1 + action 0 + 8564 : 1 +state 8565 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8565 : 1 +state 8566 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8566 : 1 +state 8567 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8567 : 1 +state 8568 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8568 : 1 +state 8569 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8569 : 1 +state 8570 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8570 : 1 +state 8571 deadlock observe3Greater1 observeIGreater1 + action 0 + 8571 : 1 +state 8572 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8572 : 1 +state 8573 deadlock observe3Greater1 observeIGreater1 + action 0 + 8573 : 1 +state 8574 deadlock observe3Greater1 observeIGreater1 + action 0 + 8574 : 1 +state 8575 deadlock observe3Greater1 observeIGreater1 + action 0 + 8575 : 1 +state 8576 deadlock observe2Greater1 observe3Greater1 observeIGreater1 + action 0 + 8576 : 1 +state 8577 deadlock observe3Greater1 observeIGreater1 + action 0 + 8577 : 1 +state 8578 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8578 : 1 +state 8579 deadlock observe4Greater1 observeIGreater1 + action 0 + 8579 : 1 +state 8580 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8580 : 1 +state 8581 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8581 : 1 +state 8582 deadlock observe4Greater1 observeIGreater1 + action 0 + 8582 : 1 +state 8583 deadlock observe4Greater1 observeIGreater1 + action 0 + 8583 : 1 +state 8584 deadlock observe2Greater1 observe4Greater1 observeIGreater1 + action 0 + 8584 : 1 +state 8585 deadlock observe4Greater1 observeIGreater1 + action 0 + 8585 : 1 +state 8586 deadlock observe4Greater1 observeIGreater1 + action 0 + 8586 : 1 +state 8587 deadlock observe3Greater1 observeIGreater1 + action 0 + 8587 : 1 +state 8588 deadlock observe3Greater1 observeIGreater1 + action 0 + 8588 : 1 +state 8589 deadlock observe3Greater1 observeIGreater1 + action 0 + 8589 : 1 +state 8590 deadlock observe3Greater1 observeIGreater1 + action 0 + 8590 : 1 +state 8591 deadlock observe3Greater1 observeIGreater1 + action 0 + 8591 : 1 +state 8592 deadlock observe3Greater1 observeIGreater1 + action 0 + 8592 : 1 +state 8593 deadlock observe3Greater1 observeIGreater1 + action 0 + 8593 : 1 +state 8594 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8594 : 1 +state 8595 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8595 : 1 +state 8596 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8596 : 1 +state 8597 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8597 : 1 +state 8598 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8598 : 1 +state 8599 deadlock observe4Greater1 observeIGreater1 + action 0 + 8599 : 1 +state 8600 deadlock observe4Greater1 observeIGreater1 + action 0 + 8600 : 1 +state 8601 deadlock observe3Greater1 observe4Greater1 observeIGreater1 + action 0 + 8601 : 1 +state 8602 deadlock observe4Greater1 observeIGreater1 + action 0 + 8602 : 1 +state 8603 deadlock observe4Greater1 observeIGreater1 + action 0 + 8603 : 1 +state 8604 deadlock observe4Greater1 observeIGreater1 + action 0 + 8604 : 1 +state 8605 deadlock observe4Greater1 observeIGreater1 + action 0 + 8605 : 1 +state 8606 deadlock observe4Greater1 observeIGreater1 + action 0 + 8606 : 1 diff --git a/resources/examples/testfiles/ma/jobscheduler.drn b/resources/examples/testfiles/ma/jobscheduler.drn new file mode 100644 index 000000000..6f2e61a39 --- /dev/null +++ b/resources/examples/testfiles/ma/jobscheduler.drn @@ -0,0 +1,71 @@ +// Exported by storm +// Original model type: Markov Automaton +@type: Markov Automaton +@parameters + +@reward_models +avg_waiting_time +@nr_states +17 +@model +state 0 !0 [1] init + action 0 [0] + 1 : 1 + action 1 [0] + 2 : 1 + action 2 [0] + 3 : 1 +state 1 !3 [1] + action 0 [0] + 4 : 0.333333 + 5 : 0.666667 +state 2 !4 [1] + action 0 [0] + 4 : 0.25 + 6 : 0.75 +state 3 !5 [1] + action 0 [0] + 5 : 0.4 + 6 : 0.6 +state 4 !0 [0.666667] one_job_finished slowest_before_fastest + action 0 [0] + 7 : 1 +state 5 !0 [0.666667] one_job_finished + action 0 [0] + 8 : 1 +state 6 !0 [0.666667] one_job_finished + action 0 [0] + 9 : 1 +state 7 !5 [0.666667] one_job_finished slowest_before_fastest + action 0 [0] + 10 : 0.4 + 11 : 0.6 +state 8 !4 [0.666667] one_job_finished + action 0 [0] + 10 : 0.25 + 12 : 0.75 +state 9 !3 [0.666667] one_job_finished + action 0 [0] + 11 : 0.333333 + 12 : 0.666667 +state 10 !0 [0.333333] half_of_jobs_finished slowest_before_fastest + action 0 [0] + 13 : 1 +state 11 !0 [0.333333] half_of_jobs_finished + action 0 [0] + 14 : 1 +state 12 !0 [0.333333] half_of_jobs_finished + action 0 [0] + 15 : 1 +state 13 !3 [0.333333] half_of_jobs_finished slowest_before_fastest + action 0 [0] + 16 : 1 +state 14 !2 [0.333333] half_of_jobs_finished + action 0 [0] + 16 : 1 +state 15 !1 [0.333333] half_of_jobs_finished + action 0 [0] + 16 : 1 +state 16 !1 [0] all_jobs_finished deadlock + action 0 [0] + 16 : 1 diff --git a/resources/examples/testfiles/ma/simple2.ma b/resources/examples/testfiles/ma/simple2.ma new file mode 100644 index 000000000..46fa2207b --- /dev/null +++ b/resources/examples/testfiles/ma/simple2.ma @@ -0,0 +1,42 @@ + +ma + + +module main + + s : [0..5]; // current state: + + + <> s=0 -> 4 : (s'=1) + 4 : (s'=2); + [alpha] s=1 -> 1 : (s'=0); + [beta] s=1 -> 0.3 : (s'=5) + 0.7 : (s'=1); + <> s=5 -> 1 : (s'=2); + [gamma] s=2 -> 1 : (s'=1); + [delta] s=2 -> 0.5 : (s'=2) + 0.5 : (s'=3); + <> s=3 -> 1 : (s'=4); + [lambda] s=4 -> 1 : (s'=3); + +endmodule + +rewards "rew0" + [delta] s=2 : 1; +endrewards + +rewards "rew1" + s=0 : 7; + [delta] s=2 : 1; +endrewards + + +rewards "rew2" + s=0 : 7; + [delta] s=2 : 1; + [lambda] s=4 : 100; +endrewards + +rewards "rew3" + s=0 : 7; + [delta] s=2 : 1; + [gamma] s=2 : 100; + [lambda] s=4 : 27; +endrewards diff --git a/resources/examples/testfiles/mdp/prism-mec-example1.nm b/resources/examples/testfiles/mdp/prism-mec-example1.nm new file mode 100644 index 000000000..bb8ec7d17 --- /dev/null +++ b/resources/examples/testfiles/mdp/prism-mec-example1.nm @@ -0,0 +1,12 @@ +mdp + +module test + + x : [0..2]; + + [] x=0 -> true; + [] x=0 -> 0.5 : (x'=1) + 0.5: (x'=2); + [] x=1 -> (x'=0); + [] x=2 -> true; + +endmodule diff --git a/resources/examples/testfiles/mdp/prism-mec-example2.nm b/resources/examples/testfiles/mdp/prism-mec-example2.nm new file mode 100644 index 000000000..7ef54d4b2 --- /dev/null +++ b/resources/examples/testfiles/mdp/prism-mec-example2.nm @@ -0,0 +1,13 @@ +mdp + +module test + + x : [0..2]; + + [] x=0 -> true; + [] x=0 -> 0.5 : (x'=1) + 0.5: (x'=1); + [] x=0 -> (x'=2); + [] x=1 -> (x'=0); + [] x=2 -> true; + +endmodule diff --git a/resources/examples/testfiles/mdp/two_dice.drn b/resources/examples/testfiles/mdp/two_dice.drn index 74d13d03b..7e88bc459 100644 --- a/resources/examples/testfiles/mdp/two_dice.drn +++ b/resources/examples/testfiles/mdp/two_dice.drn @@ -3,6 +3,8 @@ @type: MDP @parameters +@reward_models +coinflips @nr_states 169 @model diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef985f4e3..70fad6710 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) add_custom_target(binaries) add_subdirectory(storm) +add_subdirectory(storm-counterexamples) +add_subdirectory(storm-parsers) add_subdirectory(storm-cli-utilities) add_subdirectory(storm-pgcl) add_subdirectory(storm-pgcl-cli) @@ -17,6 +19,8 @@ add_subdirectory(storm-pars-cli) add_subdirectory(storm-pomdp) add_subdirectory(storm-pomdp-cli) +add_subdirectory(storm-conv) +add_subdirectory(storm-conv-cli) add_subdirectory(test) diff --git a/src/storm-cli-utilities/CMakeLists.txt b/src/storm-cli-utilities/CMakeLists.txt index 64c2848c7..de4c0fde1 100644 --- a/src/storm-cli-utilities/CMakeLists.txt +++ b/src/storm-cli-utilities/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-cli-utilities PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-cli-utilities) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-cli-utilities PUBLIC storm) +target_link_libraries(storm-cli-utilities PUBLIC storm storm-counterexamples storm-parsers) # Install storm headers to include directory. foreach(HEADER ${STORM_CLI_UTIL_HEADERS}) @@ -36,5 +36,5 @@ add_custom_target(copy_storm_cli_util_headers DEPENDS ${STORM_CLI_UTIL_OUTPUT_HE add_dependencies(storm-cli-utilities copy_storm_pars_headers) # installation -install(TARGETS storm-cli-utilities RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-cli-utilities EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-cli-utilities/cli.cpp b/src/storm-cli-utilities/cli.cpp index dfc3065b8..e79971cbc 100644 --- a/src/storm-cli-utilities/cli.cpp +++ b/src/storm-cli-utilities/cli.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "storm-cli-utilities/model-handling.h" @@ -48,6 +49,8 @@ namespace storm { storm::cli::printHeader("Storm", argc, argv); storm::settings::initializeAll("Storm", "storm"); + storm::settings::addModule(); + storm::utility::Stopwatch totalTimer(true); if (!storm::cli::parseOptions(argc, argv)) { return -1; @@ -63,7 +66,27 @@ namespace storm { storm::utility::cleanUp(); return 0; } - + + std::string shellQuoteSingleIfNecessary(const std::string& arg) { + // quote empty argument + if (arg.empty()) { + return "''"; + } + + if (arg.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./=") != std::string::npos) { + // contains potentially unsafe character, needs quoting + if (arg.find('\'') != std::string::npos) { + // contains ', we have to replace all ' with '\'' + std::string escaped(arg); + boost::replace_all(escaped, "'", "'\\''"); + return "'" + escaped + "'"; + } else { + return "'" + arg + "'"; + } + } + + return arg; + } void printHeader(std::string const& name, const int argc, const char** argv) { STORM_PRINT(name << " " << storm::utility::StormVersion::shortVersionString() << std::endl << std::endl); @@ -71,7 +94,7 @@ namespace storm { // "Compute" the command line argument string with which storm was invoked. std::stringstream commandStream; for (int i = 1; i < argc; ++i) { - commandStream << argv[i] << " "; + commandStream << " " << shellQuoteSingleIfNecessary(argv[i]); } std::string command = commandStream.str(); @@ -79,7 +102,7 @@ namespace storm { if (!command.empty()) { std::time_t result = std::time(nullptr); STORM_PRINT("Date: " << std::ctime(&result)); - STORM_PRINT("Command line arguments: " << commandStream.str() << std::endl); + STORM_PRINT("Command line arguments:" << commandStream.str() << std::endl); STORM_PRINT("Current working directory: " << storm::utility::cli::getCurrentWorkingDirectory() << std::endl << std::endl); } } diff --git a/src/storm-cli-utilities/cli.h b/src/storm-cli-utilities/cli.h index e8d8601e9..66c51bad6 100644 --- a/src/storm-cli-utilities/cli.h +++ b/src/storm-cli-utilities/cli.h @@ -11,6 +11,13 @@ namespace storm { */ int64_t process(const int argc, const char** argv); + /*! + * For a command-line argument, returns a quoted version + * with single quotes if it contains unsafe characters. + * Otherwise, just returns the unquoted argument. + */ + std::string shellQuoteSingleIfNecessary(const std::string& arg); + void printHeader(std::string const& name, const int argc, const char** argv); void printVersion(std::string const& name); diff --git a/src/storm-cli-utilities/model-handling.h b/src/storm-cli-utilities/model-handling.h index bdc1ee630..1229eef8f 100644 --- a/src/storm-cli-utilities/model-handling.h +++ b/src/storm-cli-utilities/model-handling.h @@ -2,10 +2,14 @@ #include "storm/api/storm.h" +#include "storm-counterexamples/api/counterexamples.h" +#include "storm-parsers/api/storm-parsers.h" + #include "storm/utility/resources.h" #include "storm/utility/file.h" #include "storm/utility/storm-version.h" #include "storm/utility/macros.h" +#include "storm/utility/NumberTraits.h" #include "storm/utility/initialize.h" #include "storm/utility/Stopwatch.h" @@ -14,6 +18,9 @@ #include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/Property.h" + +#include "storm/builder/BuilderType.h" #include "storm/models/ModelBase.h" @@ -34,7 +41,6 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/AbstractionSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/utility/Stopwatch.h" @@ -53,21 +59,26 @@ namespace storm { boost::optional> preprocessedProperties; }; - void parseSymbolicModelDescription(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input) { + void parseSymbolicModelDescription(storm::settings::modules::IOSettings const& ioSettings, SymbolicInput& input, storm::builder::BuilderType const& builderType) { if (ioSettings.isPrismOrJaniInputSet()) { if (ioSettings.isPrismInputSet()) { input.model = storm::api::parseProgram(ioSettings.getPrismInputFilename(), storm::settings::getModule().isPrismCompatibilityEnabled()); } else { - auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename()); - input.model = janiInput.first; - auto const& janiPropertyInput = janiInput.second; - + storm::jani::ModelFeatures supportedFeatures = storm::api::getSupportedJaniFeatures(builderType); + boost::optional> propertyFilter; if (ioSettings.isJaniPropertiesSet()) { - for (auto const& propName : ioSettings.getJaniProperties()) { - auto propertyIt = janiPropertyInput.find(propName); - STORM_LOG_THROW(propertyIt != janiPropertyInput.end(), storm::exceptions::InvalidArgumentException, "No JANI property with name '" << propName << "' is known."); - input.properties.emplace_back(propertyIt->second); + if (ioSettings.areJaniPropertiesSelected()) { + propertyFilter = ioSettings.getSelectedJaniProperties(); + } else { + propertyFilter = boost::none; } + } else { + propertyFilter = std::vector(); + } + auto janiInput = storm::api::parseJaniModel(ioSettings.getJaniInputFilename(), supportedFeatures, propertyFilter); + input.model = std::move(janiInput.first); + if (ioSettings.isJaniPropertiesSet()) { + input.properties = std::move(janiInput.second); } } } @@ -86,23 +97,21 @@ namespace storm { } } - SymbolicInput parseSymbolicInput() { + SymbolicInput parseSymbolicInput(storm::builder::BuilderType const& builderType) { auto ioSettings = storm::settings::getModule(); // Parse the property filter, if any is given. boost::optional> propertyFilter = storm::api::parsePropertyFilter(ioSettings.getPropertyFilter()); SymbolicInput input; - parseSymbolicModelDescription(ioSettings, input); + parseSymbolicModelDescription(ioSettings, input, builderType); parseProperties(ioSettings, input, propertyFilter); return input; } - SymbolicInput preprocessSymbolicInput(SymbolicInput const& input) { + SymbolicInput preprocessSymbolicInput(SymbolicInput const& input, storm::builder::BuilderType const& builderType) { auto ioSettings = storm::settings::getModule(); - auto buildSettings = storm::settings::getModule(); - auto coreSettings = storm::settings::getModule(); SymbolicInput output = input; @@ -117,25 +126,33 @@ namespace storm { output.properties = storm::api::substituteConstantsInProperties(output.properties, constantDefinitions); } + // Make sure there are no undefined constants remaining in any property. + for (auto const& property : output.properties) { + std::set usedUndefinedConstants = property.getUndefinedConstants(); + if (!usedUndefinedConstants.empty()) { + std::vector undefinedConstantsNames; + for (auto const& constant : usedUndefinedConstants) { + undefinedConstantsNames.emplace_back(constant.getName()); + } + + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The property '" << property << " still refers to the undefined constants " << boost::algorithm::join(undefinedConstantsNames, ",") << "."); + } + } + // Check whether conversion for PRISM to JANI is requested or necessary. if (input.model && input.model.get().isPrismProgram()) { bool transformToJani = ioSettings.isPrismToJaniSet(); - bool transformToJaniForJit = coreSettings.getEngine() == storm::settings::modules::CoreSettings::Engine::Sparse && buildSettings.isJitSet(); + bool transformToJaniForJit = builderType == storm::builder::BuilderType::Jit; STORM_LOG_WARN_COND(transformToJani || !transformToJaniForJit, "The JIT-based model builder is only available for JANI models, automatically converting the PRISM input model."); transformToJani |= transformToJaniForJit; if (transformToJani) { storm::prism::Program const& model = output.model.get().asPrismProgram(); - auto modelAndRenaming = model.toJaniWithLabelRenaming(true); - output.model = modelAndRenaming.first; + auto modelAndProperties = model.toJani(output.properties); + output.model = modelAndProperties.first; - if (!modelAndRenaming.second.empty()) { - std::map const& labelRenaming = modelAndRenaming.second; - std::vector amendedProperties; - for (auto const& property : output.properties) { - amendedProperties.emplace_back(property.substituteLabels(labelRenaming)); - } - output.preprocessedProperties = std::move(amendedProperties); + if (!modelAndProperties.second.empty()) { + output.preprocessedProperties = std::move(modelAndProperties.second); } } } @@ -150,16 +167,32 @@ namespace storm { if (ioSettings.isExportJaniDotSet()) { storm::api::exportJaniModelAsDot(model.asJaniModel(), ioSettings.getExportJaniDotFilename()); } - - if (model.isJaniModel() && storm::settings::getModule().isJaniFileSet()) { - storm::api::exportJaniModel(model.asJaniModel(), input.properties, storm::settings::getModule().getJaniFilename()); + } + } + + storm::builder::BuilderType getBuilderType(storm::settings::modules::CoreSettings::Engine const& engine, bool useJit) { + if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::DdSparse || engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) { + return storm::builder::BuilderType::Dd; + } else if (engine == storm::settings::modules::CoreSettings::Engine::Sparse) { + if (useJit) { + return storm::builder::BuilderType::Jit; + } else { + return storm::builder::BuilderType::Explicit; } + } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { + return storm::builder::BuilderType::Explicit; } + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unable to determine the model builder type."); } SymbolicInput parseAndPreprocessSymbolicInput() { - SymbolicInput input = parseSymbolicInput(); - input = preprocessSymbolicInput(input); + // Get the used builder type to handle cases where preprocessing depends on it + auto buildSettings = storm::settings::getModule(); + auto coreSettings = storm::settings::getModule(); + auto builderType = getBuilderType(coreSettings.getEngine(), buildSettings.isJitSet()); + + SymbolicInput input = parseSymbolicInput(builderType); + input = preprocessSymbolicInput(input, builderType); exportSymbolicInput(input); return input; } @@ -183,13 +216,18 @@ namespace storm { template std::shared_ptr buildModelSparse(SymbolicInput const& input, storm::settings::modules::BuildSettings const& buildSettings) { - auto counterexampleGeneratorSettings = storm::settings::getModule(); storm::builder::BuilderOptions options(createFormulasToRespect(input.properties)); options.setBuildChoiceLabels(buildSettings.isBuildChoiceLabelsSet()); options.setBuildStateValuations(buildSettings.isBuildStateValuationsSet()); - options.setBuildChoiceOrigins(counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet()); + if (storm::settings::manager().hasModule(storm::settings::modules::CounterexampleGeneratorSettings::moduleName)) { + auto counterexampleGeneratorSettings = storm::settings::getModule(); + options.setBuildChoiceOrigins(counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet()); + } else { + options.setBuildChoiceOrigins(false); + } options.setBuildAllLabels(buildSettings.isBuildFullModelSet()); options.setBuildAllRewardModels(buildSettings.isBuildFullModelSet()); + options.setAddOutOfBoundsState(buildSettings.isBuildOutOfBoundsStateSet()); if (buildSettings.isBuildFullModelSet()) { options.clearTerminalStates(); } @@ -217,9 +255,10 @@ namespace storm { auto buildSettings = storm::settings::getModule(); std::shared_ptr result; if (input.model) { - if (engine == storm::settings::modules::CoreSettings::Engine::Dd || engine == storm::settings::modules::CoreSettings::Engine::Hybrid || engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement) { + auto builderType = getBuilderType(engine, buildSettings.isJitSet()); + if (builderType == storm::builder::BuilderType::Dd) { result = buildModelDd(input); - } else if (engine == storm::settings::modules::CoreSettings::Engine::Sparse) { + } else if (builderType == storm::builder::BuilderType::Explicit || builderType == storm::builder::BuilderType::Jit) { result = buildModelSparse(input, buildSettings); } } else if (ioSettings.isExplicitSet() || ioSettings.isExplicitDRNSet() || ioSettings.isExplicitIMCASet()) { @@ -322,43 +361,60 @@ namespace storm { } } - template - std::shared_ptr> preprocessDdModelBisimulation(std::shared_ptr> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { + template + std::shared_ptr> preprocessDdModelBisimulation(std::shared_ptr> const& model, SymbolicInput const& input, storm::settings::modules::BisimulationSettings const& bisimulationSettings) { STORM_LOG_WARN_COND(!bisimulationSettings.isWeakBisimulationSet(), "Weak bisimulation is currently not supported on DDs. Falling back to strong bisimulation."); STORM_LOG_INFO("Performing bisimulation minimization..."); - return storm::api::performBisimulationMinimization(model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode()); + return storm::api::performBisimulationMinimization(model, createFormulasToRespect(input.properties), storm::storage::BisimulationType::Strong, bisimulationSettings.getSignatureMode()); } - template + template std::pair, bool> preprocessDdModel(std::shared_ptr> const& model, SymbolicInput const& input) { auto bisimulationSettings = storm::settings::getModule(); auto generalSettings = storm::settings::getModule(); - std::pair>, bool> result = std::make_pair(model, false); + std::pair>, bool> intermediateResult = std::make_pair(model, false); if (model->isOfType(storm::models::ModelType::MarkovAutomaton)) { - result.first = preprocessDdMarkovAutomaton(result.first->template as>()); - result.second = true; + intermediateResult.first = preprocessDdMarkovAutomaton(intermediateResult.first->template as>()); + intermediateResult.second = true; } + std::unique_ptr>, bool>> result; + auto symbolicModel = intermediateResult.first->template as>(); if (generalSettings.isBisimulationSet()) { - result.first = preprocessDdModelBisimulation(model, input, bisimulationSettings); - result.second = true; + std::shared_ptr> newModel = preprocessDdModelBisimulation(symbolicModel, input, bisimulationSettings); + result = std::make_unique>, bool>>(newModel, true); + } else { + result = std::make_unique>, bool>>(symbolicModel->template toValueType(), !std::is_same::value); } - return result; + if (result && result->first->isSymbolicModel() && storm::settings::getModule().getEngine() == storm::settings::modules::CoreSettings::Engine::DdSparse) { + // Mark as changed. + result->second = true; + + std::shared_ptr> symbolicModel = result->first->template as>(); + std::vector> formulas; + for (auto const& property : input.properties) { + formulas.emplace_back(property.getRawFormula()); + } + result->first = storm::api::transformSymbolicToSparseModel(symbolicModel, formulas); + STORM_LOG_THROW(result, storm::exceptions::NotSupportedException, "The translation to a sparse model is not supported for the given model type."); + } + + return *result; } - template + template std::pair, bool> preprocessModel(std::shared_ptr const& model, SymbolicInput const& input) { storm::utility::Stopwatch preprocessingWatch(true); std::pair, bool> result = std::make_pair(model, false); if (model->isSparseModel()) { - result = preprocessSparseModel(result.first->as>(), input); + result = preprocessSparseModel(result.first->as>(), input); } else { STORM_LOG_ASSERT(model->isSymbolicModel(), "Unexpected model type."); - result = preprocessDdModel(result.first->as>(), input); + result = preprocessDdModel(result.first->as>(), input); } preprocessingWatch.stop(); @@ -395,7 +451,10 @@ namespace storm { STORM_LOG_THROW(model->isSparseModel(), storm::exceptions::NotSupportedException, "Counterexample generation is currently only supported for sparse models."); auto sparseModel = model->as>(); - + for (auto& rewModel : sparseModel->getRewardModels()) { + rewModel.second.reduceToStateBasedRewards(sparseModel->getTransitionMatrix(), true); + } + STORM_LOG_THROW(sparseModel->isOfType(storm::models::ModelType::Dtmc) || sparseModel->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "Counterexample is currently only supported for discrete-time models."); auto counterexampleSettings = storm::settings::getModule(); @@ -429,29 +488,38 @@ namespace storm { template void printFilteredResult(std::unique_ptr const& result, storm::modelchecker::FilterType ft) { if (result->isQuantitative()) { - switch (ft) { - case storm::modelchecker::FilterType::VALUES: - STORM_PRINT(*result); - break; - case storm::modelchecker::FilterType::SUM: - STORM_PRINT(result->asQuantitativeCheckResult().sum()); - break; - case storm::modelchecker::FilterType::AVG: - STORM_PRINT(result->asQuantitativeCheckResult().average()); - break; - case storm::modelchecker::FilterType::MIN: - STORM_PRINT(result->asQuantitativeCheckResult().getMin()); - break; - case storm::modelchecker::FilterType::MAX: - STORM_PRINT(result->asQuantitativeCheckResult().getMax()); - break; - case storm::modelchecker::FilterType::ARGMIN: - case storm::modelchecker::FilterType::ARGMAX: - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported."); - case storm::modelchecker::FilterType::EXISTS: - case storm::modelchecker::FilterType::FORALL: - case storm::modelchecker::FilterType::COUNT: - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for qualitative results."); + if (ft == storm::modelchecker::FilterType::VALUES) { + STORM_PRINT(*result); + } else { + ValueType resultValue; + switch (ft) { + case storm::modelchecker::FilterType::SUM: + resultValue = result->asQuantitativeCheckResult().sum(); + break; + case storm::modelchecker::FilterType::AVG: + resultValue = result->asQuantitativeCheckResult().average(); + break; + case storm::modelchecker::FilterType::MIN: + resultValue = result->asQuantitativeCheckResult().getMin(); + break; + case storm::modelchecker::FilterType::MAX: + resultValue = result->asQuantitativeCheckResult().getMax(); + break; + case storm::modelchecker::FilterType::ARGMIN: + case storm::modelchecker::FilterType::ARGMAX: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Outputting states is not supported."); + case storm::modelchecker::FilterType::EXISTS: + case storm::modelchecker::FilterType::FORALL: + case storm::modelchecker::FilterType::COUNT: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Filter type only defined for qualitative results."); + default: + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Unhandled filter type."); + } + if (storm::NumberTraits::IsExact && storm::utility::isConstant(resultValue)) { + STORM_PRINT(resultValue << " (approx. " << storm::utility::convertNumber(resultValue) << ")"); + } else { + STORM_PRINT(resultValue); + } } } else { switch (ft) { @@ -481,7 +549,7 @@ namespace storm { } void printModelCheckingProperty(storm::jani::Property const& property) { - STORM_PRINT(std::endl << "Model checking property " << *property.getRawFormula() << " ..." << std::endl); + STORM_PRINT(std::endl << "Model checking property \"" << property.getName() << "\": " << *property.getRawFormula() << " ..." << std::endl); } template @@ -518,12 +586,85 @@ namespace storm { } } + std::vector parseConstraints(storm::expressions::ExpressionManager const& expressionManager, std::string const& constraintsString) { + std::vector constraints; + + std::vector constraintsAsStrings; + boost::split(constraintsAsStrings, constraintsString, boost::is_any_of(",")); + + storm::parser::ExpressionParser expressionParser(expressionManager); + std::unordered_map variableMapping; + for (auto const& variableTypePair : expressionManager) { + variableMapping[variableTypePair.first.getName()] = variableTypePair.first; + } + expressionParser.setIdentifierMapping(variableMapping); + + for (auto const& constraintString : constraintsAsStrings) { + if (constraintString.empty()) { + continue; + } + + storm::expressions::Expression constraint = expressionParser.parseFromString(constraintString); + STORM_LOG_TRACE("Adding special (user-provided) constraint " << constraint << "."); + constraints.emplace_back(constraint); + } + + return constraints; + } + + std::vector> parseInjectedRefinementPredicates(storm::expressions::ExpressionManager const& expressionManager, std::string const& refinementPredicatesString) { + std::vector> injectedRefinementPredicates; + + storm::parser::ExpressionParser expressionParser(expressionManager); + std::unordered_map variableMapping; + for (auto const& variableTypePair : expressionManager) { + variableMapping[variableTypePair.first.getName()] = variableTypePair.first; + } + expressionParser.setIdentifierMapping(variableMapping); + + std::vector predicateGroupsAsStrings; + boost::split(predicateGroupsAsStrings, refinementPredicatesString, boost::is_any_of(";")); + + if (!predicateGroupsAsStrings.empty()) { + for (auto const& predicateGroupString : predicateGroupsAsStrings) { + if (predicateGroupString.empty()) { + continue; + } + + std::vector predicatesAsStrings; + boost::split(predicatesAsStrings, predicateGroupString, boost::is_any_of(":")); + + if (!predicatesAsStrings.empty()) { + injectedRefinementPredicates.emplace_back(); + for (auto const& predicateString : predicatesAsStrings) { + storm::expressions::Expression predicate = expressionParser.parseFromString(predicateString); + STORM_LOG_TRACE("Adding special (user-provided) refinement predicate " << predicateString << "."); + injectedRefinementPredicates.back().emplace_back(predicate); + } + + STORM_LOG_THROW(!injectedRefinementPredicates.back().empty(), storm::exceptions::InvalidArgumentException, "Expecting non-empty list of predicates to inject for each (mentioned) refinement step."); + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(injectedRefinementPredicates.back().begin(), injectedRefinementPredicates.back().end()); + } + } + + // Finally reverse the list, because we take the predicates from the back. + std::reverse(injectedRefinementPredicates.begin(), injectedRefinementPredicates.end()); + } + + return injectedRefinementPredicates; + } + template void verifyWithAbstractionRefinementEngine(SymbolicInput const& input) { STORM_LOG_ASSERT(input.model, "Expected symbolic model description."); - verifyProperties(input, [&input] (std::shared_ptr const& formula, std::shared_ptr const& states) { + storm::settings::modules::AbstractionSettings const& abstractionSettings = storm::settings::getModule(); + storm::api::AbstractionRefinementOptions options(parseConstraints(input.model->getManager(), abstractionSettings.getConstraintString()), parseInjectedRefinementPredicates(input.model->getManager(), abstractionSettings.getInjectedRefinementPredicates())); + + verifyProperties(input, [&input,&options] (std::shared_ptr const& formula, std::shared_ptr const& states) { STORM_LOG_THROW(states->isInitialFormula(), storm::exceptions::NotSupportedException, "Abstraction-refinement can only filter initial states."); - return storm::api::verifyWithAbstractionRefinementEngine(input.model.get(), storm::api::createTask(formula, true)); + return storm::api::verifyWithAbstractionRefinementEngine(input.model.get(), storm::api::createTask(formula, true), options); }); } @@ -639,13 +780,13 @@ namespace storm { } } - template + template std::shared_ptr buildPreprocessExportModelWithValueTypeAndDdlib(SymbolicInput const& input, storm::settings::modules::CoreSettings::Engine engine) { auto ioSettings = storm::settings::getModule(); auto buildSettings = storm::settings::getModule(); std::shared_ptr model; if (!buildSettings.isNoBuildModelSet()) { - model = buildModel(engine, input, ioSettings); + model = buildModel(engine, input, ioSettings); } if (model) { @@ -655,17 +796,17 @@ namespace storm { STORM_LOG_THROW(model || input.properties.empty(), storm::exceptions::InvalidSettingsException, "No input model."); if (model) { - auto preprocessingResult = preprocessModel(model, input); + auto preprocessingResult = preprocessModel(model, input); if (preprocessingResult.second) { model = preprocessingResult.first; model->printModelInformationToStream(std::cout); } - exportModel(model, input); + exportModel(model, input); } return model; } - template + template void processInputWithValueTypeAndDdlib(SymbolicInput const& input) { auto coreSettings = storm::settings::getModule(); auto abstractionSettings = storm::settings::getModule(); @@ -674,19 +815,19 @@ namespace storm { storm::settings::modules::CoreSettings::Engine engine = coreSettings.getEngine(); if (engine == storm::settings::modules::CoreSettings::Engine::AbstractionRefinement && abstractionSettings.getAbstractionRefinementMethod() == storm::settings::modules::AbstractionSettings::Method::Games) { - verifyWithAbstractionRefinementEngine(input); + verifyWithAbstractionRefinementEngine(input); } else if (engine == storm::settings::modules::CoreSettings::Engine::Exploration) { - verifyWithExplorationEngine(input); + verifyWithExplorationEngine(input); } else { - std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); - + std::shared_ptr model = buildPreprocessExportModelWithValueTypeAndDdlib(input, engine); + if (model) { if (coreSettings.isCounterexampleSet()) { auto ioSettings = storm::settings::getModule(); - generateCounterexamples(model, input); + generateCounterexamples(model, input); } else { auto ioSettings = storm::settings::getModule(); - verifyModel(model, input, coreSettings); + verifyModel(model, input, coreSettings); } } } @@ -696,12 +837,16 @@ namespace storm { void processInputWithValueType(SymbolicInput const& input) { auto coreSettings = storm::settings::getModule(); auto generalSettings = storm::settings::getModule(); + auto bisimulationSettings = storm::settings::getModule(); if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && generalSettings.isExactSet()) { STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); - processInputWithValueTypeAndDdlib(input); + processInputWithValueTypeAndDdlib(input); + } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD && coreSettings.isDdLibraryTypeSetFromDefaultValue() && std::is_same::value && generalSettings.isBisimulationSet() && bisimulationSettings.useExactArithmeticInDdBisimulation()) { + STORM_LOG_INFO("Switching to DD library sylvan to allow for rational arithmetic."); + processInputWithValueTypeAndDdlib(input); } else if (coreSettings.getDdLibraryType() == storm::dd::DdType::CUDD) { - processInputWithValueTypeAndDdlib(input); + processInputWithValueTypeAndDdlib(input); } else { STORM_LOG_ASSERT(coreSettings.getDdLibraryType() == storm::dd::DdType::Sylvan, "Unknown DD library."); processInputWithValueTypeAndDdlib(input); diff --git a/src/storm-conv-cli/CMakeLists.txt b/src/storm-conv-cli/CMakeLists.txt new file mode 100644 index 000000000..72a311b11 --- /dev/null +++ b/src/storm-conv-cli/CMakeLists.txt @@ -0,0 +1,9 @@ +# Create storm-conv. +add_executable(storm-conv-cli ${PROJECT_SOURCE_DIR}/src/storm-conv-cli/storm-conv.cpp) +target_link_libraries(storm-conv-cli storm-conv storm-cli-utilities) # Adding headers for xcode +set_target_properties(storm-conv-cli PROPERTIES OUTPUT_NAME "storm-conv") + +add_dependencies(binaries storm-conv-cli) + +# installation +install(TARGETS storm-conv-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-conv-cli/storm-conv.cpp b/src/storm-conv-cli/storm-conv.cpp new file mode 100644 index 000000000..d60895eff --- /dev/null +++ b/src/storm-conv-cli/storm-conv.cpp @@ -0,0 +1,341 @@ + +#include "storm-conv/api/storm-conv.h" + +#include "storm/settings/SettingsManager.h" +#include "storm-conv/settings/ConvSettings.h" +#include "storm-conv/settings/modules/ConversionGeneralSettings.h" +#include "storm-conv/settings/modules/ConversionInputSettings.h" +#include "storm-conv/settings/modules/ConversionOutputSettings.h" + +#include "storm/api/storm.h" +#include "storm-parsers/api/storm-parsers.h" +#include "storm/utility/initialize.h" +#include "storm/utility/macros.h" +#include "storm/utility/Stopwatch.h" + +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + + +#include "storm-cli-utilities/cli.h" +#include "storm/exceptions/OptionParserException.h" + +namespace storm { + namespace conv { + + void setUrgentOptions() { + + // Set the correct log level + if (storm::settings::getModule().isStdOutOutputEnabled()) { + storm::utility::setLogLevel(l3pp::LogLevel::OFF); + } else { + auto const& general = storm::settings::getModule(); + if (general.isVerboseSet()) { + storm::utility::setLogLevel(l3pp::LogLevel::INFO); + } + if (general.isDebugOutputSet()) { + storm::utility::setLogLevel(l3pp::LogLevel::DEBUG); + } + if (general.isTraceOutputSet()) { + storm::utility::setLogLevel(l3pp::LogLevel::TRACE); + } + } + } + + storm::utility::Stopwatch startStopwatch(std::string const& message) { + STORM_PRINT_AND_LOG(message); + return storm::utility::Stopwatch(true); + } + + void stopStopwatch(storm::utility::Stopwatch& stopWatch) { + stopWatch.stop(); + STORM_PRINT_AND_LOG(" done. (" << stopWatch << " seconds)." << std::endl); + } + + void processPrismInputJaniOutput(storm::prism::Program const& prismProg, std::vector const& properties) { + auto const& output = storm::settings::getModule(); + auto const& input = storm::settings::getModule(); + auto const& jani = storm::settings::getModule(); + + auto conversionTime = startStopwatch("Converting PRISM Program to JANI model ... " ); + + storm::converter::PrismToJaniConverterOptions options; + options.allVariablesGlobal = jani.isGlobalVarsSet(); + options.suffix = ""; + options.janiOptions = storm::converter::JaniConversionOptions(jani); + options.janiOptions.substituteConstants = true; + + // Get the name of the output file + std::string outputFilename = ""; + if (output.isJaniOutputFilenameSet()) { + outputFilename = output.getJaniOutputFilename(); + } else if (input.isPrismInputSet() && !output.isStdOutOutputEnabled()) { + outputFilename = input.getPrismInputFilename(); + // Remove extension if present + auto dotPos = outputFilename.rfind('.'); + if (dotPos != std::string::npos) { + outputFilename.erase(dotPos); + } + std::string suffix = ""; + if (input.isConstantsSet()) { + suffix = input.getConstantDefinitionString(); + std::replace(suffix.begin(), suffix.end(), ',', '_'); + std::replace(suffix.begin(), suffix.end(), '=', '-'); + } + suffix = suffix + ".jani"; + outputFilename += suffix; + } + + // Find a good model name + auto startOfFilename = outputFilename.rfind("/"); + if (startOfFilename == std::string::npos) { + startOfFilename = 0; + } else { + ++startOfFilename; + } + auto endOfFilename = outputFilename.rfind("."); + if (endOfFilename == std::string::npos) { + endOfFilename = outputFilename.size(); + } + options.janiOptions.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename); + + + auto janiModelProperties = storm::api::convertPrismToJani(prismProg, properties, options); + + stopStopwatch(conversionTime); + auto exportingTime = startStopwatch("Exporting JANI model ... "); + + if (outputFilename != "") { + storm::api::exportJaniToFile(janiModelProperties.first, janiModelProperties.second, outputFilename, jani.isCompactJsonSet()); + STORM_PRINT_AND_LOG("Stored to file '" << outputFilename << "'"); + } + + if (output.isStdOutOutputEnabled()) { + storm::api::printJaniToStream(janiModelProperties.first, janiModelProperties.second, std::cout, jani.isCompactJsonSet()); + } + stopStopwatch(exportingTime); + } + + void processPrismInput() { + auto parsingTime = startStopwatch("Parsing PRISM input ... " ); + + auto const& input = storm::settings::getModule(); + + // Parse the prism program + storm::storage::SymbolicModelDescription prismProg = storm::api::parseProgram(input.getPrismInputFilename(), input.isPrismCompatibilityEnabled(), false); + + // Parse properties (if available) + std::vector properties; + if (input.isPropertyInputSet()) { + boost::optional> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter()); + properties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), prismProg, propertyFilter); + } + + // Set constant definitions in program + std::string constantDefinitionString = input.getConstantDefinitionString(); + auto constantDefinitions = prismProg.parseConstantDefinitions(constantDefinitionString); + prismProg = storm::storage::SymbolicModelDescription(prismProg.asPrismProgram().defineUndefinedConstants(constantDefinitions)); + // Substitution of constants can only be done after conversion in order to preserve formula definitions in which + // constants appear that are renamed in some modules... + + stopStopwatch(parsingTime); + + // Branch on the type of output + auto const& output = storm::settings::getModule(); + if (output.isJaniOutputSet()) { + processPrismInputJaniOutput(prismProg.asPrismProgram(), properties); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible."); + } + } + + void processJaniInputJaniOutput(storm::jani::Model const& janiModel, std::vector const& properties) { + auto conversionTime = startStopwatch("Performing transformations on JANI model ... " ); + + auto const& output = storm::settings::getModule(); + auto const& input = storm::settings::getModule(); + auto const& jani = storm::settings::getModule(); + + storm::converter::JaniConversionOptions options(jani); + + // Get the name of the output file + std::string outputFilename = ""; + if (output.isJaniOutputFilenameSet()) { + outputFilename = output.getJaniOutputFilename(); + } else if (input.isJaniInputSet() && !output.isStdOutOutputEnabled()) { + outputFilename = input.getJaniInputFilename(); + // Remove extension if present + auto dotPos = outputFilename.rfind('.'); + if (dotPos != std::string::npos) { + outputFilename.erase(dotPos); + } + outputFilename += "_converted.jani"; + } + + // Get a good model name from the output filename + auto startOfFilename = outputFilename.rfind("/"); + if (startOfFilename == std::string::npos) { + startOfFilename = 0; + } else { + ++startOfFilename; + } + auto endOfFilename = outputFilename.rfind("."); + if (endOfFilename == std::string::npos) { + endOfFilename = outputFilename.size(); + } + options.modelName = outputFilename.substr(startOfFilename, endOfFilename - startOfFilename); + + auto transformedJaniModel = janiModel; + auto transformedProperties = properties; + storm::api::transformJani(transformedJaniModel, transformedProperties, options); + + stopStopwatch(conversionTime); + auto exportingTime = startStopwatch("Exporting JANI model ... "); + + if (outputFilename != "") { + storm::api::exportJaniToFile(transformedJaniModel, transformedProperties, outputFilename, jani.isCompactJsonSet()); + STORM_PRINT_AND_LOG("Stored to file '" << outputFilename << "'"); + } + + if (output.isStdOutOutputEnabled()) { + storm::api::printJaniToStream(transformedJaniModel, transformedProperties, std::cout, jani.isCompactJsonSet()); + } + stopStopwatch(exportingTime); + } + + void processJaniInput() { + auto parsingTime = startStopwatch("Parsing JANI input ... " ); + + auto const& input = storm::settings::getModule(); + + // Parse the jani model and selected properties + boost::optional> janiPropertyFilter; + if (input.isJaniPropertiesSet()) { + if (input.areJaniPropertiesSelected()) { + janiPropertyFilter = input.getSelectedJaniProperties(); + } else { + janiPropertyFilter = boost::none; + } + } else { + if (input.isPropertyInputSet()) { + janiPropertyFilter = std::vector(); + } else { + // If no properties are selected, take the ones from the jani file. + janiPropertyFilter = boost::none; + } + } + auto janiModelProperties = storm::api::parseJaniModel(input.getJaniInputFilename(), storm::jani::getAllKnownModelFeatures(), janiPropertyFilter); + + // Parse additional properties given from command line + std::vector properties = std::move(janiModelProperties.second); + if (input.isPropertyInputSet()) { + boost::optional> propertyFilter = storm::api::parsePropertyFilter(input.getPropertyInputFilter()); + auto additionalProperties = storm::api::parsePropertiesForSymbolicModelDescription(input.getPropertyInput(), janiModelProperties.first, propertyFilter); + properties.insert(properties.end(), additionalProperties.begin(), additionalProperties.end()); + } + + storm::storage::SymbolicModelDescription symbDescr(janiModelProperties.first); + + // Substitute constant definitions in model and properties. + std::string constantDefinitionString = input.getConstantDefinitionString(); + auto constantDefinitions = symbDescr.parseConstantDefinitions(constantDefinitionString); + auto janiModel = janiModelProperties.first.defineUndefinedConstants(constantDefinitions).substituteConstants(); + if (!properties.empty()) { + properties = storm::api::substituteConstantsInProperties(properties, constantDefinitions); + } + stopStopwatch(parsingTime); + + // Branch on the type of output + auto const& output = storm::settings::getModule(); + if (output.isJaniOutputSet()) { + processJaniInputJaniOutput(janiModel, properties); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "There is either no outputformat specified or the provided combination of input and output format is not compatible."); + } + } + + void processOptions() { + // Start by setting some urgent options (log levels, etc.) + setUrgentOptions(); + + // Branch on the type of input + auto const& input = storm::settings::getModule(); + STORM_LOG_THROW(!(input.isPrismInputSet() && input.isJaniInputSet()), storm::exceptions::InvalidSettingsException, "Multiple input options were set."); + if (input.isPrismInputSet()) { + processPrismInput(); + } else if (input.isJaniInputSet()) { + processJaniInput(); + } + } + } +} + +bool parseOptions(const int argc, const char* argv[]) { + try { + storm::settings::mutableManager().setFromCommandLine(argc, argv); + } catch (storm::exceptions::OptionParserException& e) { + storm::settings::manager().printHelp(); + throw e; + return false; + } + + auto const& general = storm::settings::getModule(); + + // Set options from config file (if given) + if (general.isConfigSet()) { + storm::settings::mutableManager().setFromConfigurationFile(general.getConfigFilename()); + } + + bool result = true; + if (general.isHelpSet()) { + storm::settings::manager().printHelp(general.getHelpModuleName()); + result = false; + } + + if (general.isVersionSet()) { + storm::cli::printVersion("storm-conv"); + result = false;; + } + + return result; +} + +/*! + * Main entry point of the executable storm-conv. + */ +int main(const int argc, const char** argv) { + + try { + storm::utility::setUp(); + + // Print header info only if output to sdtout is disabled + bool outputToStdOut = false; + for (int i = 1; i < argc; ++i) { + if (std::string(argv[i]) == "--" + storm::settings::modules::ConversionOutputSettings::stdoutOptionName) { + outputToStdOut = true; + } + } + if (outputToStdOut) { + storm::utility::setLogLevel(l3pp::LogLevel::OFF); + } else { + storm::cli::printHeader("Storm-conv", argc, argv); + } + + storm::settings::initializeConvSettings("Storm-conv", "storm-conv"); + if (!parseOptions(argc, argv)) { + return -1; + } + + storm::conv::processOptions(); + + storm::utility::cleanUp(); + return 0; + } catch (storm::exceptions::BaseException const& exception) { + STORM_LOG_ERROR("An exception caused Storm-conv to terminate. The message of the exception is: " << exception.what()); + return 1; + } catch (std::exception const& exception) { + STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-conv to terminate. The message of this exception is: " << exception.what()); + return 2; + } +} diff --git a/src/storm-conv/CMakeLists.txt b/src/storm-conv/CMakeLists.txt new file mode 100644 index 000000000..4ead2828e --- /dev/null +++ b/src/storm-conv/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-conv/*.h ${PROJECT_SOURCE_DIR}/src/storm-conv/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-conv) + + + +file(GLOB_RECURSE STORM_CONV_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-conv/*/*.cpp) +file(GLOB_RECURSE STORM_CONV_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-conv/*/*.h) + + +# Create storm-conv. +add_library(storm-conv SHARED ${STORM_CONV_SOURCES} ${STORM_CONV_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-conv PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-conv) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-conv PUBLIC storm ${STORM_CONV_LINK_LIBRARIES}) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_CONV_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_CONV_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_conv_headers DEPENDS ${STORM_CONV_OUTPUT_HEADERS} ${STORM_CONV_HEADERS}) +add_dependencies(storm-conv copy_storm_conv_headers) + +# installation +install(TARGETS storm-conv EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm-conv/api/storm-conv.cpp b/src/storm-conv/api/storm-conv.cpp new file mode 100644 index 000000000..0ed03a071 --- /dev/null +++ b/src/storm-conv/api/storm-conv.cpp @@ -0,0 +1,78 @@ +#include "storm-conv/api/storm-conv.h" + +#include "storm/storage/prism/Program.h" +#include "storm/storage/jani/Property.h" +#include "storm/storage/jani/JaniLocationExpander.h" +#include "storm/storage/jani/JSONExporter.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + +namespace storm { + namespace api { + + void transformJani(storm::jani::Model& janiModel, std::vector& properties, storm::converter::JaniConversionOptions const& options) { + + if (options.substituteConstants) { + janiModel = janiModel.substituteConstants(); + } + + if (!options.locationVariables.empty()) { + for (auto const& pair : options.locationVariables) { + storm::jani::JaniLocationExpander expander(janiModel); + expander.transform(pair.first, pair.second); + janiModel = expander.getResult(); + } + } + + if (options.flatten) { + std::shared_ptr smtSolverFactory; + if (storm::settings::hasModule()) { + smtSolverFactory = std::make_shared(); + } else { + smtSolverFactory = std::make_shared(); + } + janiModel = janiModel.flattenComposition(smtSolverFactory); + } + + if (!options.edgeAssignments) { + janiModel.pushEdgeAssignmentsToDestinations(); + } + + auto uneliminatedFeatures = janiModel.restrictToFeatures(options.allowedModelFeatures); + STORM_LOG_WARN_COND(uneliminatedFeatures.empty(), "The following model features could not be eliminated: " << uneliminatedFeatures.toString()); + + if (options.modelName) { + janiModel.setName(options.modelName.get()); + } + } + + std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties, storm::converter::PrismToJaniConverterOptions options) { + + // Perform conversion + auto res = program.toJani(properties, options.allVariablesGlobal); + if (res.second.empty()) { + std::vector clondedProperties; + for (auto const& p : properties) { + clondedProperties.push_back(p.clone()); + } + res.second = std::move(clondedProperties); + } + + // Postprocess Jani model based on the options + transformJani(res.first, res.second, options.janiOptions); + + return res; + } + + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename, bool compact) { + storm::jani::JsonExporter::toFile(model, properties, filename, true, compact); + } + + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream, bool compact) { + storm::jani::JsonExporter::toStream(model, properties, ostream, true, compact); + } + + + } +} \ No newline at end of file diff --git a/src/storm-conv/api/storm-conv.h b/src/storm-conv/api/storm-conv.h new file mode 100644 index 000000000..12e45269d --- /dev/null +++ b/src/storm-conv/api/storm-conv.h @@ -0,0 +1,28 @@ +#pragma once + +#include "storm-conv/converter/options/PrismToJaniConverterOptions.h" +#include "storm-conv/converter/options/JaniConversionOptions.h" + +namespace storm { + + namespace prism { + class Program; + } + namespace jani { + class Model; + class Property; + } + + namespace api { + + void transformJani(storm::jani::Model& janiModel, std::vector& properties, storm::converter::JaniConversionOptions const& options); + + std::pair> convertPrismToJani(storm::prism::Program const& program, std::vector const& properties = std::vector(), storm::converter::PrismToJaniConverterOptions options = storm::converter::PrismToJaniConverterOptions()); + + void exportJaniToFile(storm::jani::Model const& model, std::vector const& properties, std::string const& filename, bool compact = false); + + void printJaniToStream(storm::jani::Model const& model, std::vector const& properties, std::ostream& ostream, bool compact = false); + + + } +} \ No newline at end of file diff --git a/src/storm-conv/converter/options/JaniConversionOptions.cpp b/src/storm-conv/converter/options/JaniConversionOptions.cpp new file mode 100644 index 000000000..9c1bc1b04 --- /dev/null +++ b/src/storm-conv/converter/options/JaniConversionOptions.cpp @@ -0,0 +1,20 @@ +#include "storm-conv/converter/options/PrismToJaniConverterOptions.h" + +namespace storm { + namespace converter { + + JaniConversionOptions::JaniConversionOptions() : edgeAssignments(false), flatten(false), substituteConstants(true), allowedModelFeatures(storm::jani::getAllKnownModelFeatures()) { + // Intentionally left empty + }; + + JaniConversionOptions::JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings) : locationVariables(settings.getLocationVariables()), edgeAssignments(settings.isAllowEdgeAssignmentsSet()), flatten(settings.isExportFlattenedSet()), substituteConstants(true), allowedModelFeatures(storm::jani::getAllKnownModelFeatures()) { + if (settings.isEliminateFunctionsSet()) { + allowedModelFeatures.remove(storm::jani::ModelFeature::Functions); + } + if (settings.isEliminateArraysSet()) { + allowedModelFeatures.remove(storm::jani::ModelFeature::Arrays); + } + }; + } +} + diff --git a/src/storm-conv/converter/options/JaniConversionOptions.h b/src/storm-conv/converter/options/JaniConversionOptions.h new file mode 100644 index 000000000..e5af6e3d0 --- /dev/null +++ b/src/storm-conv/converter/options/JaniConversionOptions.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +#include "storm-conv/settings/modules/JaniExportSettings.h" +#include "storm/storage/jani/ModelFeatures.h" + +namespace storm { + namespace converter { + + struct JaniConversionOptions { + + JaniConversionOptions(); + JaniConversionOptions(storm::settings::modules::JaniExportSettings const& settings); + + /// (Automaton,Variable)-pairs that will be transformed to location variables of the respective automaton. + std::vector> locationVariables; + + /// If set, the model might have transient assignments to the edges + bool edgeAssignments; + + /// If set, the model is transformed into a single automaton + bool flatten; + + /// If set, constants in expressions are substituted with their definition + bool substituteConstants; + + /// If given, the model will get this name + boost::optional modelName; + + /// Only these model features are allowed in the output + storm::jani::ModelFeatures allowedModelFeatures; + + }; + } +} + diff --git a/src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp b/src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp new file mode 100644 index 000000000..a64f9edbc --- /dev/null +++ b/src/storm-conv/converter/options/PrismToJaniConverterOptions.cpp @@ -0,0 +1,12 @@ +#include "storm-conv/converter/options/PrismToJaniConverterOptions.h" + + +namespace storm { + namespace converter { + + PrismToJaniConverterOptions::PrismToJaniConverterOptions() : allVariablesGlobal(false), suffix("") { + // Intentionally left empty + }; + } +} + diff --git a/src/storm-conv/converter/options/PrismToJaniConverterOptions.h b/src/storm-conv/converter/options/PrismToJaniConverterOptions.h new file mode 100644 index 000000000..0d3d02c85 --- /dev/null +++ b/src/storm-conv/converter/options/PrismToJaniConverterOptions.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "storm-conv/converter/options/JaniConversionOptions.h" + + +namespace storm { + namespace converter { + + + struct PrismToJaniConverterOptions { + + PrismToJaniConverterOptions(); + + bool allVariablesGlobal; + std::string suffix; + JaniConversionOptions janiOptions; + }; + } +} + diff --git a/src/storm-conv/settings/ConvSettings.cpp b/src/storm-conv/settings/ConvSettings.cpp new file mode 100644 index 000000000..cbb872390 --- /dev/null +++ b/src/storm-conv/settings/ConvSettings.cpp @@ -0,0 +1,24 @@ +#include "storm-conv/settings/ConvSettings.h" + +#include "storm-conv/settings/modules/ConversionGeneralSettings.h" +#include "storm-conv/settings/modules/ConversionInputSettings.h" +#include "storm-conv/settings/modules/ConversionOutputSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" + +#include "storm/settings/SettingsManager.h" + + +namespace storm { + namespace settings { + void initializeConvSettings(std::string const& name, std::string const& executableName) { + storm::settings::mutableManager().setName(name, executableName); + + // Register relevant settings modules. + storm::settings::addModule(); + storm::settings::addModule(); + storm::settings::addModule(); + storm::settings::addModule(); + } + + } +} diff --git a/src/storm-conv/settings/ConvSettings.h b/src/storm-conv/settings/ConvSettings.h new file mode 100644 index 000000000..21cbcab31 --- /dev/null +++ b/src/storm-conv/settings/ConvSettings.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace storm { + namespace settings { + + void initializeConvSettings(std::string const& name, std::string const& executableName); + + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/ConversionGeneralSettings.cpp b/src/storm-conv/settings/modules/ConversionGeneralSettings.cpp new file mode 100644 index 000000000..4f1c65e74 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionGeneralSettings.cpp @@ -0,0 +1,77 @@ +#include "storm-conv/settings/modules/ConversionGeneralSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ConversionGeneralSettings::moduleName = "general"; + const std::string ConversionGeneralSettings::helpOptionName = "help"; + const std::string ConversionGeneralSettings::helpOptionShortName = "h"; + const std::string ConversionGeneralSettings::versionOptionName = "version"; + const std::string ConversionGeneralSettings::verboseOptionName = "verbose"; + const std::string ConversionGeneralSettings::verboseOptionShortName = "v"; + const std::string ConversionGeneralSettings::debugOptionName = "debug"; + const std::string ConversionGeneralSettings::traceOptionName = "trace"; + const std::string ConversionGeneralSettings::configOptionName = "config"; + const std::string ConversionGeneralSettings::configOptionShortName = "c"; + + ConversionGeneralSettings::ConversionGeneralSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, helpOptionName, false, "Shows all available options, arguments and descriptions.").setShortName(helpOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("hint", "A regular expression to show help for all matching entities or 'all' for the complete help.").setDefaultValueString("all").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, versionOptionName, false, "Prints the version information.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, verboseOptionName, false, "Enables more verbose output.").setShortName(verboseOptionShortName).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, debugOptionName, false, "Enables verbose and debug output.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, traceOptionName, false, "Enables verbose and debug and trace output.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, configOptionName, false, "If given, this file will be read and parsed for additional configuration settings.").setShortName(configOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the configuration.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + } + + bool ConversionGeneralSettings::isHelpSet() const { + return this->getOption(helpOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isVersionSet() const { + return this->getOption(versionOptionName).getHasOptionBeenSet(); + } + + std::string ConversionGeneralSettings::getHelpModuleName() const { + return this->getOption(helpOptionName).getArgumentByName("hint").getValueAsString(); + } + + bool ConversionGeneralSettings::isVerboseSet() const { + return this->getOption(verboseOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isDebugOutputSet() const { + return this->getOption(debugOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isTraceOutputSet() const { + return this->getOption(traceOptionName).getHasOptionBeenSet(); + } + + bool ConversionGeneralSettings::isConfigSet() const { + return this->getOption(configOptionName).getHasOptionBeenSet(); + } + + std::string ConversionGeneralSettings::getConfigFilename() const { + return this->getOption(configOptionName).getArgumentByName("filename").getValueAsString(); + } + + void ConversionGeneralSettings::finalize() { + // Intentionally left empty. + } + + bool ConversionGeneralSettings::check() const { + return true; + } + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-conv/settings/modules/ConversionGeneralSettings.h b/src/storm-conv/settings/modules/ConversionGeneralSettings.h new file mode 100644 index 000000000..dc7e79f27 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionGeneralSettings.h @@ -0,0 +1,88 @@ +#pragma once +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + class ConversionGeneralSettings : public ModuleSettings { + public: + + ConversionGeneralSettings(); + + /*! + * Retrieves whether the help option was set. + * + * @return True if the help option was set. + */ + bool isHelpSet() const; + + /*! + * Retrieves whether the version option was set. + * + * @return True if the version option was set. + */ + bool isVersionSet() const; + + /*! + * Retrieves the name of the module for which to show the help or "all" to indicate that the full help + * needs to be shown. + * + * @return The name of the module for which to show the help or "all". + */ + std::string getHelpModuleName() const; + + /*! + * Retrieves whether the verbose option was set. + * + * @return True if the verbose option was set. + */ + bool isVerboseSet() const; + + /*! + * Retrieves whether the debug output option was set. + * + */ + bool isDebugOutputSet() const; + + /*! + * Retrieves whether the trace output option was set. + * + */ + bool isTraceOutputSet() const; + + /*! + * Retrieves whether the config option was set. + * + * @return True if the config option was set. + */ + bool isConfigSet() const; + + /*! + * Retrieves the name of the file that is to be scanned for settings. + * + * @return The name of the file that is to be scanned for settings. + */ + std::string getConfigFilename() const; + + bool check() const override; + void finalize() override; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string helpOptionName; + static const std::string helpOptionShortName; + static const std::string versionOptionName; + static const std::string verboseOptionName; + static const std::string verboseOptionShortName; + static const std::string debugOptionName; + static const std::string traceOptionName; + static const std::string configOptionName; + static const std::string configOptionShortName; + }; + } + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.cpp b/src/storm-conv/settings/modules/ConversionInputSettings.cpp new file mode 100644 index 000000000..b1522ab4f --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionInputSettings.cpp @@ -0,0 +1,114 @@ +#include "storm-conv/settings/modules/ConversionInputSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" +#include "storm/parser/CSVParser.h" + +#include "storm/exceptions/InvalidSettingsException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ConversionInputSettings::moduleName = "input"; + const std::string ConversionInputSettings::propertyOptionName = "prop"; + const std::string ConversionInputSettings::propertyOptionShortName = "prop"; + const std::string ConversionInputSettings::constantsOptionName = "constants"; + const std::string ConversionInputSettings::constantsOptionShortName = "const"; + const std::string ConversionInputSettings::prismInputOptionName = "prism"; + const std::string ConversionInputSettings::prismCompatibilityOptionName = "prismcompat"; + const std::string ConversionInputSettings::prismCompatibilityOptionShortName = "pc"; + const std::string ConversionInputSettings::janiInputOptionName = "jani"; + const std::string ConversionInputSettings::janiPropertyOptionName = "janiproperty"; + const std::string ConversionInputSettings::janiPropertyOptionShortName = "jprop"; + + + ConversionInputSettings::ConversionInputSettings() : ModuleSettings(moduleName) { + // General + this->addOption(storm::settings::OptionBuilder(moduleName, propertyOptionName, false, "Specifies the properties to be checked on the model.").setShortName(propertyOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("property or filename", "The formula or the file containing the formulas.").build()) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filter", "The names of the properties to check.").setDefaultValueString("all").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use in symbolic models. Note that this requires the model to be given as an symbolic model (e.g., via --" + prismInputOptionName + ").").setShortName(constantsOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); + + // Prism related + this->addOption(storm::settings::OptionBuilder(moduleName, prismInputOptionName, false, "Parses the model given in the PRISM format.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the PRISM input.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, prismCompatibilityOptionName, false, "Enables PRISM compatibility. This may be necessary to process some PRISM models.").setShortName(prismCompatibilityOptionShortName).build()); + + // Jani related + this->addOption(storm::settings::OptionBuilder(moduleName, janiInputOptionName, false, "Parses the model given in the JANI format.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "The name of the file from which to read the JANI input.").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, janiPropertyOptionName, false, "Specifies the properties from the jani model (given by --" + janiInputOptionName + ") to be checked.").setShortName(janiPropertyOptionShortName) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of properties to be checked").setDefaultValueString("").build()).build()); + + } + + bool ConversionInputSettings::isPrismInputSet() const { + return this->getOption(prismInputOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getPrismInputFilename() const { + return this->getOption(prismInputOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool ConversionInputSettings::isJaniInputSet() const { + return this->getOption(janiInputOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getJaniInputFilename() const { + return this->getOption(janiInputOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool ConversionInputSettings::isPrismCompatibilityEnabled() const { + return this->getOption(prismCompatibilityOptionName).getHasOptionBeenSet(); + } + + bool ConversionInputSettings::isConstantsSet() const { + return this->getOption(constantsOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getConstantDefinitionString() const { + return this->getOption(constantsOptionName).getArgumentByName("values").getValueAsString(); + } + + bool ConversionInputSettings::isPropertyInputSet() const { + return this->getOption(propertyOptionName).getHasOptionBeenSet(); + } + + std::string ConversionInputSettings::getPropertyInput() const { + return this->getOption(propertyOptionName).getArgumentByName("property or filename").getValueAsString(); + } + + std::string ConversionInputSettings::getPropertyInputFilter() const { + return this->getOption(propertyOptionName).getArgumentByName("filter").getValueAsString(); + } + + bool ConversionInputSettings::isJaniPropertiesSet() const { + return this->getOption(janiPropertyOptionName).getHasOptionBeenSet(); + } + + bool ConversionInputSettings::areJaniPropertiesSelected() const { + return this->getOption(janiPropertyOptionName).getHasOptionBeenSet() && (this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString() != ""); + } + + std::vector ConversionInputSettings::getSelectedJaniProperties() const { + return storm::parser::parseCommaSeperatedValues(this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString()); + } + + void ConversionInputSettings::finalize() { + // Intentionally left empty. + } + + bool ConversionInputSettings::check() const { + return true; + } + + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-conv/settings/modules/ConversionInputSettings.h b/src/storm-conv/settings/modules/ConversionInputSettings.h new file mode 100644 index 000000000..2ca110a20 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionInputSettings.h @@ -0,0 +1,118 @@ +#pragma once +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + class ConversionInputSettings : public ModuleSettings { + public: + + ConversionInputSettings(); + + /*! + * Retrieves whether the property option was set. + * + * @return True if the property option was set. + */ + bool isPropertyInputSet() const; + + /*! + * Retrieves the property specified with the property option. + * + * @return The property specified with the property option. + */ + std::string getPropertyInput() const; + + /*! + * Retrieves the property filter. + * + * @return The property filter. + */ + std::string getPropertyInputFilter() const; + + /*! + * Retrieves whether constant definition option was set. + * + * @return True if the constant definition option was set. + */ + bool isConstantsSet() const; + + /*! + * Retrieves the string that defines the constants of a symbolic model (given via the symbolic option). + * + * @return The string that defines the constants of a symbolic model. + */ + std::string getConstantDefinitionString() const; + + /*! + * Retrieves whether the PRISM language option was set. + */ + bool isPrismInputSet() const; + + /*! + * Retrieves the name of the file that contains the PRISM model specification if the model was given + * using the PRISM input option. + */ + std::string getPrismInputFilename() const; + + /*! + * Retrieves whether the PRISM compatibility mode was enabled. + * + * @return True iff the PRISM compatibility mode was enabled. + */ + bool isPrismCompatibilityEnabled() const; + + /*! + * Retrieves whether the Jani option was set. + */ + bool isJaniInputSet() const; + + /*! + * Retrieves the name of the file that contains the jani model specification if the model was given. + */ + std::string getJaniInputFilename() const; + + /*! + * Retrieves whether the jani-property option was set + * @return + */ + bool isJaniPropertiesSet() const; + + /*! + * Retrieves whether one or more jani-properties have been selected + * @return + */ + bool areJaniPropertiesSelected() const; + + /*! + * @return The names of the jani properties to check + */ + std::vector getSelectedJaniProperties() const; + + + + bool check() const override; + void finalize() override; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string propertyOptionName; + static const std::string propertyOptionShortName; + static const std::string constantsOptionName; + static const std::string constantsOptionShortName; + static const std::string prismInputOptionName; + static const std::string prismCompatibilityOptionName; + static const std::string prismCompatibilityOptionShortName; + static const std::string janiInputOptionName; + static const std::string janiPropertyOptionName; + static const std::string janiPropertyOptionShortName; + }; + + + } + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/ConversionOutputSettings.cpp b/src/storm-conv/settings/modules/ConversionOutputSettings.cpp new file mode 100644 index 000000000..61002078d --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionOutputSettings.cpp @@ -0,0 +1,57 @@ +#include "storm-conv/settings/modules/ConversionOutputSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include "storm/exceptions/InvalidSettingsException.h" +#include "storm/exceptions/InvalidOperationException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string ConversionOutputSettings::moduleName = "output"; + const std::string ConversionOutputSettings::stdoutOptionName = "stdout"; + const std::string ConversionOutputSettings::janiOutputOptionName = "tojani"; + + ConversionOutputSettings::ConversionOutputSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, stdoutOptionName, false, "If set, the output will be printed to stdout.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, janiOutputOptionName, false, "converts the input model to Jani.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "the name of the output file (if not empty).").setDefaultValueString("").build()).build()); + } + + bool ConversionOutputSettings::isStdOutOutputEnabled() const { + return this->getOption(stdoutOptionName).getHasOptionBeenSet(); + } + + bool ConversionOutputSettings::isJaniOutputSet() const { + return this->getOption(janiOutputOptionName).getHasOptionBeenSet(); + } + + bool ConversionOutputSettings::isJaniOutputFilenameSet() const { + return isJaniOutputSet() + && !this->getOption(janiOutputOptionName).getArgumentByName("filename").wasSetFromDefaultValue() + && this->getOption(janiOutputOptionName).getArgumentByName("filename").getHasBeenSet() + && this->getOption(janiOutputOptionName).getArgumentByName("filename").getValueAsString() != ""; + } + + std::string ConversionOutputSettings::getJaniOutputFilename() const { + STORM_LOG_THROW(isJaniOutputFilenameSet(), storm::exceptions::InvalidOperationException, "Tried to get the jani output name although none was specified."); + return this->getOption(janiOutputOptionName).getArgumentByName("filename").getValueAsString(); + } + + void ConversionOutputSettings::finalize() { + // Intentionally left empty. + } + + bool ConversionOutputSettings::check() const { + STORM_LOG_THROW(!isJaniOutputFilenameSet() || ArgumentValidatorFactory::createWritableFileValidator()->isValid(getJaniOutputFilename()), storm::exceptions::InvalidSettingsException, "Unable to write at file " + getJaniOutputFilename()); + return true; + } + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm-conv/settings/modules/ConversionOutputSettings.h b/src/storm-conv/settings/modules/ConversionOutputSettings.h new file mode 100644 index 000000000..e429cdd93 --- /dev/null +++ b/src/storm-conv/settings/modules/ConversionOutputSettings.h @@ -0,0 +1,49 @@ +#pragma once +#include "storm/settings/modules/ModuleSettings.h" + +namespace storm { + namespace settings { + namespace modules { + + class ConversionOutputSettings : public ModuleSettings { + public: + + ConversionOutputSettings(); + + /*! + * Retrieves whether the output should be printed to stdout + */ + bool isStdOutOutputEnabled() const; + + /*! + * Retrieves whether the output should be in the Jani format + */ + bool isJaniOutputSet() const; + + /*! + * Retrieves whether an output filename for the jani file was specified + */ + bool isJaniOutputFilenameSet() const; + + /*! + * Retrieves the name of the jani output (if specified) + */ + std::string getJaniOutputFilename() const; + + bool check() const override; + void finalize() override; + + // The name of the module. + static const std::string moduleName; + // name of the option that enables output to stdout. It needs to be public because we have to check this option very early + static const std::string stdoutOptionName; + + private: + // Define the string names of the options as constants. + static const std::string janiOutputOptionName; + }; + + + } + } +} \ No newline at end of file diff --git a/src/storm-conv/settings/modules/JaniExportSettings.cpp b/src/storm-conv/settings/modules/JaniExportSettings.cpp new file mode 100644 index 000000000..207de8edb --- /dev/null +++ b/src/storm-conv/settings/modules/JaniExportSettings.cpp @@ -0,0 +1,88 @@ +#include "JaniExportSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/SettingMemento.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + +#include + +namespace storm { + namespace settings { + namespace modules { + const std::string JaniExportSettings::moduleName = "exportJani"; + + const std::string JaniExportSettings::edgeAssignmentsOptionName = "edge-assignments"; + const std::string JaniExportSettings::exportFlattenOptionName = "flatten"; + const std::string JaniExportSettings::locationVariablesOptionName = "location-variables"; + const std::string JaniExportSettings::globalVariablesOptionName = "globalvars"; + const std::string JaniExportSettings::compactJsonOptionName = "compactjson"; + const std::string JaniExportSettings::eliminateArraysOptionName = "remove-arrays"; + const std::string JaniExportSettings::eliminateFunctionsOptionName = "remove-functions"; + + JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, locationVariablesOptionName, true, "Variables to export in the location").addArgument(storm::settings::ArgumentBuilder::createStringArgument("variables", "A comma separated list of automaton and local variable names seperated by a dot, e.g. A.x,B.y.").setDefaultValueString("").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, edgeAssignmentsOptionName, false, "If set, the output model can have transient edge assignments. This can simplify the jani model but is not compliant to the jani standard.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, exportFlattenOptionName, false, "Flattens the composition of Automata to obtain an equivalent model that contains exactly one automaton").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, globalVariablesOptionName, false, "If set, variables will preferably be made global, e.g., to guarantee the same variable order as in the input file.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, compactJsonOptionName, false, "If set, the size of the resulting jani file will be reduced at the cost of (human-)readability.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, eliminateArraysOptionName, false, "If set, transforms the model such that array variables/expressions are eliminated.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, eliminateFunctionsOptionName, false, "If set, transforms the model such that functions are eliminated.").build()); + } + + bool JaniExportSettings::isAllowEdgeAssignmentsSet() const { + return this->getOption(edgeAssignmentsOptionName).getHasOptionBeenSet(); + } + + bool JaniExportSettings::isExportFlattenedSet() const { + return this->getOption(exportFlattenOptionName).getHasOptionBeenSet(); + } + + bool JaniExportSettings::isLocationVariablesSet() const { + return this->getOption(locationVariablesOptionName).getHasOptionBeenSet(); + } + + std::vector> JaniExportSettings::getLocationVariables() const { + std::vector> result; + if (isLocationVariablesSet()) { + std::string argument = this->getOption(locationVariablesOptionName).getArgumentByName("variables").getValueAsString(); + std::vector arguments; + boost::split( arguments, argument, boost::is_any_of(",")); + for (auto const& pair : arguments) { + std::vector keyvaluepair; + boost::split( keyvaluepair, pair, boost::is_any_of(".")); + STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::IllegalArgumentException, "Expected a name of the form AUTOMATON.VARIABLE (with no further dots) but got " << pair); + result.emplace_back(keyvaluepair.at(0), keyvaluepair.at(1)); + } + } + return result; + } + + bool JaniExportSettings::isGlobalVarsSet() const { + return this->getOption(globalVariablesOptionName).getHasOptionBeenSet(); + } + + bool JaniExportSettings::isCompactJsonSet() const { + return this->getOption(compactJsonOptionName).getHasOptionBeenSet(); + } + + bool JaniExportSettings::isEliminateArraysSet() const { + return this->getOption(eliminateArraysOptionName).getHasOptionBeenSet(); + } + + bool JaniExportSettings::isEliminateFunctionsSet() const { + return this->getOption(eliminateFunctionsOptionName).getHasOptionBeenSet(); + } + + void JaniExportSettings::finalize() { + + } + + bool JaniExportSettings::check() const { + return true; + } + } + } +} diff --git a/src/storm-conv/settings/modules/JaniExportSettings.h b/src/storm-conv/settings/modules/JaniExportSettings.h new file mode 100644 index 000000000..04952e9fd --- /dev/null +++ b/src/storm-conv/settings/modules/JaniExportSettings.h @@ -0,0 +1,50 @@ +#pragma once + +#include "storm-config.h" +#include "storm/settings/modules/ModuleSettings.h" + + +namespace storm { + namespace settings { + namespace modules { + class JaniExportSettings : public ModuleSettings { + public: + /*! + * Creates a new JaniExport setting + */ + JaniExportSettings(); + + bool isAllowEdgeAssignmentsSet() const; + + bool isExportFlattenedSet() const; + + bool isLocationVariablesSet() const; + + bool isGlobalVarsSet() const; + + bool isCompactJsonSet() const; + + bool isEliminateArraysSet() const; + + bool isEliminateFunctionsSet() const; + + std::vector> getLocationVariables() const; + + bool check() const override; + void finalize() override; + + static const std::string moduleName; + + private: + static const std::string edgeAssignmentsOptionName; + static const std::string exportFlattenOptionName; + static const std::string locationVariablesOptionName; + static const std::string globalVariablesOptionName; + static const std::string compactJsonOptionName; + static const std::string eliminateArraysOptionName; + static const std::string eliminateFunctionsOptionName; + + }; + } + } +} diff --git a/src/storm-counterexamples/CMakeLists.txt b/src/storm-counterexamples/CMakeLists.txt new file mode 100644 index 000000000..2052930c6 --- /dev/null +++ b/src/storm-counterexamples/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*.h ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-counterexamples) + + + +file(GLOB_RECURSE STORM_CEX_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*/*.cpp) +file(GLOB_RECURSE STORM_CEX_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-counterexamples/*/*.h) + + +# Create storm-dft. +add_library(storm-counterexamples SHARED ${STORM_CEX_SOURCES} ${STORM_CEX_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-counterexamples PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-counterexamples) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-counterexamples PUBLIC storm) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_CEX_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_CEX_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_cex_headers DEPENDS ${STORM_CEX_OUTPUT_HEADERS} ${STORM_CEX_HEADERS}) +add_dependencies(storm-counterexamples copy_storm_cex_headers) + +# installation +install(TARGETS storm-counterexamples EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm/api/counterexamples.cpp b/src/storm-counterexamples/api/counterexamples.cpp similarity index 95% rename from src/storm/api/counterexamples.cpp rename to src/storm-counterexamples/api/counterexamples.cpp index c57724ad5..5652beba6 100644 --- a/src/storm/api/counterexamples.cpp +++ b/src/storm-counterexamples/api/counterexamples.cpp @@ -1,4 +1,4 @@ -#include "storm/api/counterexamples.h" +#include "storm-counterexamples/api/counterexamples.h" #include "storm/environment/Environment.h" diff --git a/src/storm/api/counterexamples.h b/src/storm-counterexamples/api/counterexamples.h similarity index 80% rename from src/storm/api/counterexamples.h rename to src/storm-counterexamples/api/counterexamples.h index 672ddc4df..6a5984991 100644 --- a/src/storm/api/counterexamples.h +++ b/src/storm-counterexamples/api/counterexamples.h @@ -1,7 +1,7 @@ #pragma once -#include "storm/counterexamples/MILPMinimalLabelSetGenerator.h" -#include "storm/counterexamples/SMTMinimalLabelSetGenerator.h" +#include "storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h" +#include "storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h" namespace storm { namespace api { diff --git a/src/storm/counterexamples/Counterexample.cpp b/src/storm-counterexamples/counterexamples/Counterexample.cpp similarity index 79% rename from src/storm/counterexamples/Counterexample.cpp rename to src/storm-counterexamples/counterexamples/Counterexample.cpp index 4aba71b9c..9975f54ba 100644 --- a/src/storm/counterexamples/Counterexample.cpp +++ b/src/storm-counterexamples/counterexamples/Counterexample.cpp @@ -1,4 +1,4 @@ -#include "storm/counterexamples/Counterexample.h" +#include "storm-counterexamples/counterexamples/Counterexample.h" namespace storm { namespace counterexamples { diff --git a/src/storm/counterexamples/Counterexample.h b/src/storm-counterexamples/counterexamples/Counterexample.h similarity index 100% rename from src/storm/counterexamples/Counterexample.h rename to src/storm-counterexamples/counterexamples/Counterexample.h diff --git a/src/storm/counterexamples/HighLevelCounterexample.cpp b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.cpp similarity index 92% rename from src/storm/counterexamples/HighLevelCounterexample.cpp rename to src/storm-counterexamples/counterexamples/HighLevelCounterexample.cpp index 707ed6d39..11279a220 100644 --- a/src/storm/counterexamples/HighLevelCounterexample.cpp +++ b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.cpp @@ -1,4 +1,4 @@ -#include "storm/counterexamples/HighLevelCounterexample.h" +#include "storm-counterexamples/counterexamples/HighLevelCounterexample.h" namespace storm { namespace counterexamples { diff --git a/src/storm/counterexamples/HighLevelCounterexample.h b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.h similarity index 93% rename from src/storm/counterexamples/HighLevelCounterexample.h rename to src/storm-counterexamples/counterexamples/HighLevelCounterexample.h index 92310a5ba..27fe981c0 100644 --- a/src/storm/counterexamples/HighLevelCounterexample.h +++ b/src/storm-counterexamples/counterexamples/HighLevelCounterexample.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/counterexamples/Counterexample.h" +#include "Counterexample.h" #include "storm/storage/SymbolicModelDescription.h" diff --git a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h similarity index 99% rename from src/storm/counterexamples/MILPMinimalLabelSetGenerator.h rename to src/storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h index da7c55b77..52ed50778 100644 --- a/src/storm/counterexamples/MILPMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/MILPMinimalLabelSetGenerator.h @@ -17,7 +17,7 @@ #include "storm/solver/MinMaxLinearEquationSolver.h" -#include "storm/counterexamples/HighLevelCounterexample.h" +#include "storm-counterexamples/counterexamples/HighLevelCounterexample.h" #include "storm/utility/graph.h" #include "storm/utility/counterexamples.h" @@ -29,7 +29,7 @@ #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" +#include "storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h" namespace storm { @@ -341,7 +341,7 @@ namespace storm { std::list const& relevantChoicesForState = choiceInformation.relevantChoicesForRelevantStates.at(state); for (uint_fast64_t row : relevantChoicesForState) { for (auto const& successorEntry : mdp.getTransitionMatrix().getRow(row)) { - if (stateInformation.relevantStates.get(successorEntry.getColumn())) { + if (stateInformation.relevantStates.get(successorEntry.getColumn()) && resultingMap.find(std::make_pair(state, successorEntry.getColumn())) == resultingMap.end()) { variableNameBuffer.str(""); variableNameBuffer.clear(); variableNameBuffer << "t" << state << "to" << successorEntry.getColumn(); @@ -935,7 +935,7 @@ namespace storm { double maximalReachabilityProbability = 0; if (checkThresholdFeasible) { storm::modelchecker::helper::SparseMdpPrctlHelper modelcheckerHelper; - std::vector result = std::move(modelcheckerHelper.computeUntilProbabilities(env, false, mdp.getTransitionMatrix(), mdp.getBackwardTransitions(), phiStates, psiStates, false, false, storm::solver::GeneralMinMaxLinearEquationSolverFactory()).values); + std::vector result = std::move(modelcheckerHelper.computeUntilProbabilities(env, false, mdp.getTransitionMatrix(), mdp.getBackwardTransitions(), phiStates, psiStates, false, false).values); for (auto state : mdp.getInitialStates()) { maximalReachabilityProbability = std::max(maximalReachabilityProbability, result[state]); } diff --git a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h similarity index 76% rename from src/storm/counterexamples/SMTMinimalLabelSetGenerator.h rename to src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h index 94b828479..d1101d45a 100644 --- a/src/storm/counterexamples/SMTMinimalLabelSetGenerator.h +++ b/src/storm-counterexamples/counterexamples/SMTMinimalLabelSetGenerator.h @@ -5,7 +5,7 @@ #include "storm/solver/Z3SmtSolver.h" -#include "storm/counterexamples/HighLevelCounterexample.h" +#include "storm-counterexamples/counterexamples/HighLevelCounterexample.h" #include "storm/storage/prism/Program.h" #include "storm/storage/expressions/Expression.h" @@ -16,6 +16,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" +#include "storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotSupportedException.h" @@ -28,7 +29,20 @@ namespace storm { class Environment; namespace counterexamples { - + + /** + * Helper to avoid case disticinot between prism and jani + * Returns the number of edges/commands in a symbolic model description. + */ + size_t nrCommands(storm::storage::SymbolicModelDescription const& descr) { + if (descr.isJaniModel()) { + return descr.asJaniModel().getNumberOfEdges(); + } else { + assert(descr.isPrismProgram()); + return descr.asPrismProgram().getNumberOfCommands(); + } + } + /*! * This class provides functionality to generate a minimal counterexample to a probabilistic reachability * property in terms of used labels. @@ -49,14 +63,16 @@ namespace storm { // The set of labels that matter in terms of minimality. boost::container::flat_set minimalityLabels; - + // A set of labels that is definitely known to be taken in the final solution. boost::container::flat_set knownLabels; + + boost::container::flat_set dontCareLabels; // A list of relevant choices for each relevant state. std::map> relevantChoicesForRelevantStates; }; - + struct VariableInformation { // The manager responsible for the constraints we are building. std::shared_ptr manager; @@ -154,10 +170,12 @@ namespace storm { std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(remainingLabels, remainingLabels.end())); relevancyInformation.relevantLabels = remainingLabels; } - + + relevancyInformation.dontCareLabels = dontCareLabels; std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), dontCareLabels.begin(), dontCareLabels.end(), std::inserter(relevancyInformation.minimalityLabels, relevancyInformation.minimalityLabels.begin())); STORM_LOG_DEBUG("Found " << relevancyInformation.relevantLabels.size() << " relevant and " << relevancyInformation.knownLabels.size() << " known labels."); + STORM_LOG_DEBUG("Found " << relevancyInformation.minimalityLabels.size() << " labels to minize over."); return relevancyInformation; } @@ -263,21 +281,6 @@ namespace storm { return variableInformation; } - /*! - * Asserts the constraints that are initially needed for the Fu-Malik procedure. - * - * @param solver The solver in which to assert the constraints. - * @param variableInformation A structure with information about the variables for the labels. - */ - static void assertFuMalikInitialConstraints(z3::solver& solver, VariableInformation const& variableInformation) { - // Assert that at least one of the labels must be taken. - z3::expr formula = variableInformation.labelVariables.at(0); - for (uint_fast64_t index = 1; index < variableInformation.labelVariables.size(); ++index) { - formula = formula || variableInformation.labelVariables.at(index); - } - solver.add(formula); - } - static storm::expressions::Expression getOtherSynchronizationEnabledFormula(boost::container::flat_set const& labelSet, std::map>> const& synchronizingLabels, boost::container::flat_map, storm::expressions::Expression> const& labelSetToFormula, VariableInformation const& variableInformation, RelevancyInformation const& relevancyInformation) { // Taking all commands of a combination does not necessarily mean that a following label set needs to be taken. // This is because it could be that the commands are taken to enable other synchronizations. Therefore, we need @@ -324,13 +327,19 @@ namespace storm { * @param context The Z3 context in which to build the expressions. * @param solver The solver to use for the satisfiability evaluation. */ - static void assertCuts(storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::vector> const& labelSets, storm::storage::BitVector const& psiStates, VariableInformation const& variableInformation, RelevancyInformation const& relevancyInformation, storm::solver::SmtSolver& solver) { + static std::chrono::milliseconds assertCuts(storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::vector> const& labelSets, storm::storage::BitVector const& psiStates, VariableInformation const& variableInformation, RelevancyInformation const& relevancyInformation, storm::solver::SmtSolver& solver, bool addBackwardImplications) { // Walk through the model and // * identify labels enabled in initial states // * identify labels that can directly precede a given action // * identify labels that directly reach a target state // * identify labels that can directly follow a given action - + auto assertCutsClock = std::chrono::high_resolution_clock::now(); + + // + if (addBackwardImplications) { + STORM_LOG_THROW(!symbolicModel.isJaniModel() || !symbolicModel.asJaniModel().usesAssignmentLevels(), storm::exceptions::NotSupportedException, "Counterexample generation with backward implications is not supported for indexed assignments"); + } + boost::container::flat_set initialLabels; std::set> initialCombinations; boost::container::flat_set targetLabels; @@ -345,6 +354,7 @@ namespace storm { storm::storage::BitVector const& initialStates = model.getInitialStates(); for (auto currentState : relevancyInformation.relevantStates) { + bool isInitial = initialStates.get(currentState); for (auto currentChoice : relevancyInformation.relevantChoicesForRelevantStates.at(currentState)) { // If the choice is a synchronization choice, we need to record it. @@ -355,7 +365,7 @@ namespace storm { } // If the state is initial, we need to add all the choice labels to the initial label set. - if (initialStates.get(currentState)) { + if (isInitial) { initialLabels.insert(labelSets[currentChoice].begin(), labelSets[currentChoice].end()); initialCombinations.insert(labelSets[currentChoice]); } @@ -389,6 +399,7 @@ namespace storm { for (auto const& successorEntry : transitionMatrix.getRow(predecessorChoice)) { if (successorEntry.getColumn() == currentState) { choiceTargetsCurrentState = true; + break; } } @@ -400,11 +411,10 @@ namespace storm { } } } - + // Store the found implications in a container similar to the preceding label sets. std::map, std::set>> backwardImplications; - - if (!symbolicModel.isJaniModel() || !symbolicModel.asJaniModel().usesAssignmentLevels()) { + if (addBackwardImplications) { // Create a new solver over the same variables as the given symbolic model description to use it for // determining the symbolic cuts. std::unique_ptr localSolver; @@ -458,6 +468,12 @@ namespace storm { // Now check for possible backward cuts. for (auto const& labelSetAndPrecedingLabelSetsPair : precedingLabels) { + bool backwardImplicationAdded = false; +// std::cout << "labelSetAndPrecedingLabelSetsPair.first "; +// for (auto const& e : labelSetAndPrecedingLabelSetsPair.first) { +// std::cout << e << ", "; +// } +// std::cout << std::endl; // Find out the commands for the currently considered label set. storm::expressions::Expression guardConjunction; @@ -510,15 +526,18 @@ namespace storm { // If the solver reports unsat, then we know that the current selection is not enabled in the initial state. if (checkResult == storm::solver::SmtSolver::CheckResult::Unsat) { STORM_LOG_DEBUG("Selection not enabled in initial state."); - + + //std::cout << "not gc: " << !guardConjunction << std::endl; localSolver->add(!guardConjunction); STORM_LOG_DEBUG("Asserted disjunction of negated guards."); // Now check the possible preceding label sets for the essential ones. for (auto const& precedingLabelSet : labelSetAndPrecedingLabelSetsPair.second) { + if (labelSetAndPrecedingLabelSetsPair.first == precedingLabelSet) continue; - + + //std::cout << "push" << std::endl; // Create a restore point so we can easily pop-off all weakest precondition expressions. localSolver->push(); @@ -576,7 +595,9 @@ namespace storm { } } } - + + //std::cout << "pgc: " << preceedingGuardConjunction << std::endl; + // Assert all the guards of the preceding command set. localSolver->add(preceedingGuardConjunction); @@ -587,8 +608,7 @@ namespace storm { // Iterate over all possible combinations of updates of the preceding command set. std::vector formulae; - bool done = false; - while (!done) { + while (true) { std::map currentVariableUpdateCombinationMap; for (auto const& updateIterator : iteratorVector) { for (auto const& variableUpdatePair : *updateIterator) { @@ -616,7 +636,7 @@ namespace storm { // If we had to reset all iterator to the start, we are done. if (k == 0) { - done = true; + break; } } @@ -624,19 +644,25 @@ namespace storm { assertDisjunction(*localSolver, formulae, symbolicModel.isPrismProgram() ? symbolicModel.asPrismProgram().getManager() : symbolicModel.asJaniModel().getManager()); STORM_LOG_DEBUG("Asserted disjunction of all weakest preconditions."); - - if (localSolver->check() == storm::solver::SmtSolver::CheckResult::Sat) { + storm::solver::SmtSolver::CheckResult result = localSolver->check(); + + if (result == storm::solver::SmtSolver::CheckResult::Sat) { backwardImplications[labelSetAndPrecedingLabelSetsPair.first].insert(precedingLabelSet); + backwardImplicationAdded = true; + } else if (result == storm::solver::SmtSolver::CheckResult::Unknown) { + STORM_LOG_ERROR("The SMT solver does not come to a conclusive answer. Does your model contain integer division?"); } - + localSolver->pop(); } // Popping the disjunction of negated guards from the solver stack. localSolver->pop(); + STORM_LOG_ERROR_COND(backwardImplicationAdded, "Error in adding cuts for counterexample generation (backward implication misses a label set)."); } else { STORM_LOG_DEBUG("Selection is enabled in initial state."); } + } } else if (symbolicModel.isJaniModel()) { STORM_LOG_WARN("Model uses assignment levels, did not assert backward implications."); @@ -716,85 +742,88 @@ namespace storm { assertDisjunction(solver, formulae, *variableInformation.manager); } } - - STORM_LOG_DEBUG("Asserting taken labels are followed and preceeded by another label if they are not a target label or an initial label, respectively."); - boost::container::flat_map, storm::expressions::Expression> labelSetToFormula; - for (auto const& labelSet : relevancyInformation.relevantLabelSets) { - storm::expressions::Expression labelSetFormula = variableInformation.manager->boolean(false); - // Compute the set of unknown labels on the left-hand side of the implication. - boost::container::flat_set unknownLhsLabels; - std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLhsLabels, unknownLhsLabels.end())); - for (auto label : unknownLhsLabels) { - labelSetFormula = labelSetFormula || !variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); - } - - // Only build a constraint if the combination does not lead to a target state and - // no successor set is already known. - storm::expressions::Expression successorExpression; - if (targetCombinations.find(labelSet) == targetCombinations.end() && hasKnownSuccessor.find(labelSet) == hasKnownSuccessor.end()) { - successorExpression = variableInformation.manager->boolean(false); + if(addBackwardImplications) { - auto const& followingLabelSets = followingLabels.at(labelSet); + STORM_LOG_DEBUG("Asserting taken labels are followed and preceeded by another label if they are not a target label or an initial label, respectively."); + boost::container::flat_map, storm::expressions::Expression> labelSetToFormula; + for (auto const &labelSet : relevancyInformation.relevantLabelSets) { + storm::expressions::Expression labelSetFormula = variableInformation.manager->boolean(false); - for (auto const& followingSet : followingLabelSets) { - boost::container::flat_set tmpSet; - - // Check which labels of the current following set are not known. This set must be non-empty, because - // otherwise a successor combination would already be known and control cannot reach this point. - std::set_difference(followingSet.begin(), followingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); - - // Construct an expression that enables all unknown labels of the current following set. - storm::expressions::Expression conj = variableInformation.manager->boolean(true); - for (auto label : tmpSet) { - conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + // Compute the set of unknown labels on the left-hand side of the implication. + boost::container::flat_set unknownLhsLabels; + std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLhsLabels, unknownLhsLabels.end())); + for (auto label : unknownLhsLabels) { + labelSetFormula = labelSetFormula || !variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + } + + // Only build a constraint if the combination does not lead to a target state and + // no successor set is already known. + storm::expressions::Expression successorExpression; + if (targetCombinations.find(labelSet) == targetCombinations.end() && hasKnownSuccessor.find(labelSet) == hasKnownSuccessor.end()) { + successorExpression = variableInformation.manager->boolean(false); + + auto const &followingLabelSets = followingLabels.at(labelSet); + + for (auto const &followingSet : followingLabelSets) { + boost::container::flat_set tmpSet; + + // Check which labels of the current following set are not known. This set must be non-empty, because + // otherwise a successor combination would already be known and control cannot reach this point. + std::set_difference(followingSet.begin(), followingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); + + // Construct an expression that enables all unknown labels of the current following set. + storm::expressions::Expression conj = variableInformation.manager->boolean(true); + for (auto label : tmpSet) { + conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + } + successorExpression = successorExpression || conj; } - successorExpression = successorExpression || conj; + } else { + successorExpression = variableInformation.manager->boolean(true); } - } else { - successorExpression = variableInformation.manager->boolean(true); - } - // Constructed following cuts at this point. - - // Only build a constraint if the combination is no initial combination and no - // predecessor set is already known. - storm::expressions::Expression predecessorExpression; - if (initialCombinations.find(labelSet) == initialCombinations.end() && hasKnownPredecessor.find(labelSet) == hasKnownPredecessor.end()) { - predecessorExpression = variableInformation.manager->boolean(false); - + // Constructed following cuts at this point. + + // Only build a constraint if the combination is no initial combination and no + // predecessor set is already known. + storm::expressions::Expression predecessorExpression; + if (initialCombinations.find(labelSet) == initialCombinations.end() && hasKnownPredecessor.find(labelSet) == hasKnownPredecessor.end()) { + predecessorExpression = variableInformation.manager->boolean(false); + // std::cout << "labelSet" << std::endl; // for (auto const& e : labelSet) { // std::cout << e << ", "; // } // std::cout << std::endl; - auto const& preceedingLabelSets = backwardImplications.at(labelSet); + auto const &preceedingLabelSets = backwardImplications.at(labelSet); - for (auto const& preceedingSet : preceedingLabelSets) { - boost::container::flat_set tmpSet; - - // Check which labels of the current following set are not known. This set must be non-empty, because - // otherwise a predecessor combination would already be known and control cannot reach this point. - std::set_difference(preceedingSet.begin(), preceedingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); - - // Construct an expression that enables all unknown labels of the current following set. - storm::expressions::Expression conj = variableInformation.manager->boolean(true); - for (auto label : tmpSet) { - conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + for (auto const &preceedingSet : preceedingLabelSets) { + boost::container::flat_set tmpSet; + + // Check which labels of the current following set are not known. This set must be non-empty, because + // otherwise a predecessor combination would already be known and control cannot reach this point. + std::set_difference(preceedingSet.begin(), preceedingSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(tmpSet, tmpSet.end())); + + // Construct an expression that enables all unknown labels of the current following set. + storm::expressions::Expression conj = variableInformation.manager->boolean(true); + for (auto label : tmpSet) { + conj = conj && variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label)); + } + predecessorExpression = predecessorExpression || conj; } - predecessorExpression = predecessorExpression || conj; + } else { + predecessorExpression = variableInformation.manager->boolean(true); } - } else { - predecessorExpression = variableInformation.manager->boolean(true); + + labelSetFormula = labelSetFormula || (successorExpression && predecessorExpression); + + labelSetToFormula[labelSet] = labelSetFormula; } - - labelSetFormula = labelSetFormula || (successorExpression && predecessorExpression); - labelSetToFormula[labelSet] = labelSetFormula; - } - - for (auto const& labelSetFormula : labelSetToFormula) { - solver.add(labelSetFormula.second || getOtherSynchronizationEnabledFormula(labelSetFormula.first, synchronizingLabels, labelSetToFormula, variableInformation, relevancyInformation)); + for (auto const &labelSetFormula : labelSetToFormula) { + solver.add(labelSetFormula.second || getOtherSynchronizationEnabledFormula(labelSetFormula.first, synchronizingLabels, labelSetToFormula, variableInformation, relevancyInformation)); + } } STORM_LOG_DEBUG("Asserting synchronization cuts."); @@ -831,6 +860,9 @@ namespace storm { assertDisjunction(solver, formulae, *variableInformation.manager); } } + + auto endTime = std::chrono::high_resolution_clock::now(); + return std::chrono::duration_cast(endTime - assertCutsClock); } /*! @@ -945,22 +977,7 @@ namespace storm { } solver.add(disjunction); } - - /*! - * Asserts that the conjunction of the given formulae holds. If the content of the conjunction is empty, - * this corresponds to asserting true. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param formulaVector A vector of expressions that shall form the conjunction. - */ - static void assertConjunction(z3::context& context, z3::solver& solver, std::vector const& formulaVector) { - z3::expr conjunction = context.bool_val(true); - for (auto expr : formulaVector) { - conjunction = conjunction && expr; - } - solver.add(conjunction); - } + /*! * Creates a full-adder for the two inputs and returns the resulting bit as well as the carry bit. @@ -1030,10 +1047,12 @@ namespace storm { */ static std::vector> createAdderPairs(VariableInformation const& variableInformation, std::vector> const& in) { std::vector> result; - - result.reserve(in.size() / 2 + in.size() % 2); - - for (uint_fast64_t index = 0; index < in.size() / 2; ++index) { + + + uint64_t maxIndex = in.size() / 2; + result.reserve(maxIndex + in.size() % 2); + + for (uint_fast64_t index = 0; index < maxIndex; ++index) { result.push_back(createAdder(variableInformation, in[2 * index], in[2 * index + 1])); } @@ -1137,112 +1156,6 @@ namespace storm { return relaxingVariable; } - /*! - * Asserts that the input vector encodes a decimal smaller or equal to one. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param input The binary encoded input number. - */ - static void assertLessOrEqualOne(z3::context& context, z3::solver& solver, std::vector input) { - std::transform(input.begin(), input.end(), input.begin(), [](z3::expr e) -> z3::expr { return !e; }); - assertConjunction(context, solver, input); - } - - /*! - * Asserts that at most one of given literals may be true at any time. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param blockingVariables A vector of variables out of which only one may be true. - */ - static void assertAtMostOne(z3::context& context, z3::solver& solver, std::vector const& literals) { - std::vector counter = createCounterCircuit(context, literals); - assertLessOrEqualOne(context, solver, counter); - } - - /*! - * Performs one Fu-Malik-Maxsat step. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param variableInformation A structure with information about the variables for the labels. - * @return True iff the constraint system was satisfiable. - */ - static bool fuMalikMaxsatStep(z3::context& context, z3::solver& solver, std::vector& auxiliaryVariables, std::vector& softConstraints, uint_fast64_t& nextFreeVariableIndex) { - z3::expr_vector assumptions(context); - for (auto const& auxiliaryVariable : auxiliaryVariables) { - assumptions.push_back(!auxiliaryVariable); - } - - // Check whether the assumptions are satisfiable. - STORM_LOG_DEBUG("Invoking satisfiability checking."); - z3::check_result result = solver.check(assumptions); - STORM_LOG_DEBUG("Done invoking satisfiability checking."); - - if (result == z3::sat) { - return true; - } else { - STORM_LOG_DEBUG("Computing unsat core."); - z3::expr_vector unsatCore = solver.unsat_core(); - STORM_LOG_DEBUG("Computed unsat core."); - - std::vector blockingVariables; - blockingVariables.reserve(unsatCore.size()); - - // Create stringstream to build expression names. - std::stringstream variableName; - - for (uint_fast64_t softConstraintIndex = 0; softConstraintIndex < softConstraints.size(); ++softConstraintIndex) { - for (uint_fast64_t coreIndex = 0; coreIndex < unsatCore.size(); ++coreIndex) { - bool isContainedInCore = false; - if (softConstraints[softConstraintIndex] == unsatCore[coreIndex]) { - isContainedInCore = true; - } - - if (isContainedInCore) { - variableName.clear(); - variableName.str(""); - variableName << "b" << nextFreeVariableIndex; - blockingVariables.push_back(context.bool_const(variableName.str().c_str())); - - variableName.clear(); - variableName.str(""); - variableName << "a" << nextFreeVariableIndex; - ++nextFreeVariableIndex; - auxiliaryVariables[softConstraintIndex] = context.bool_const(variableName.str().c_str()); - - softConstraints[softConstraintIndex] = softConstraints[softConstraintIndex] || blockingVariables.back(); - - solver.add(softConstraints[softConstraintIndex] || auxiliaryVariables[softConstraintIndex]); - } - } - } - - assertAtMostOne(context, solver, blockingVariables); - } - - return false; - } - - /*! - * Rules out the given command set for the given solver. - * - * @param context The Z3 context in which to build the expressions. - * @param solver The solver to use for the satisfiability evaluation. - * @param commandSet The command set to rule out as a solution. - * @param variableInformation A structure with information about the variables for the labels. - */ - static void ruleOutSolution(z3::context& context, z3::solver& solver, boost::container::flat_set const& commandSet, VariableInformation const& variableInformation) { - z3::expr blockSolutionExpression = context.bool_val(false); - for (auto labelIndexPair : variableInformation.labelToIndexMap) { - if (commandSet.find(labelIndexPair.first) != commandSet.end()) { - blockSolutionExpression = blockSolutionExpression || variableInformation.labelVariables[labelIndexPair.second]; - } - } - - solver.add(blockSolutionExpression); - } /*! * Determines the set of labels that was chosen by the given model. @@ -1300,7 +1213,7 @@ namespace storm { * in order to satisfy the constraint system. * @return The smallest set of labels such that the constraint system of the solver is satisfiable. */ - static boost::container::flat_set findSmallestCommandSet(storm::solver::SmtSolver& solver, VariableInformation& variableInformation, uint_fast64_t& currentBound) { + static boost::optional> findSmallestCommandSet(storm::solver::SmtSolver& solver, VariableInformation& variableInformation, uint_fast64_t& currentBound) { // Check if we can find a solution with the current bound. storm::expressions::Expression assumption = !variableInformation.auxiliaryVariables.back(); @@ -1315,6 +1228,10 @@ namespace storm { solver.add(variableInformation.auxiliaryVariables.back()); variableInformation.auxiliaryVariables.push_back(assertLessOrEqualKRelaxed(solver, variableInformation, ++currentBound)); assumption = !variableInformation.auxiliaryVariables.back(); + if (currentBound > variableInformation.minimalityLabelVariables.size()) { + STORM_LOG_DEBUG("Constraint system fully explored: Bound exceeds maximum of " << variableInformation.minimalityLabelVariables.size()); + return boost::none; + } } // At this point we know that the constraint system was satisfiable, so compute the induced label @@ -1322,6 +1239,45 @@ namespace storm { return getUsedLabelSet(*solver.getModel(), variableInformation); } + static void ruleOutSingleSolution(storm::solver::SmtSolver& solver, boost::container::flat_set const& labelSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { + std::vector formulae; + + boost::container::flat_set unknownLabels; + std::set_intersection(labelSet.begin(), labelSet.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + + //std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + for (auto const& label : unknownLabels) { + formulae.emplace_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); + } + + boost::container::flat_set remainingLabels; + //std::set_difference(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end(), labelSet.begin(), labelSet.end(), std::inserter(remainingLabels, remainingLabels.end())); + std::set_difference(relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), labelSet.begin(), labelSet.end(), std::inserter(remainingLabels, remainingLabels.end())); + + for (auto const& label : remainingLabels) { + formulae.emplace_back(variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); + } + + STORM_LOG_DEBUG("Ruling out single solution."); + assertDisjunction(solver, formulae, *variableInformation.manager); + } + + static void ruleOutBiggerSolutions(storm::solver::SmtSolver& solver, boost::container::flat_set const& labelSet, VariableInformation& variableInformation, RelevancyInformation const& relevancyInformation) { + std::vector formulae; + + boost::container::flat_set unknownLabels; + std::set_intersection(labelSet.begin(), labelSet.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + + //std::set_difference(labelSet.begin(), labelSet.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownLabels, unknownLabels.end())); + for (auto const& label : unknownLabels) { + formulae.emplace_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); + } + + + STORM_LOG_DEBUG("Ruling out set of solutions."); + assertDisjunction(solver, formulae, *variableInformation.manager); + } + /*! * Analyzes the given sub-model that has a maximal reachability of zero (i.e. no psi states are reachable) and tries to construct assertions that aim to make at least one psi state reachable. * @@ -1425,7 +1381,10 @@ namespace storm { std::vector formulae; boost::container::flat_set unknownReachableLabels; std::set_difference(reachableLabels.begin(), reachableLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownReachableLabels, unknownReachableLabels.end())); - for (auto label : unknownReachableLabels) { + boost::container::flat_set unknownReachableMinimalityLabels; + std::set_intersection(unknownReachableLabels.begin(), unknownReachableLabels.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownReachableMinimalityLabels, unknownReachableMinimalityLabels.end())); + + for (auto label : unknownReachableMinimalityLabels) { formulae.push_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); } for (auto const& cutLabelSet : cutLabels) { @@ -1526,7 +1485,10 @@ namespace storm { std::vector formulae; boost::container::flat_set unknownReachableLabels; std::set_difference(reachableLabels.begin(), reachableLabels.end(), relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end(), std::inserter(unknownReachableLabels, unknownReachableLabels.end())); - for (auto label : unknownReachableLabels) { + boost::container::flat_set unknownReachableMinimalityLabels; + std::set_intersection(unknownReachableLabels.begin(), unknownReachableLabels.end(), relevancyInformation.minimalityLabels.begin(), relevancyInformation.minimalityLabels.end(), std::inserter(unknownReachableMinimalityLabels, unknownReachableMinimalityLabels.end())); + + for (auto label : unknownReachableMinimalityLabels) { formulae.push_back(!variableInformation.labelVariables.at(variableInformation.labelToIndexMap.at(label))); } for (auto const& cutLabelSet : cutLabels) { @@ -1548,7 +1510,7 @@ namespace storm { * Returns the sub-model obtained from removing all choices that do not originate from the specified filterLabelSet. * Also returns the Labelsets of the sub-model. */ - static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet) { + static std::pair>, std::vector>> restrictModelToLabelSet(storm::models::sparse::Model const& model, boost::container::flat_set const& filterLabelSet, boost::optional absorbState = boost::none) { bool customRowGrouping = model.isOfType(storm::models::ModelType::Mdp); @@ -1582,42 +1544,93 @@ namespace storm { if (customRowGrouping) { transitionMatrixBuilder.newRowGroup(currentRow); } - transitionMatrixBuilder.addNextValue(currentRow, state, storm::utility::one()); + uint64_t targetState = absorbState == boost::none ? state : absorbState.get(); + transitionMatrixBuilder.addNextValue(currentRow, targetState, storm::utility::one()); // Insert an empty label set for this choice resultLabelSet.emplace_back(); ++currentRow; } + } - + std::shared_ptr> resultModel; if (model.isOfType(storm::models::ModelType::Dtmc)) { - resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling())); + resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling()), model.getRewardModels()); } else { - resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling())); + resultModel = std::make_shared>(transitionMatrixBuilder.build(), storm::models::sparse::StateLabeling(model.getStateLabeling()), model.getRewardModels()); } return std::make_pair(resultModel, std::move(resultLabelSet)); } - static T computeMaximalReachabilityProbability(Environment const& env, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { - T result = storm::utility::zero(); - + static std::vector computeMaximalReachabilityProbability(Environment const& env, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional> const& rewardName) { + std::vector results; + std::vector allStatesResult; STORM_LOG_DEBUG("Invoking model checker."); if (model.isOfType(storm::models::ModelType::Dtmc)) { - allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false, storm::solver::GeneralLinearEquationSolverFactory()); + if (rewardName == boost::none) { + results.push_back(storm::utility::zero()); + allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false); + for (auto state : model.getInitialStates()) { + results.back() = std::max(results.back(), allStatesResult[state]); + } + } else { + for (auto const &rewName : rewardName.get()) { + results.push_back(storm::utility::zero()); + allStatesResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), model.getRewardModel(rewName), psiStates, false); + for (auto state : model.getInitialStates()) { + results.back() = std::max(results.back(), allStatesResult[state]); + } + } + } } else { - storm::modelchecker::helper::SparseMdpPrctlHelper modelCheckerHelper; - allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(), model.getBackwardTransitions(), phiStates, psiStates, false, false, storm::solver::GeneralMinMaxLinearEquationSolverFactory()).values); - } - for (auto state : model.getInitialStates()) { - result = std::max(result, allStatesResult[state]); + if (rewardName == boost::none) { + results.push_back(storm::utility::zero()); + storm::modelchecker::helper::SparseMdpPrctlHelper modelCheckerHelper; + allStatesResult = std::move(modelCheckerHelper.computeUntilProbabilities(env, false, model.getTransitionMatrix(),model.getBackwardTransitions(), phiStates,psiStates, false, false).values); + for (auto state : model.getInitialStates()) { + results.back() = std::max(results.back(), allStatesResult[state]); + } + } else { + STORM_LOG_THROW(rewardName != boost::none, storm::exceptions::NotSupportedException, "Reward property counterexample generation is currently only supported for DTMCs."); + } } - return result; + + return results; } public: + struct Options { + Options(bool checkThresholdFeasible = false) : checkThresholdFeasible(checkThresholdFeasible) { + auto const& settings = storm::settings::getModule(); + + encodeReachability = settings.isEncodeReachabilitySet(); + useDynamicConstraints = settings.isUseDynamicConstraintsSet(); + } + + bool checkThresholdFeasible; + bool encodeReachability; + bool useDynamicConstraints; + bool silent = false; + bool addBackwardImplicationCuts = true; + uint64_t continueAfterFirstCounterexampleUntil = 0; + uint64_t maximumCounterexamples = 1; + uint64_t multipleCounterexampleSizeCap = 100000000; + uint64_t maximumExtraIterations = 100000000; + }; + + struct GeneratorStats { + std::chrono::milliseconds setupTime; + std::chrono::milliseconds solverTime; + std::chrono::milliseconds modelCheckingTime; + std::chrono::milliseconds analysisTime; + std::chrono::milliseconds cutTime; + uint64_t iterations; + }; + + /*! * Computes the minimal command set that is needed in the given model to exceed the given probability threshold for satisfying phi until psi. * @@ -1625,13 +1638,16 @@ namespace storm { * @param model The sparse model in which to find the minimal command set. * @param phiStates A bit vector characterizing all phi states in the model. * @param psiStates A bit vector characterizing all psi states in the model. - * @param probabilityThreshold The threshold that is to be achieved or exceeded. + * @param propertyThreshold The threshold that is to be achieved or exceeded. + * @param rewardName The name of the reward structure to use, or boost::none if probabilities are considerd. * @param strictBound Indicates whether the threshold needs to be achieved (true) or exceeded (false). - * @param checkThresholdFeasible If set, it is verified that the model can actually achieve/exceed the given probability value. If this check - * is made and fails, an exception is thrown. + * @param options A set of options for customization. */ - static boost::container::flat_set getMinimalLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, double probabilityThreshold, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), bool checkThresholdFeasible = false, bool includeReachabilityEncoding = false) { + static std::vector> getMinimalLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector propertyThreshold, boost::optional> const& rewardName, bool strictBound, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options()) { #ifdef STORM_HAVE_Z3 + STORM_LOG_THROW(propertyThreshold.size() > 0, storm::exceptions::InvalidArgumentException, "At least one threshold has to be specified."); + STORM_LOG_THROW(propertyThreshold.size() == 1 || (rewardName && rewardName.get().size() == propertyThreshold.size()), storm::exceptions::InvalidArgumentException, "Multiple thresholds is only supported for multiple reward structures"); + std::vector> result; // Set up all clocks used for time measurement. auto totalClock = std::chrono::high_resolution_clock::now(); auto timeOfLastMessage = std::chrono::high_resolution_clock::now(); @@ -1666,14 +1682,18 @@ namespace storm { labelSets[choice] = choiceOrigins.getEdgeIndexSet(choice); } } + assert(labelSets.size() == model.getNumberOfChoices()); // (1) Check whether its possible to exceed the threshold if checkThresholdFeasible is set. - double maximalReachabilityProbability = 0; - if (checkThresholdFeasible) { - maximalReachabilityProbability = computeMaximalReachabilityProbability(env, model, phiStates, psiStates); - - STORM_LOG_THROW((strictBound && maximalReachabilityProbability >= probabilityThreshold) || (!strictBound && maximalReachabilityProbability > probabilityThreshold), storm::exceptions::InvalidArgumentException, "Given probability threshold " << probabilityThreshold << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability << "."); - std::cout << std::endl << "Maximal reachability in model is " << maximalReachabilityProbability << "." << std::endl << std::endl; + std::vector maximalReachabilityProbability; + if (options.checkThresholdFeasible) { + maximalReachabilityProbability = computeMaximalReachabilityProbability(env, model, phiStates, psiStates, rewardName); + + for (uint64_t i = 0; i < maximalReachabilityProbability.size(); ++i) { + STORM_LOG_THROW((strictBound && maximalReachabilityProbability[i] >= propertyThreshold[i]) || (!strictBound && maximalReachabilityProbability[i] > propertyThreshold[i]), storm::exceptions::InvalidArgumentException, "Given probability threshold " << propertyThreshold[i] << " can not be " << (strictBound ? "achieved" : "exceeded") << " in model with maximal reachability probability of " << maximalReachabilityProbability[i] << "."); + std::cout << std::endl << "Maximal property value in model is " << maximalReachabilityProbability[i] << "." << std::endl << std::endl; + } + } // (2) Identify all states and commands that are relevant, because only these need to be considered later. @@ -1684,7 +1704,7 @@ namespace storm { std::unique_ptr solver = std::make_unique(*manager); // (4) Create the variables for the relevant commands. - VariableInformation variableInformation = createVariables(manager, model, psiStates, relevancyInformation, includeReachabilityEncoding); + VariableInformation variableInformation = createVariables(manager, model, psiStates, relevancyInformation, options.encodeReachability); STORM_LOG_DEBUG("Created variables."); // (5) Now assert an adder whose result variables can later be used to constrain the nummber of label @@ -1692,19 +1712,19 @@ namespace storm { // and subsequently relax that. variableInformation.adderVariables = assertAdder(*solver, variableInformation); variableInformation.auxiliaryVariables.push_back(assertLessOrEqualKRelaxed(*solver, variableInformation, 0)); - + + // As we are done with the setup at this point, stop the clock for the setup time. + totalSetupTime = std::chrono::high_resolution_clock::now() - setupTimeClock; + // (6) Add constraints that cut off a lot of suboptimal solutions. STORM_LOG_DEBUG("Asserting cuts."); - assertCuts(symbolicModel, model, labelSets, psiStates, variableInformation, relevancyInformation, *solver); + stats.cutTime = assertCuts(symbolicModel, model, labelSets, psiStates, variableInformation, relevancyInformation, *solver, options.addBackwardImplicationCuts); STORM_LOG_DEBUG("Asserted cuts."); - if (includeReachabilityEncoding) { + if (options.encodeReachability) { assertReachabilityCuts(model, labelSets, psiStates, variableInformation, relevancyInformation, *solver); STORM_LOG_DEBUG("Asserted reachability cuts."); } - - // As we are done with the setup at this point, stop the clock for the setup time. - totalSetupTime = std::chrono::high_resolution_clock::now() - setupTimeClock; - + // (7) Find the smallest set of commands that satisfies all constraints. If the probability of // satisfying phi until psi exceeds the given threshold, the set of labels is minimal and can be returned. // Otherwise, the current solution has to be ruled out and the next smallest solution is retrieved from @@ -1714,10 +1734,10 @@ namespace storm { // If there are no relevant labels, return directly. if (relevancyInformation.relevantLabels.empty()) { - return commandSet; + return {commandSet}; } else if (relevancyInformation.minimalityLabels.empty()) { commandSet.insert(relevancyInformation.relevantLabels.begin(), relevancyInformation.relevantLabels.end()); - return commandSet; + return {commandSet}; } // Set up some variables for the iterations. @@ -1725,55 +1745,110 @@ namespace storm { uint_fast64_t lastSize = 0; uint_fast64_t iterations = 0; uint_fast64_t currentBound = 0; - maximalReachabilityProbability = 0; + uint64_t firstCounterexampleFound = 0; // The value is not queried before being set. + std::vector maximalPropertyValue; uint_fast64_t zeroProbabilityCount = 0; + size_t smallestCounterexampleSize = model.getNumberOfChoices(); // Definitive upper bound uint64_t progressDelay = storm::settings::getModule().getShowProgressDelay(); do { + ++iterations; + + if (result.size() > 0 && iterations > firstCounterexampleFound + options.maximumExtraIterations) { + break; + } STORM_LOG_DEBUG("Computing minimal command set."); solverClock = std::chrono::high_resolution_clock::now(); - commandSet = findSmallestCommandSet(*solver, variableInformation, currentBound); + boost::optional> smallest = findSmallestCommandSet(*solver, variableInformation, currentBound); totalSolverTime += std::chrono::high_resolution_clock::now() - solverClock; - STORM_LOG_DEBUG("Computed minimal command set of size " << (commandSet.size() + relevancyInformation.knownLabels.size()) << "."); + if(smallest == boost::none) { + STORM_LOG_DEBUG("No further counterexamples."); + break; + } else { + commandSet = smallest.get(); + } + STORM_LOG_DEBUG("Computed minimal command with bound " << currentBound << " and set of size " << commandSet.size() + relevancyInformation.knownLabels.size() << " (" << commandSet.size() << " + " << relevancyInformation.knownLabels.size() << ") "); // Restrict the given model to the current set of labels and compute the reachability probability. modelCheckingClock = std::chrono::high_resolution_clock::now(); commandSet.insert(relevancyInformation.knownLabels.begin(), relevancyInformation.knownLabels.end()); - auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet); + commandSet.insert(relevancyInformation.dontCareLabels.begin(), relevancyInformation.dontCareLabels.end()); + if (commandSet.size() > smallestCounterexampleSize + options.continueAfterFirstCounterexampleUntil || (result.size() > 1 && commandSet.size() > options.multipleCounterexampleSizeCap) ) { + STORM_LOG_DEBUG("No further counterexamples of similar size."); + break; + } + + if (commandSet.size() == nrCommands(symbolicModel)) { + result.push_back(commandSet); + break; + } + + auto subChoiceOrigins = restrictModelToLabelSet(model, commandSet, psiStates.getNextSetIndex(0)); std::shared_ptr> const& subModel = subChoiceOrigins.first; std::vector> const& subLabelSets = subChoiceOrigins.second; // Now determine the maximal reachability probability in the sub-model. - maximalReachabilityProbability = computeMaximalReachabilityProbability(env, *subModel, phiStates, psiStates); + maximalPropertyValue = computeMaximalReachabilityProbability(env, *subModel, phiStates, psiStates, rewardName); totalModelCheckingTime += std::chrono::high_resolution_clock::now() - modelCheckingClock; // Depending on whether the threshold was successfully achieved or not, we proceed by either analyzing the bad solution or stopping the iteration process. analysisClock = std::chrono::high_resolution_clock::now(); - if ((strictBound && maximalReachabilityProbability < probabilityThreshold) || (!strictBound && maximalReachabilityProbability <= probabilityThreshold)) { - if (maximalReachabilityProbability == 0) { + bool violation = false; + for (uint64_t i = 0; i < maximalPropertyValue.size(); i++) { + violation |= (strictBound && maximalPropertyValue[i] < propertyThreshold[i]) || (!strictBound && maximalPropertyValue[i] <= propertyThreshold[i]); + } + + if (violation) { + if (!rewardName && maximalPropertyValue.front() == storm::utility::zero()) { ++zeroProbabilityCount; + } + + if (options.useDynamicConstraints) { + // Determine which of the two analysis techniques to call by performing a reachability analysis. + storm::storage::BitVector reachableStates = storm::utility::graph::getReachableStates(subModel->getTransitionMatrix(), subModel->getInitialStates(), phiStates, psiStates); - // If there was no target state reachable, analyze the solution and guide the solver into the right direction. - analyzeZeroProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + if (reachableStates.isDisjointFrom(psiStates)) { + // If there was no target state reachable, analyze the solution and guide the solver into the right direction. + analyzeZeroProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + } else { + // If the reachability probability was greater than zero (i.e. there is a reachable target state), but the probability was insufficient to exceed + // the given threshold, we analyze the solution and try to guide the solver into the right direction. + analyzeInsufficientProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + } + + if (relevancyInformation.dontCareLabels.size() > 0) { + ruleOutSingleSolution(*solver, commandSet, variableInformation, relevancyInformation); + } } else { - // If the reachability probability was greater than zero (i.e. there is a reachable target state), but the probability was insufficient to exceed - // the given threshold, we analyze the solution and try to guide the solver into the right direction. - analyzeInsufficientProbabilitySolution(*solver, *subModel, subLabelSets, model, labelSets, phiStates, psiStates, commandSet, variableInformation, relevancyInformation); + // Do not guide solver, just rule out current solution. + ruleOutSingleSolution(*solver, commandSet, variableInformation, relevancyInformation); } } else { - done = true; + STORM_LOG_DEBUG("Found a counterexample."); + if (result.empty()) { + // If this is the first counterexample we find, we store when we found it. + firstCounterexampleFound = iterations; + } + result.push_back(commandSet); + if (options.maximumCounterexamples > result.size()) { + STORM_LOG_DEBUG("Exclude counterexample for future."); + ruleOutBiggerSolutions(*solver, commandSet, variableInformation, relevancyInformation); + } else { + STORM_LOG_DEBUG("Stop searching for further counterexamples."); + done = true; + } + smallestCounterexampleSize = std::min(smallestCounterexampleSize, commandSet.size()); } totalAnalysisTime += (std::chrono::high_resolution_clock::now() - analysisClock); - ++iterations; auto now = std::chrono::high_resolution_clock::now(); auto durationSinceLastMessage = std::chrono::duration_cast(now - timeOfLastMessage).count(); if (static_cast(durationSinceLastMessage) >= progressDelay || lastSize < commandSet.size()) { auto milliseconds = std::chrono::duration_cast(now - totalClock).count(); if (lastSize < commandSet.size()) { - std::cout << "Improved lower bound to " << commandSet.size() << " after " << milliseconds << "ms." << std::endl; + std::cout << "Improved lower bound to " << currentBound << " after " << milliseconds << "ms." << std::endl; lastSize = commandSet.size(); } else { - std::cout << "Lower bound on label set size is " << commandSet.size() << " after " << milliseconds << "ms (checked " << iterations << " models, " << zeroProbabilityCount << " could not reach the target set)." << std::endl; + std::cout << "Lower bound on label set size is " << currentBound << " after " << milliseconds << "ms (checked " << iterations << " models, " << zeroProbabilityCount << " could not reach the target set)." << std::endl; timeOfLastMessage = std::chrono::high_resolution_clock::now(); } } @@ -1781,12 +1856,20 @@ namespace storm { // Compute and emit the time measurements if the corresponding flag was set. totalTime = std::chrono::high_resolution_clock::now() - totalClock; + + stats.analysisTime = std::chrono::duration_cast(totalAnalysisTime); + stats.setupTime = std::chrono::duration_cast(totalSetupTime); + stats.modelCheckingTime = std::chrono::duration_cast(totalModelCheckingTime); + stats.solverTime = std::chrono::duration_cast(totalSolverTime); + stats.iterations = iterations; + if (storm::settings::getModule().isShowStatisticsSet()) { boost::container::flat_set allLabels; for (auto const& e : labelSets) { allLabels.insert(e.begin(), e.end()); } - + + std::cout << "Metrics:" << std::endl; std::cout << " * all labels: " << allLabels.size() << std::endl; std::cout << " * known labels: " << relevancyInformation.knownLabels.size() << std::endl; @@ -1805,13 +1888,13 @@ namespace storm { std::cout << " * number of models that could not reach a target state: " << zeroProbabilityCount << " (" << 100 * static_cast(zeroProbabilityCount)/iterations << "%)" << std::endl << std::endl; } - return commandSet; + return result; #else throw storm::exceptions::NotImplementedException() << "This functionality is unavailable since storm has been compiled without support for Z3."; #endif } - static void extendLabelSetLowerBound(storm::models::sparse::Model const& model, boost::container::flat_set& commandSet, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) { + static void extendLabelSetLowerBound(storm::models::sparse::Model const& model, boost::container::flat_set& commandSet, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool silent = false) { auto startTime = std::chrono::high_resolution_clock::now(); // Create sub-model that only contains the choices allowed by the given command set. @@ -1849,11 +1932,17 @@ namespace storm { } if (onlyProb0ESuccessors) { - auto const& labelSet = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(choice); - hasLabeledChoice |= !labelSet.empty(); + uint64_t labelSetSize = 0; + if (model.getChoiceOrigins()->isPrismChoiceOrigins()) { + labelSetSize = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(choice).size(); + } else { + assert(model.getChoiceOrigins()->isJaniChoiceOrigins()); + labelSetSize = model.getChoiceOrigins()->asJaniChoiceOrigins().getEdgeIndexSet(choice).size(); + } + hasLabeledChoice |= (labelSetSize != 0); - if (smallestCommandChoice == 0 || labelSet.size() < smallestCommandSetSize) { - smallestCommandSetSize = labelSet.size(); + if (smallestCommandChoice == 0 || labelSetSize < smallestCommandSetSize) { + smallestCommandSetSize = labelSetSize; smallestCommandChoice = choice; } } @@ -1861,9 +1950,15 @@ namespace storm { if (hasLabeledChoice) { // Take all labels of the selected choice. - auto const& labelSet = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(smallestCommandChoice); - commandSet.insert(labelSet.begin(), labelSet.end()); - + if (model.getChoiceOrigins()->isPrismChoiceOrigins()) { + auto const& labelSet = model.getChoiceOrigins()->asPrismChoiceOrigins().getCommandSet(smallestCommandChoice); + commandSet.insert(labelSet.begin(), labelSet.end()); + } else { + assert(model.getChoiceOrigins()->isJaniChoiceOrigins()); + auto const& labelSet = model.getChoiceOrigins()->asJaniChoiceOrigins().getEdgeIndexSet(smallestCommandChoice); + commandSet.insert(labelSet.begin(), labelSet.end()); + } + // Check for which successor states choices need to be added for (auto const& successorEntry : model.getTransitionMatrix().getRow(smallestCommandChoice)) { if (!storm::utility::isZero(successorEntry.getValue())) { @@ -1877,29 +1972,64 @@ namespace storm { } auto endTime = std::chrono::high_resolution_clock::now(); - std::cout << std::endl << "Extended command for lower bounded property to size " << commandSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; - } - - static boost::container::flat_set computeCounterexampleLabelSet(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { - STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); - std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; + if (!silent) { + std::cout << std::endl << "Extended command for lower bounded property to size " << commandSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + } - STORM_LOG_THROW(formula->isProbabilityOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); - storm::logic::ProbabilityOperatorFormula const& probabilityOperator = formula->asProbabilityOperatorFormula(); - STORM_LOG_THROW(probabilityOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); - STORM_LOG_THROW(probabilityOperator.getSubformula().isUntilFormula() || probabilityOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'phi U psi' for counterexample generation."); + } - storm::logic::ComparisonType comparisonType = probabilityOperator.getComparisonType(); - bool strictBound = comparisonType == storm::logic::ComparisonType::Less; - double threshold = probabilityOperator.getThresholdAs(); + struct CexInput { + storm::logic::ComparisonType comparisonType; + std::vector threshold; + boost::optional> rewardName = boost::none; + bool lowerBoundedFormula = false; + bool strictBound; storm::storage::BitVector phiStates; storm::storage::BitVector psiStates; + + void addRewardThresholdCombination(std::string reward, double thresh) { + STORM_LOG_THROW(rewardName, storm::exceptions::InvalidOperationException, "Can only add more reward names if a reward name is already set"); + rewardName.get().push_back(reward); + threshold.push_back(thresh); + } + }; + + static CexInput precompute(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { + + CexInput result; + STORM_LOG_THROW(formula->isProbabilityOperatorFormula() || formula->isRewardOperatorFormula(), storm::exceptions::InvalidPropertyException, "Counterexample generation does not support this kind of formula. Expecting a probability operator as the outermost formula element."); + if (formula->isProbabilityOperatorFormula()) { + storm::logic::ProbabilityOperatorFormula const& probabilityOperator = formula->asProbabilityOperatorFormula(); + STORM_LOG_THROW(probabilityOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); + STORM_LOG_THROW(probabilityOperator.getSubformula().isUntilFormula() || probabilityOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'phi U psi' for counterexample generation."); + + result.comparisonType = probabilityOperator.getComparisonType(); + result.threshold.push_back(probabilityOperator.getThresholdAs()); + } else { + assert(formula->isRewardOperatorFormula()); + storm::logic::RewardOperatorFormula const& rewardOperator = formula->asRewardOperatorFormula(); + STORM_LOG_THROW(rewardOperator.hasBound(), storm::exceptions::InvalidPropertyException, "Counterexample generation only supports bounded formulas."); + STORM_LOG_THROW( rewardOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'F phi' for counterexample generation."); + + result.comparisonType = rewardOperator.getComparisonType(); + result.threshold.push_back(rewardOperator.getThresholdAs()); + result.rewardName = std::vector(); + result.rewardName.get().push_back(rewardOperator.getRewardModelName()); + + STORM_LOG_THROW(!storm::logic::isLowerBound(result.comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for probability formulas."); + STORM_LOG_THROW(model.hasRewardModel(result.rewardName.get().front()), storm::exceptions::InvalidPropertyException, "Property refers to reward " << result.rewardName.get().front() << " but model does not contain such a reward model."); + STORM_LOG_THROW(model.getRewardModel(result.rewardName.get().front()).hasOnlyStateRewards(), storm::exceptions::NotSupportedException, "We only support state-based rewards at the moment."); + } + result.strictBound = result.comparisonType == storm::logic::ComparisonType::Less; + storm::logic::Formula const& subformula = formula->asOperatorFormula().getSubformula(); + + storm::modelchecker::SparsePropositionalModelChecker> modelchecker(model); - if (probabilityOperator.getSubformula().isUntilFormula()) { - STORM_LOG_THROW(!storm::logic::isLowerBound(comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for eventually formulas."); - storm::logic::UntilFormula const& untilFormula = probabilityOperator.getSubformula().asUntilFormula(); + if (subformula.isUntilFormula()) { + STORM_LOG_THROW(!storm::logic::isLowerBound(result.comparisonType), storm::exceptions::NotSupportedException, "Lower bounds in counterexamples are only supported for eventually formulas."); + storm::logic::UntilFormula const& untilFormula = subformula.asUntilFormula(); std::unique_ptr leftResult = modelchecker.check(env, untilFormula.getLeftSubformula()); std::unique_ptr rightResult = modelchecker.check(env, untilFormula.getRightSubformula()); @@ -1907,21 +2037,21 @@ namespace storm { storm::modelchecker::ExplicitQualitativeCheckResult const& leftQualitativeResult = leftResult->asExplicitQualitativeCheckResult(); storm::modelchecker::ExplicitQualitativeCheckResult const& rightQualitativeResult = rightResult->asExplicitQualitativeCheckResult(); - phiStates = leftQualitativeResult.getTruthValuesVector(); - psiStates = rightQualitativeResult.getTruthValuesVector(); - } else if (probabilityOperator.getSubformula().isEventuallyFormula()) { - storm::logic::EventuallyFormula const& eventuallyFormula = probabilityOperator.getSubformula().asEventuallyFormula(); + result.phiStates = leftQualitativeResult.getTruthValuesVector(); + result.psiStates = rightQualitativeResult.getTruthValuesVector(); + } else if (subformula.isEventuallyFormula()) { + storm::logic::EventuallyFormula const& eventuallyFormula = subformula.asEventuallyFormula(); std::unique_ptr subResult = modelchecker.check(env, eventuallyFormula.getSubformula()); storm::modelchecker::ExplicitQualitativeCheckResult const& subQualitativeResult = subResult->asExplicitQualitativeCheckResult(); - phiStates = storm::storage::BitVector(model.getNumberOfStates(), true); - psiStates = subQualitativeResult.getTruthValuesVector(); + result.phiStates = storm::storage::BitVector(model.getNumberOfStates(), true); + result.psiStates = subQualitativeResult.getTruthValuesVector(); } - bool lowerBoundedFormula = false; - if (storm::logic::isLowerBound(comparisonType)) { + if (storm::logic::isLowerBound(result.comparisonType)) { + STORM_LOG_DEBUG("Computing counterexample for a lowerbound."); // If the formula specifies a lower bound, we need to modify the phi and psi states. // More concretely, we convert P(min)>lambda(F psi) to P(max)<(1-lambda)(G !psi) = P(max)<(1-lambda)(!psi U prob0E(psi)) // where prob0E(psi) is the set of states for which there exists a strategy \sigma_0 that avoids @@ -1930,44 +2060,68 @@ namespace storm { // This means that from all states in prob0E(psi) we need to include labels such that \sigma_0 // is actually included in the resulting model. This prevents us from guaranteeing the minimality of // the returned counterexample, so we warn about that. - STORM_LOG_WARN("Generating counterexample for lower-bounded property. The resulting command set need not be minimal."); + // Modify bound appropriately. - comparisonType = storm::logic::invertPreserveStrictness(comparisonType); - threshold = storm::utility::one() - threshold; + result.comparisonType = storm::logic::invertPreserveStrictness(result.comparisonType); + result.threshold.back() = storm::utility::one() - result.threshold.back(); // Modify the phi and psi states appropriately. - storm::storage::BitVector statesWithProbability0E = storm::utility::graph::performProb0E(model.getTransitionMatrix(), model.getTransitionMatrix().getRowGroupIndices(), model.getBackwardTransitions(), phiStates, psiStates); - phiStates = ~psiStates; - psiStates = std::move(statesWithProbability0E); + storm::storage::BitVector statesWithProbability0E = storm::utility::graph::performProb0E(model.getTransitionMatrix(), model.getTransitionMatrix().getRowGroupIndices(), model.getBackwardTransitions(), result.phiStates, result.psiStates); + result.phiStates = ~result.psiStates; + result.psiStates = std::move(statesWithProbability0E); // Remember our transformation so we can add commands to guarantee that the prob0E(a) states actually // have a strategy that voids a states. - lowerBoundedFormula = true; + result.lowerBoundedFormula = true; } + return result; + + } + + + static std::vector> computeCounterexampleLabelSet(Environment const& env, GeneratorStats& stats, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, CexInput const& counterexInput, boost::container::flat_set const& dontCareLabels = boost::container::flat_set(), Options const& options = Options(true)) { + STORM_LOG_THROW(model.isOfType(storm::models::ModelType::Dtmc) || model.isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "MaxSAT-based counterexample generation is supported only for discrete-time models."); // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSet = getMinimalLabelSet(env, symbolicModel, model, phiStates, psiStates, threshold, strictBound, boost::container::flat_set(), true, storm::settings::getModule().isEncodeReachabilitySet()); + auto labelSets = getMinimalLabelSet(env, stats, symbolicModel, model, counterexInput.phiStates, counterexInput.psiStates, counterexInput.threshold, counterexInput.rewardName, counterexInput.strictBound, dontCareLabels, options); auto endTime = std::chrono::high_resolution_clock::now(); - std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + if (!options.silent) { + for (auto const& labelSet : labelSets) { + std::cout << std::endl << "Computed minimal label set of size " << labelSet.size(); + + } + std::cout << std::endl << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; + + } // Extend the command set properly. - if (lowerBoundedFormula) { - extendLabelSetLowerBound(model, labelSet, phiStates, psiStates); + for (auto& labelSet : labelSets) { + if (counterexInput.lowerBoundedFormula) { + STORM_LOG_DEBUG("Extending the counterexample due to lower bound computation."); + extendLabelSetLowerBound(model, labelSet, counterexInput.phiStates, counterexInput.psiStates, options.silent); + } } - return labelSet; + return labelSets; } static std::shared_ptr computeCounterexample(Environment const& env, storm::storage::SymbolicModelDescription const& symbolicModel, storm::models::sparse::Model const& model, std::shared_ptr const& formula) { #ifdef STORM_HAVE_Z3 - auto labelSet = computeCounterexampleLabelSet(env, symbolicModel, model, formula); - + std::cout << std::endl << "Generating minimal label counterexample for formula " << *formula << std::endl; + GeneratorStats stats; + CexInput prec = precompute(env, symbolicModel, model, formula); + if (prec.lowerBoundedFormula) { + STORM_LOG_WARN("Generating counterexample for lower-bounded property. The resulting command set need not be minimal."); + } + auto labelSets = computeCounterexampleLabelSet(env, stats, symbolicModel, model, prec); + + if (symbolicModel.isPrismProgram()) { - return std::make_shared(symbolicModel.asPrismProgram().restrictCommands(labelSet)); + return std::make_shared(symbolicModel.asPrismProgram().restrictCommands(labelSets[0])); } else { STORM_LOG_ASSERT(symbolicModel.isJaniModel(), "Unknown symbolic model description type."); - return std::make_shared(symbolicModel.asJaniModel().restrictEdges(labelSet)); + return std::make_shared(symbolicModel.asJaniModel().restrictEdges(labelSets[0])); } #else throw storm::exceptions::NotImplementedException() << "This functionality is unavailable since storm has been compiled without support for Z3."; diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp similarity index 77% rename from src/storm/settings/modules/CounterexampleGeneratorSettings.cpp rename to src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp index b33a332df..5b2142ee3 100644 --- a/src/storm/settings/modules/CounterexampleGeneratorSettings.cpp +++ b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.cpp @@ -1,4 +1,4 @@ -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" +#include "storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/exceptions/InvalidSettingsException.h" @@ -16,13 +16,15 @@ namespace storm { const std::string CounterexampleGeneratorSettings::minimalCommandSetOptionName = "mincmd"; const std::string CounterexampleGeneratorSettings::encodeReachabilityOptionName = "encreach"; const std::string CounterexampleGeneratorSettings::schedulerCutsOptionName = "schedcuts"; - + const std::string CounterexampleGeneratorSettings::noDynamicConstraintsOptionName = "nodyn"; + CounterexampleGeneratorSettings::CounterexampleGeneratorSettings() : ModuleSettings(moduleName) { std::vector techniques = {"maxsat", "milp"}; - this->addOption(storm::settings::OptionBuilder(moduleName, minimalCommandSetOptionName, true, "Computes a counterexample for the given model in terms of a minimal command set. Note that this requires the model to be given in a symbolic format.") + this->addOption(storm::settings::OptionBuilder(moduleName, minimalCommandSetOptionName, true, "Computes a counterexample for the given model in terms of a minimal command/edge set. Note that this requires the model to be given in a symbolic format.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("method", "Sets which technique is used to derive the counterexample.").setDefaultValueString("maxsat").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(techniques)).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, encodeReachabilityOptionName, true, "Sets whether to encode reachability for MAXSAT-based minimal command counterexample generation.").build()); - this->addOption(storm::settings::OptionBuilder(moduleName, schedulerCutsOptionName, true, "Sets whether to add the scheduler cuts for MILP-based minimal command counterexample generation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, encodeReachabilityOptionName, true, "Sets whether to encode reachability for MAXSAT-based counterexample generation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, schedulerCutsOptionName, true, "Sets whether to add the scheduler cuts for MILP-based counterexample generation.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, noDynamicConstraintsOptionName, true, "Disables the generation of dynamic constraints in the MAXSAT-based counterexample generation.").build()); } bool CounterexampleGeneratorSettings::isMinimalCommandSetGenerationSet() const { @@ -44,10 +46,14 @@ namespace storm { bool CounterexampleGeneratorSettings::isUseSchedulerCutsSet() const { return this->getOption(schedulerCutsOptionName).getHasOptionBeenSet(); } - + + bool CounterexampleGeneratorSettings::isUseDynamicConstraintsSet() const { + return !this->getOption(noDynamicConstraintsOptionName).getHasOptionBeenSet(); + } + bool CounterexampleGeneratorSettings::check() const { // Ensure that the model was given either symbolically or explicitly. - STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule().isPrismInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM format."); + STORM_LOG_THROW(!isMinimalCommandSetGenerationSet() || storm::settings::getModule().isPrismInputSet() || storm::settings::getModule().isJaniInputSet(), storm::exceptions::InvalidSettingsException, "For the generation of a minimal command set, the model has to be specified in the PRISM/JANI format."); if (isMinimalCommandSetGenerationSet()) { STORM_LOG_WARN_COND(isUseMaxSatBasedMinimalCommandSetGenerationSet() || !isEncodeReachabilitySet(), "Encoding reachability is only available for the MaxSat-based minimal command set generation, so selecting it has no effect."); diff --git a/src/storm/settings/modules/CounterexampleGeneratorSettings.h b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h similarity index 89% rename from src/storm/settings/modules/CounterexampleGeneratorSettings.h rename to src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h index 03002c8f6..bdb0813a6 100644 --- a/src/storm/settings/modules/CounterexampleGeneratorSettings.h +++ b/src/storm-counterexamples/settings/modules/CounterexampleGeneratorSettings.h @@ -56,6 +56,13 @@ namespace storm { */ bool isUseSchedulerCutsSet() const; + /*! + * Retrieves whether to use the dynamic constraints in the MAXSAT-based technique. + * + * @return True iff dynamic constraints are to be used. + */ + bool isUseDynamicConstraintsSet() const; + bool check() const override; // The name of the module. @@ -66,6 +73,7 @@ namespace storm { static const std::string minimalCommandSetOptionName; static const std::string encodeReachabilityOptionName; static const std::string schedulerCutsOptionName; + static const std::string noDynamicConstraintsOptionName; }; } // namespace modules diff --git a/src/storm-dft-cli/CMakeLists.txt b/src/storm-dft-cli/CMakeLists.txt index 4780eef4d..5886ac0a0 100644 --- a/src/storm-dft-cli/CMakeLists.txt +++ b/src/storm-dft-cli/CMakeLists.txt @@ -6,4 +6,4 @@ set_target_properties(storm-dft-cli PROPERTIES OUTPUT_NAME "storm-dft") add_dependencies(binaries storm-dft-cli) # installation -install(TARGETS storm-dft-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-dft-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-dft-cli/storm-dft.cpp b/src/storm-dft-cli/storm-dft.cpp index 21f3cfecc..0e38d7757 100644 --- a/src/storm-dft-cli/storm-dft.cpp +++ b/src/storm-dft-cli/storm-dft.cpp @@ -1,164 +1,68 @@ -#include "storm-dft/settings/DftSettings.h" +#include "storm-dft/api/storm-dft.h" +#include "storm-dft/settings/DftSettings.h" #include "storm-dft/settings/modules/DftIOSettings.h" #include "storm-dft/settings/modules/FaultTreeSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/ResourceSettings.h" +#include "storm/settings/modules/GeneralSettings.h" + +#include "storm-parsers/api/storm-parsers.h" #include "storm/utility/initialize.h" -#include "storm/api/storm.h" #include "storm-cli-utilities/cli.h" -#include "storm-dft/parser/DFTGalileoParser.h" -#include "storm-dft/parser/DFTJsonParser.h" -#include "storm-dft/modelchecker/dft/DFTModelChecker.h" -#include "storm-dft/modelchecker/dft/DFTASFChecker.h" -#include "storm-dft/transformations/DftToGspnTransformator.h" -#include "storm-dft/storage/dft/DftJsonExporter.h" - -#include "storm-gspn/storage/gspn/GSPN.h" -#include "storm-gspn/storm-gspn.h" - -#include -#include - -template -std::shared_ptr> loadDFT() { - storm::settings::modules::DftIOSettings const& dftIOSettings = storm::settings::getModule(); - std::shared_ptr> dft; - // Build DFT from given file. - if (dftIOSettings.isDftJsonFileSet()) { - storm::parser::DFTJsonParser parser; - STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftJsonFilename()); - dft = std::make_shared>(parser.parseJson(dftIOSettings.getDftJsonFilename())); - } else { - storm::parser::DFTGalileoParser parser; - STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftFilename()); - dft = std::make_shared>(parser.parseDFT(dftIOSettings.getDftFilename())); - } - - if (dftIOSettings.isDisplayStatsSet()) { - std::cout << "=============DFT Statistics==============" << std::endl; - dft->writeStatsToStream(std::cout); - std::cout << "=========================================" << std::endl; - } - return dft; -} - /*! - * Analyse the given DFT according to the given properties. - * We first load the DFT from the given file, then build the corresponding model and last check against the given properties. - * - * @param properties PCTL formulas capturing the properties to check. - * @param symred Flag whether symmetry reduction should be used. - * @param allowModularisation Flag whether modularisation should be applied if possible. - * @param enableDC Flag whether Don't Care propagation should be used. - * @param approximationError Allowed approximation error. - */ -template -void analyzeDFT(std::vector const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { - std::shared_ptr> dft = loadDFT(); - - // Build properties - std::string propString = properties[0]; - for (size_t i = 1; i < properties.size(); ++i) { - propString += ";" + properties[i]; - } - std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); - STORM_LOG_ASSERT(props.size() > 0, "No properties found."); - - // Check model - storm::modelchecker::DFTModelChecker modelChecker; - modelChecker.check(*dft, props, symred, allowModularisation, enableDC, approximationError); - modelChecker.printTimings(); - modelChecker.printResults(); -} - -/*! - * Analyze the DFT with use of SMT solving. - * - * @param filename Path to DFT file in Galileo format. + * Process commandline options and start computations. */ template -void analyzeWithSMT(std::shared_ptr> dft) { - STORM_LOG_DEBUG("Running DFT analysis with use of SMT"); - storm::modelchecker::DFTASFChecker asfChecker(*dft); - asfChecker.convert(); - asfChecker.toFile("test.smt2"); - //bool sat = dftSmtBuilder.check(); - //std::cout << "SMT result: " << sat << std::endl; -} - void processOptions() { // Start by setting some urgent options (log levels, resources, etc.) storm::cli::setUrgentOptions(); storm::settings::modules::DftIOSettings const& dftIOSettings = storm::settings::getModule(); storm::settings::modules::FaultTreeSettings const& faultTreeSettings = storm::settings::getModule(); - storm::settings::modules::GeneralSettings const& generalSettings = storm::settings::getModule(); storm::settings::modules::IOSettings const& ioSettings = storm::settings::getModule(); + if (!dftIOSettings.isDftFileSet() && !dftIOSettings.isDftJsonFileSet()) { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No input model."); } + // Build DFT from given file + std::shared_ptr> dft; + if (dftIOSettings.isDftJsonFileSet()) { + STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftJsonFilename()); + dft = storm::api::loadDFTJsonFile(dftIOSettings.getDftJsonFilename()); + } else { + STORM_LOG_DEBUG("Loading DFT from file " << dftIOSettings.getDftFilename()); + dft = storm::api::loadDFTGalileoFile(dftIOSettings.getDftFilename()); + } + + if (dftIOSettings.isDisplayStatsSet()) { + std::cout << "=============DFT Statistics==============" << std::endl; + dft->writeStatsToStream(std::cout); + std::cout << "=========================================" << std::endl; + } + if (dftIOSettings.isExportToJson()) { - STORM_LOG_THROW(dftIOSettings.isDftFileSet(), storm::exceptions::InvalidSettingsException, "No input model in Galileo format given."); - std::shared_ptr> dft = loadDFT(); // Export to json - storm::storage::DftJsonExporter::toFile(*dft, dftIOSettings.getExportJsonFilename()); + storm::api::exportDFTToJsonFile(*dft, dftIOSettings.getExportJsonFilename()); return; } - if (dftIOSettings.isTransformToGspn()) { - std::shared_ptr> dft = loadDFT(); // Transform to GSPN - storm::transformations::dft::DftToGspnTransformator gspnTransformator(*dft); - bool smart = true; - gspnTransformator.transform(smart); - storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); - uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); - - storm::handleGSPNExportSettings(*gspn); - - std::shared_ptr const& exprManager = gspn->getExpressionManager(); - storm::builder::JaniGSPNBuilder builder(*gspn); - storm::jani::Model* model = builder.build(); - storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); - - storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); - auto evtlFormula = std::make_shared(targetExpression); - auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); - auto tbUntil = std::make_shared(tbFormula); - - auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); - auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); - - storm::settings::modules::JaniExportSettings const& janiSettings = storm::settings::getModule(); - if (janiSettings.isJaniFileSet()) { - storm::api::exportJaniModel(*model, {storm::jani::Property("time-bounded", tbUntil), storm::jani::Property("mttf", rewFormula)}, janiSettings.getJaniFilename()); - } - - delete model; - delete gspn; + storm::api::transformToGSPN(*dft); return; } - bool parametric = false; -#ifdef STORM_HAVE_CARL - parametric = generalSettings.isParametricSet(); -#endif - + #ifdef STORM_HAVE_Z3 if (faultTreeSettings.solveWithSMT()) { // Solve with SMT - if (parametric) { - // std::shared_ptr> dft = loadDFT(); - // analyzeWithSMT(dftSettings.getDftFilename()); - } else { - std::shared_ptr> dft = loadDFT(); - analyzeWithSMT(dft); - } + 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."); return; } #endif @@ -170,9 +74,8 @@ void processOptions() { optimizationDirection = "max"; } - // Construct properties to check for + // Construct properties to analyse std::vector properties; - if (ioSettings.isPropertySet()) { properties.push_back(ioSettings.getProperty()); } @@ -195,38 +98,31 @@ void processOptions() { } } - if (properties.empty()) { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "No property given."); + // Build properties + STORM_LOG_THROW(!properties.empty(), storm::exceptions::InvalidSettingsException, "No property given."); + std::string propString = properties[0]; + for (size_t i = 1; i < properties.size(); ++i) { + propString += ";" + properties[i]; } + std::vector> props = storm::api::extractFormulasFromProperties(storm::api::parseProperties(propString)); + STORM_LOG_ASSERT(props.size() > 0, "No properties found."); - // Set possible approximation error - double approximationError = 0.0; + // Carry out the actual analysis if (faultTreeSettings.isApproximationErrorSet()) { - approximationError = faultTreeSettings.getApproximationError(); - } - - // From this point on we are ready to carry out the actual computations. - if (parametric) { -#ifdef STORM_HAVE_CARL - analyzeDFT(properties, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); -#endif + // Approximate analysis + storm::api::analyzeDFTApprox(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), faultTreeSettings.getApproximationError(), true); } else { - analyzeDFT(properties, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), approximationError); + storm::api::analyzeDFT(*dft, props, faultTreeSettings.useSymmetryReduction(), faultTreeSettings.useModularisation(), !faultTreeSettings.isDisableDC(), true); } } /*! - * Entry point for the DyFTeE backend. + * Entry point for Storm-DFT. * * @param argc The argc argument of main(). * @param argv The argv argument of main(). * @return Return code, 0 if successfull, not 0 otherwise. */ -/*! - * Main entry point of the executable storm-pars. - */ int main(const int argc, const char** argv) { try { storm::utility::setUp(); @@ -238,7 +134,12 @@ int main(const int argc, const char** argv) { return -1; } - processOptions(); + storm::settings::modules::GeneralSettings const& generalSettings = storm::settings::getModule(); + if (generalSettings.isParametricSet()) { + processOptions(); + } else { + processOptions(); + } totalTimer.stop(); if (storm::settings::getModule().isPrintTimeAndMemorySet()) { @@ -249,10 +150,10 @@ int main(const int argc, const char** argv) { storm::utility::cleanUp(); return 0; } catch (storm::exceptions::BaseException const& exception) { - STORM_LOG_ERROR("An exception caused Storm-DyFTeE to terminate. The message of the exception is: " << exception.what()); + STORM_LOG_ERROR("An exception caused Storm-DFT to terminate. The message of the exception is: " << exception.what()); return 1; } catch (std::exception const& exception) { - STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-DyFTeE to terminate. The message of this exception is: " << exception.what()); + STORM_LOG_ERROR("An unexpected exception occurred and caused Storm-DFT to terminate. The message of this exception is: " << exception.what()); return 2; } } diff --git a/src/storm-dft/CMakeLists.txt b/src/storm-dft/CMakeLists.txt index 9ec70aed2..48a046238 100644 --- a/src/storm-dft/CMakeLists.txt +++ b/src/storm-dft/CMakeLists.txt @@ -17,7 +17,7 @@ set_target_properties(storm-dft PROPERTIES DEFINE_SYMBOL "") list(APPEND STORM_TARGETS storm-dft) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-dft PUBLIC storm storm-gspn ${STORM_DFT_LINK_LIBRARIES}) +target_link_libraries(storm-dft PUBLIC storm storm-gspn storm-parsers ${STORM_DFT_LINK_LIBRARIES}) # Install storm headers to include directory. foreach(HEADER ${STORM_DFT_HEADERS}) @@ -36,5 +36,5 @@ add_custom_target(copy_storm_dft_headers DEPENDS ${STORM_DFT_OUTPUT_HEADERS} ${S add_dependencies(storm-dft copy_storm_dft_headers) # installation -install(TARGETS storm-dft RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-dft EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-dft/api/storm-dft.cpp b/src/storm-dft/api/storm-dft.cpp new file mode 100644 index 000000000..b8794372c --- /dev/null +++ b/src/storm-dft/api/storm-dft.cpp @@ -0,0 +1,74 @@ +#include "storm-dft/api/storm-dft.h" + +namespace storm { + namespace api { + + template<> + void exportDFTToJsonFile(storm::storage::DFT const& dft, std::string const& file) { + storm::storage::DftJsonExporter::toFile(dft, file); + } + + template<> + void exportDFTToJsonFile(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); + } + + template<> + std::string exportDFTToJsonString(storm::storage::DFT const& dft) { + std::stringstream stream; + storm::storage::DftJsonExporter::toStream(dft, stream); + return stream.str(); + } + + template<> + std::string exportDFTToJsonString(storm::storage::DFT const& dft) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to JSON not supported for this data type."); + } + + template<> + void exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { + storm::modelchecker::DFTASFChecker asfChecker(dft); + asfChecker.convert(); + asfChecker.toFile(file); + } + + template<> + void exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Export to SMT does not support this data type."); + } + + template<> + void transformToGSPN(storm::storage::DFT const& dft) { + // Transform to GSPN + storm::transformations::dft::DftToGspnTransformator gspnTransformator(dft); + bool smart = true; + gspnTransformator.transform(smart); + storm::gspn::GSPN* gspn = gspnTransformator.obtainGSPN(); + uint64_t toplevelFailedPlace = gspnTransformator.toplevelFailedPlaceId(); + + storm::api::handleGSPNExportSettings(*gspn, [&](storm::builder::JaniGSPNBuilder const& builder) { + std::shared_ptr const& exprManager = gspn->getExpressionManager(); + storm::jani::Variable const& topfailedVar = builder.getPlaceVariable(toplevelFailedPlace); + + storm::expressions::Expression targetExpression = exprManager->integer(1) == topfailedVar.getExpressionVariable().getExpression(); + auto evtlFormula = std::make_shared(targetExpression); + auto tbFormula = std::make_shared(std::make_shared(true), evtlFormula, storm::logic::TimeBound(false, exprManager->integer(0)), storm::logic::TimeBound(false, exprManager->integer(10)), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); + auto tbUntil = std::make_shared(tbFormula); + + auto evFormula = std::make_shared(evtlFormula, storm::logic::FormulaContext::Time); + auto rewFormula = std::make_shared(evFormula, storm::logic::OperatorInformation(), storm::logic::RewardMeasureType::Expectation); + std::vector res({storm::jani::Property("time-bounded", tbUntil, {}), storm::jani::Property("mttf", rewFormula, {})}); + return res; + } + ); + + delete gspn; + } + + template<> + void transformToGSPN(storm::storage::DFT const& dft) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation to GSPN not supported for this data type."); + } + + } +} diff --git a/src/storm-dft/api/storm-dft.h b/src/storm-dft/api/storm-dft.h new file mode 100644 index 000000000..ec4e7166a --- /dev/null +++ b/src/storm-dft/api/storm-dft.h @@ -0,0 +1,138 @@ +#pragma once + +#include + +#include "storm-dft/parser/DFTGalileoParser.h" +#include "storm-dft/parser/DFTJsonParser.h" +#include "storm-dft/storage/dft/DftJsonExporter.h" + +#include "storm-dft/modelchecker/dft/DFTModelChecker.h" +#include "storm-dft/modelchecker/dft/DFTASFChecker.h" + +#include "storm-dft/transformations/DftToGspnTransformator.h" +#include "storm-gspn/api/storm-gspn.h" + +namespace storm { + namespace api { + + /*! + * Load DFT from Galileo file. + * + * @param file File containing DFT description in Galileo format. + * + * @return DFT. + */ + template + std::shared_ptr> loadDFTGalileoFile(std::string const& file) { + return std::make_shared>(storm::parser::DFTGalileoParser::parseDFT(file)); + } + + /*! + * Load DFT from JSON string. + * + * @param jsonString String containing DFT description in JSON format. + * + * @return DFT. + */ + template + std::shared_ptr> loadDFTJsonString(std::string const& jsonString) { + storm::parser::DFTJsonParser parser; + return std::make_shared>(parser.parseJsonFromString(jsonString)); + } + + /*! + * Load DFT from JSON file. + * + * @param file File containing DFT description in JSON format. + * + * @return DFT. + */ + template + std::shared_ptr> loadDFTJsonFile(std::string const& file) { + storm::parser::DFTJsonParser parser; + return std::make_shared>(parser.parseJsonFromFile(file)); + } + + /*! + * Analyse the given DFT according to the given properties. + * First the Markov model is built from the DFT and then this model is checked against the given properties. + * + * @param dft DFT. + * @param properties PCTL formulas capturing the properties to check. + * @param symred Flag whether symmetry reduction should be used. + * @param allowModularisation Flag whether modularisation should be applied if possible. + * @param enableDC Flag whether Don't Care propagation should be used. + * + * @return Result. + */ + template + typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFT(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, bool printOutput) { + storm::modelchecker::DFTModelChecker modelChecker; + typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, 0.0); + if (printOutput) { + modelChecker.printTimings(); + modelChecker.printResults(); + } + return results; + } + + /*! + * Approximate the analysis result of the given DFT according to the given properties. + * First the Markov model is built from the DFT and then this model is checked against the given properties. + * + * @param dft DFT. + * @param properties PCTL formulas capturing the properties to check. + * @param symred Flag whether symmetry reduction should be used. + * @param allowModularisation Flag whether modularisation should be applied if possible. + * @param enableDC Flag whether Don't Care propagation should be used. + * @param approximationError Allowed approximation error. + * + * @return Result. + */ + template + typename storm::modelchecker::DFTModelChecker::dft_results analyzeDFTApprox(storm::storage::DFT const& dft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError, bool printOutput) { + storm::modelchecker::DFTModelChecker modelChecker; + typename storm::modelchecker::DFTModelChecker::dft_results results = modelChecker.check(dft, properties, symred, allowModularisation, enableDC, approximationError); + if (printOutput) { + modelChecker.printTimings(); + modelChecker.printResults(); + } + return results; + } + + /*! + * Export DFT to JSON file. + * + * @param dft DFT. + * @param file File. + */ + template + void exportDFTToJsonFile(storm::storage::DFT const& dft, std::string const& file); + + /*! + * Export DFT to JSON string. + * + * @param dft DFT. + */ + template + std::string exportDFTToJsonString(storm::storage::DFT const& dft); + + /*! + * Export DFT to SMT encoding. + * + * @param dft DFT. + * @param file File. + */ + template + void exportDFTToSMT(storm::storage::DFT const& dft, std::string const& file); + + /*! + * Transform DFT to GSPN. + * + * @param dft DFT. + */ + template + void transformToGSPN(storm::storage::DFT const& dft); + + } +} diff --git a/src/storm-dft/storage/dft/DFTBuilder.cpp b/src/storm-dft/builder/DFTBuilder.cpp similarity index 73% rename from src/storm-dft/storage/dft/DFTBuilder.cpp rename to src/storm-dft/builder/DFTBuilder.cpp index 88abc9665..a333c3cd6 100644 --- a/src/storm-dft/storage/dft/DFTBuilder.cpp +++ b/src/storm-dft/builder/DFTBuilder.cpp @@ -11,15 +11,15 @@ namespace storm { - namespace storage { + namespace builder { template std::size_t DFTBuilder::mUniqueOffset = 0; template - DFT DFTBuilder::build() { + storm::storage::DFT DFTBuilder::build() { for(auto& elem : mChildNames) { - DFTGatePointer gate = std::static_pointer_cast>(elem.first); + DFTGatePointer gate = std::static_pointer_cast>(elem.first); for(auto const& child : elem.second) { auto itFind = mElements.find(child); if (itFind != mElements.end()) { @@ -54,16 +54,16 @@ namespace storm { for(auto& elem : mDependencyChildNames) { bool first = true; - std::vector>> dependencies; + std::vector>> dependencies; for(auto const& childName : elem.second) { auto itFind = mElements.find(childName); STORM_LOG_ASSERT(itFind != mElements.end(), "Child '" << childName << "' not found"); DFTElementPointer childElement = itFind->second; if (!first) { STORM_LOG_ASSERT(childElement->isBasicElement(), "Child '" << childName << "' of dependency '" << elem.first->name() << "' must be BE."); - dependencies.push_back(std::static_pointer_cast>(childElement)); + dependencies.push_back(std::static_pointer_cast>(childElement)); } else { - elem.first->setTriggerElement(std::static_pointer_cast>(childElement)); + elem.first->setTriggerElement(std::static_pointer_cast>(childElement)); childElement->addOutgoingDependency(elem.first); } first = false; @@ -92,7 +92,7 @@ namespace storm { } STORM_LOG_ASSERT(!mTopLevelIdentifier.empty(), "No top level element."); - DFT dft(elems, mElements[mTopLevelIdentifier]); + storm::storage::DFT dft(elems, mElements[mTopLevelIdentifier]); // Set layout info for (auto& elem : mElements) { @@ -113,7 +113,7 @@ namespace storm { if(elem->nrChildren() == 0 || elem->isDependency()) { elem->setRank(0); } else { - DFTGatePointer gate = std::static_pointer_cast>(elem); + DFTGatePointer gate = std::static_pointer_cast>(elem); unsigned maxrnk = 0; unsigned newrnk = 0; @@ -131,7 +131,7 @@ namespace storm { } template - bool DFTBuilder::addRestriction(std::string const& name, std::vector const& children, DFTElementType tp) { + bool DFTBuilder::addRestriction(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp) { if (children.size() <= 1) { STORM_LOG_ERROR("Sequence enforcers require at least two children"); } @@ -140,10 +140,10 @@ namespace storm { } DFTRestrictionPointer restr; switch (tp) { - case DFTElementType::SEQ: - restr = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::SEQ: + restr = std::make_shared>(mNextId++, name); break; - case DFTElementType::MUTEX: + case storm::storage::DFTElementType::MUTEX: // TODO notice that mutex state generation support is lacking anyway, as DONT CARE propagation would be broken for this. STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not supported."); break; @@ -159,7 +159,7 @@ namespace storm { } template - bool DFTBuilder::addStandardGate(std::string const& name, std::vector const& children, DFTElementType tp) { + bool DFTBuilder::addStandardGate(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp) { STORM_LOG_ASSERT(children.size() > 0, "No child for " << name); if(mElements.count(name) != 0) { // Element with that name already exists. @@ -167,28 +167,28 @@ namespace storm { } DFTElementPointer element; switch(tp) { - case DFTElementType::AND: - element = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::AND: + element = std::make_shared>(mNextId++, name); break; - case DFTElementType::OR: - element = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::OR: + element = std::make_shared>(mNextId++, name); break; - case DFTElementType::PAND: - element = std::make_shared>(mNextId++, name, pandDefaultInclusive); + case storm::storage::DFTElementType::PAND: + element = std::make_shared>(mNextId++, name, pandDefaultInclusive); break; - case DFTElementType::POR: - element = std::make_shared>(mNextId++, name, porDefaultInclusive); + case storm::storage::DFTElementType::POR: + element = std::make_shared>(mNextId++, name, porDefaultInclusive); break; - case DFTElementType::SPARE: - element = std::make_shared>(mNextId++, name); + case storm::storage::DFTElementType::SPARE: + element = std::make_shared>(mNextId++, name); break; - case DFTElementType::BE: - case DFTElementType::VOT: - case DFTElementType::PDEP: + case storm::storage::DFTElementType::BE: + case storm::storage::DFTElementType::VOT: + case storm::storage::DFTElementType::PDEP: // Handled separately STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type handled separately."); - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case storm::storage::DFTElementType::CONSTF: + case storm::storage::DFTElementType::CONSTS: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not supported."); default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Gate type not known."); @@ -199,29 +199,29 @@ namespace storm { } template - void DFTBuilder::topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L) { + void DFTBuilder::topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L) { if(visited[n] == topoSortColour::GREY) { throw storm::exceptions::WrongFormatException("DFT is cyclic"); } else if(visited[n] == topoSortColour::WHITE) { if(n->isGate()) { visited[n] = topoSortColour::GREY; - for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { + for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { topoVisit(c, visited, L); } } // TODO restrictions and dependencies have no parents, so this can be done more efficiently. if(n->isRestriction()) { visited[n] = topoSortColour::GREY; - for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { + for (DFTElementPointer const& c : std::static_pointer_cast>(n)->children()) { topoVisit(c, visited, L); } } if(n->isDependency()) { visited[n] = topoSortColour::GREY; - for (DFTElementPointer const& c : std::static_pointer_cast>(n)->dependentEvents()) { + for (DFTElementPointer const& c : std::static_pointer_cast>(n)->dependentEvents()) { topoVisit(c, visited, L); } - topoVisit(std::static_pointer_cast>(n)->triggerEvent(), visited, L); + topoVisit(std::static_pointer_cast>(n)->triggerEvent(), visited, L); } visited[n] = topoSortColour::BLACK; L.push_back(n); @@ -229,8 +229,8 @@ namespace storm { } template - std::vector>> DFTBuilder::topoSort() { - std::map> visited; + std::vector>> DFTBuilder::topoSort() { + std::map> visited; for(auto const& e : mElements) { visited.insert(std::make_pair(e.second, topoSortColour::WHITE)); } @@ -252,22 +252,22 @@ namespace storm { void DFTBuilder::copyElement(DFTElementPointer element) { std::vector children; switch (element->type()) { - case DFTElementType::AND: - case DFTElementType::OR: - case DFTElementType::PAND: - case DFTElementType::POR: - case DFTElementType::SPARE: - case DFTElementType::VOT: + case storm::storage::DFTElementType::AND: + case storm::storage::DFTElementType::OR: + case storm::storage::DFTElementType::PAND: + case storm::storage::DFTElementType::POR: + case storm::storage::DFTElementType::SPARE: + case storm::storage::DFTElementType::VOT: { - for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { + for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { children.push_back(elem->name()); } - copyGate(std::static_pointer_cast>(element), children); + copyGate(std::static_pointer_cast>(element), children); break; } - case DFTElementType::BE: + case storm::storage::DFTElementType::BE: { - std::shared_ptr> be = std::static_pointer_cast>(element); + std::shared_ptr> be = std::static_pointer_cast>(element); ValueType dormancyFactor = storm::utility::zero(); if (be->canFail()) { dormancyFactor = be->passiveFailureRate() / be->activeFailureRate(); @@ -275,14 +275,14 @@ namespace storm { addBasicElement(be->name(), be->activeFailureRate(), dormancyFactor, be->isTransient()); break; } - case DFTElementType::CONSTF: - case DFTElementType::CONSTS: + case storm::storage::DFTElementType::CONSTF: + case storm::storage::DFTElementType::CONSTS: // TODO STORM_LOG_ASSERT(false, "Const elements not supported."); break; - case DFTElementType::PDEP: + case storm::storage::DFTElementType::PDEP: { - DFTDependencyPointer dependency = std::static_pointer_cast>(element); + DFTDependencyPointer dependency = std::static_pointer_cast>(element); children.push_back(dependency->triggerEvent()->name()); for(auto const& depEv : dependency->dependentEvents()) { children.push_back(depEv->name()); @@ -290,10 +290,10 @@ namespace storm { addDepElement(element->name(), children, dependency->probability()); break; } - case DFTElementType::SEQ: - case DFTElementType::MUTEX: + case storm::storage::DFTElementType::SEQ: + case storm::storage::DFTElementType::MUTEX: { - for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { + for (DFTElementPointer const& elem : std::static_pointer_cast>(element)->children()) { children.push_back(elem->name()); } addRestriction(element->name(), children, element->type()); @@ -308,15 +308,15 @@ namespace storm { template void DFTBuilder::copyGate(DFTGatePointer gate, std::vector const& children) { switch (gate->type()) { - case DFTElementType::AND: - case DFTElementType::OR: - case DFTElementType::PAND: - case DFTElementType::POR: - case DFTElementType::SPARE: + case storm::storage::DFTElementType::AND: + case storm::storage::DFTElementType::OR: + case storm::storage::DFTElementType::PAND: + case storm::storage::DFTElementType::POR: + case storm::storage::DFTElementType::SPARE: addStandardGate(gate->name(), children, gate->type()); break; - case DFTElementType::VOT: - addVotElement(gate->name(), std::static_pointer_cast>(gate)->threshold(), children); + case storm::storage::DFTElementType::VOT: + addVotElement(gate->name(), std::static_pointer_cast>(gate)->threshold(), children); break; default: STORM_LOG_ASSERT(false, "Dft type not known."); diff --git a/src/storm-dft/storage/dft/DFTBuilder.h b/src/storm-dft/builder/DFTBuilder.h similarity index 81% rename from src/storm-dft/storage/dft/DFTBuilder.h rename to src/storm-dft/builder/DFTBuilder.h index 42713e601..625355371 100644 --- a/src/storm-dft/storage/dft/DFTBuilder.h +++ b/src/storm-dft/builder/DFTBuilder.h @@ -11,18 +11,22 @@ namespace storm { namespace storage { + // Forward declaration template class DFT; + } + + namespace builder { template class DFTBuilder { - using DFTElementPointer = std::shared_ptr>; + using DFTElementPointer = std::shared_ptr>; using DFTElementVector = std::vector; - using DFTGatePointer = std::shared_ptr>; + using DFTGatePointer = std::shared_ptr>; using DFTGateVector = std::vector; - using DFTDependencyPointer = std::shared_ptr>; - using DFTRestrictionPointer = std::shared_ptr>; + using DFTDependencyPointer = std::shared_ptr>; + using DFTRestrictionPointer = std::shared_ptr>; private: std::size_t mNextId = 0; @@ -34,7 +38,7 @@ namespace storm { std::unordered_map> mDependencyChildNames; std::vector mDependencies; std::vector mRestrictions; - std::unordered_map mLayoutInfo; + std::unordered_map mLayoutInfo; public: DFTBuilder(bool defaultInclusive = true, bool binaryDependencies = true) : pandDefaultInclusive(defaultInclusive), porDefaultInclusive(defaultInclusive), binaryDependencies(binaryDependencies) { @@ -42,47 +46,47 @@ namespace storm { } bool addAndElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::AND); + return addStandardGate(name, children, storm::storage::DFTElementType::AND); } bool addOrElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::OR); + return addStandardGate(name, children, storm::storage::DFTElementType::OR); } bool addPandElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::PAND); + return addStandardGate(name, children, storm::storage::DFTElementType::PAND); } bool addPandElement(std::string const& name, std::vector const& children, bool inclusive) { bool tmpDefault = pandDefaultInclusive; pandDefaultInclusive = inclusive; - bool result = addStandardGate(name, children, DFTElementType::PAND); + bool result = addStandardGate(name, children, storm::storage::DFTElementType::PAND); pandDefaultInclusive = tmpDefault; return result; } bool addPorElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::POR); + return addStandardGate(name, children, storm::storage::DFTElementType::POR); } bool addPorElement(std::string const& name, std::vector const& children, bool inclusive) { bool tmpDefault = porDefaultInclusive; porDefaultInclusive = inclusive; - bool result = addStandardGate(name, children, DFTElementType::POR); + bool result = addStandardGate(name, children, storm::storage::DFTElementType::POR); pandDefaultInclusive = tmpDefault; return result; } bool addSpareElement(std::string const& name, std::vector const& children) { - return addStandardGate(name, children, DFTElementType::SPARE); + return addStandardGate(name, children, storm::storage::DFTElementType::SPARE); } bool addSequenceEnforcer(std::string const& name, std::vector const& children) { - return addRestriction(name, children, DFTElementType::SEQ); + return addRestriction(name, children, storm::storage::DFTElementType::SEQ); } bool addMutex(std::string const& name, std::vector const& children) { - return addRestriction(name, children, DFTElementType::MUTEX); + return addRestriction(name, children, storm::storage::DFTElementType::MUTEX); } bool addDepElement(std::string const& name, std::vector const& children, ValueType probability) { @@ -125,15 +129,13 @@ namespace storm { } STORM_LOG_ASSERT(storm::utility::isOne(probability) || children.size() == 2, "PDep with multiple children supported."); - DFTDependencyPointer element = std::make_shared>(mNextId++, - nameDep, - probability); + DFTDependencyPointer element = std::make_shared>(mNextId++, nameDep, probability); mElements[element->name()] = element; mDependencyChildNames[element] = {trigger, children[i]}; mDependencies.push_back(element); } } else { - DFTDependencyPointer element = std::make_shared>(mNextId++, name, probability); + DFTDependencyPointer element = std::make_shared>(mNextId++, name, probability); mElements[element->name()] = element; mDependencyChildNames[element] = children; mDependencies.push_back(element); @@ -161,7 +163,7 @@ namespace storm { STORM_LOG_ERROR("Voting gates with threshold higher than the number of children is not supported."); return false; } - DFTElementPointer element = std::make_shared>(mNextId++, name, threshold); + DFTElementPointer element = std::make_shared>(mNextId++, name, threshold); mElements[name] = element; mChildNames[element] = children; @@ -173,7 +175,7 @@ namespace storm { //failureRate > 0 //0 <= dormancyFactor <= 1 - mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); + mElements[name] = std::make_shared>(mNextId++, name, failureRate, dormancyFactor, transient); return true; } @@ -189,7 +191,7 @@ namespace storm { std::string getUniqueName(std::string name); - DFT build(); + storm::storage::DFT build(); /** * Copy element and insert it again in the builder. @@ -211,13 +213,13 @@ namespace storm { unsigned computeRank(DFTElementPointer const& elem); - bool addStandardGate(std::string const& name, std::vector const& children, DFTElementType tp); + bool addStandardGate(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp); - bool addRestriction(std::string const& name, std::vector const& children, DFTElementType tp); + bool addRestriction(std::string const& name, std::vector const& children, storm::storage::DFTElementType tp); enum class topoSortColour {WHITE, BLACK, GREY}; - void topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L); + void topoVisit(DFTElementPointer const& n, std::map>& visited, DFTElementVector& L); DFTElementVector topoSort(); diff --git a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp index 82a566496..93e1170be 100644 --- a/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp +++ b/src/storm-dft/builder/ExplicitDFTModelBuilder.cpp @@ -58,7 +58,7 @@ namespace storm { usedHeuristic(storm::settings::getModule().getApproximationHeuristic()), generator(dft, *stateGenerationInfo, enableDC, mergeFailedStates), matrixBuilder(!generator.isDeterministicModel()), - stateStorage(((dft.stateVectorSize() / 64) + 1) * 64), + stateStorage(dft.stateBitVectorSize()), // TODO Matthias: make choosable //explorationQueue(dft.nrElements()+1, 0, 1) explorationQueue(200, 0, 0.9) diff --git a/src/storm-dft/modelchecker/dft/DFTASFChecker.h b/src/storm-dft/modelchecker/dft/DFTASFChecker.h index c4a47116d..a4337bb58 100644 --- a/src/storm-dft/modelchecker/dft/DFTASFChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTASFChecker.h @@ -33,13 +33,15 @@ namespace storm { } + friend bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) { + return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex); + } + + private: uint64_t spareIndex; uint64_t childIndex; }; - bool operator<(SpareAndChildPair const& p1, SpareAndChildPair const& p2) { - return p1.spareIndex < p2.spareIndex || (p1.spareIndex == p2.spareIndex && p1.childIndex < p2.childIndex); - } class DFTASFChecker { using ValueType = double; diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp index d2b435c1c..2a2a62e14 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.cpp @@ -1,9 +1,12 @@ #include "DFTModelChecker.h" #include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/builder/ParallelCompositionBuilder.h" #include "storm/utility/bitoperations.h" #include "storm/utility/DirectEncodingExporter.h" +#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm-dft/builder/ExplicitDFTModelBuilder.h" #include "storm-dft/storage/dft/DFTIsomorphism.h" @@ -14,7 +17,7 @@ namespace storm { namespace modelchecker { template - void DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { + typename DFTModelChecker::dft_results DFTModelChecker::check(storm::storage::DFT const& origDft, std::vector> const& properties, bool symred, bool allowModularisation, bool enableDC, double approximationError) { // Initialize this->approximationError = approximationError; totalTimer.start(); @@ -33,11 +36,11 @@ namespace storm { for (ValueType result : resultsValue) { checkResults.push_back(result); } - } else { checkResults = checkHelper(dft, properties, symred, allowModularisation, enableDC, approximationError); } totalTimer.stop(); + return checkResults; } template @@ -54,14 +57,14 @@ namespace storm { case storm::storage::DFTElementType::AND: STORM_LOG_TRACE("top modularisation called AND"); dfts = dft.topModularisation(); - STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules."); + STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules."); nrK = dfts.size(); nrM = dfts.size(); break; case storm::storage::DFTElementType::OR: STORM_LOG_TRACE("top modularisation called OR"); dfts = dft.topModularisation(); - STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules."); + STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules."); nrK = 0; nrM = dfts.size(); invResults = true; @@ -69,7 +72,7 @@ namespace storm { case storm::storage::DFTElementType::VOT: STORM_LOG_TRACE("top modularisation called VOT"); dfts = dft.topModularisation(); - STORM_LOG_TRACE("Modularsation into " << dfts.size() << " submodules."); + STORM_LOG_TRACE("Modularisation into " << dfts.size() << " submodules."); nrK = std::static_pointer_cast const>(dft.getTopLevelGate())->threshold(); nrM = dfts.size(); if(nrK <= nrM/2) { @@ -107,7 +110,7 @@ namespace storm { int limK = invResults ? -1 : nrM+1; int chK = invResults ? -1 : 1; // WARNING: there is a bug for computing permutations with more than 32 elements - STORM_LOG_ASSERT(res.size() < 32, "Permutations work only for < 32 elements"); + STORM_LOG_THROW(res.size() < 32, storm::exceptions::NotSupportedException, "Permutations work only for < 32 elements"); for(int cK = nrK; cK != limK; cK += chK ) { STORM_LOG_ASSERT(cK >= 0, "ck negative."); size_t permutation = smallestIntWithNBitsSet(static_cast(cK)); @@ -176,7 +179,7 @@ namespace storm { bool firstTime = true; std::shared_ptr> composedModel; for (auto const ft : dfts) { - STORM_LOG_INFO("Building Model via parallel composition..."); + STORM_LOG_DEBUG("Building Model via parallel composition..."); explorationTimer.start(); // Find symmetries @@ -185,12 +188,12 @@ namespace storm { if(symred) { auto colouring = ft.colourDFT(); symmetries = ft.findSymmetries(colouring); - STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries."); + STORM_LOG_DEBUG("Found " << symmetries.groups.size() << " symmetries."); STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries); } // Build a single CTMC - STORM_LOG_INFO("Building Model..."); + STORM_LOG_DEBUG("Building Model..."); storm::builder::ExplicitDFTModelBuilder builder(ft, symmetries, enableDC); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); builder.buildModel(labeloptions, 0, 0.0); @@ -226,7 +229,7 @@ namespace storm { } } - composedModel->printModelInformationToStream(std::cout); + //composedModel->printModelInformationToStream(std::cout); return composedModel; } else { // No composition was possible @@ -237,17 +240,17 @@ namespace storm { if(symred) { auto colouring = dft.colourDFT(); symmetries = dft.findSymmetries(colouring); - STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries."); + STORM_LOG_DEBUG("Found " << symmetries.groups.size() << " symmetries."); STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries); } // Build a single CTMC - STORM_LOG_INFO("Building Model..."); + STORM_LOG_DEBUG("Building Model..."); storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); - model->printModelInformationToStream(std::cout); + //model->printModelInformationToStream(std::cout); explorationTimer.stop(); STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Ctmc), storm::exceptions::NotSupportedException, "Parallel composition only applicable for CTMCs"); return model->template as>(); @@ -264,7 +267,7 @@ namespace storm { if(symred) { auto colouring = dft.colourDFT(); symmetries = dft.findSymmetries(colouring); - STORM_LOG_INFO("Found " << symmetries.groups.size() << " symmetries."); + STORM_LOG_DEBUG("Found " << symmetries.groups.size() << " symmetries."); STORM_LOG_TRACE("Symmetries: " << std::endl << symmetries); } @@ -292,7 +295,7 @@ namespace storm { if (iteration > 0) { explorationTimer.start(); } - STORM_LOG_INFO("Building model..."); + STORM_LOG_DEBUG("Building model..."); // TODO Matthias refine model using existing model and MC results builder.buildModel(labeloptions, iteration, approximationError); explorationTimer.stop(); @@ -301,10 +304,10 @@ namespace storm { // TODO Matthias: possible to do bisimulation on approximated model and not on concrete one? // Build model for lower bound - STORM_LOG_INFO("Getting model for lower bound..."); + STORM_LOG_DEBUG("Getting model for lower bound..."); model = builder.getModelApproximation(true, !probabilityFormula); // We only output the info from the lower bound as the info for the upper bound is the same - model->printModelInformationToStream(std::cout); + //model->printModelInformationToStream(std::cout); buildingTimer.stop(); // Check lower bounds @@ -314,7 +317,7 @@ namespace storm { approxResult.first = newResult[0]; // Build model for upper bound - STORM_LOG_INFO("Getting model for upper bound..."); + STORM_LOG_DEBUG("Getting model for upper bound..."); buildingTimer.start(); model = builder.getModelApproximation(false, !probabilityFormula); buildingTimer.stop(); @@ -326,25 +329,25 @@ namespace storm { ++iteration; STORM_LOG_ASSERT(comparator.isLess(approxResult.first, approxResult.second) || comparator.isEqual(approxResult.first, approxResult.second), "Under-approximation " << approxResult.first << " is greater than over-approximation " << approxResult.second); - STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")"); + //STORM_LOG_INFO("Result after iteration " << iteration << ": (" << std::setprecision(10) << approxResult.first << ", " << approxResult.second << ")"); totalTimer.stop(); printTimings(); totalTimer.start(); STORM_LOG_THROW(!storm::utility::isInfinity(approxResult.first) && !storm::utility::isInfinity(approxResult.second), storm::exceptions::NotSupportedException, "Approximation does not work if result might be infinity."); } while (!isApproximationSufficient(approxResult.first, approxResult.second, approximationError, probabilityFormula)); - STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : ".")); + //STORM_LOG_INFO("Finished approximation after " << iteration << " iteration" << (iteration > 1 ? "s." : ".")); dft_results results; results.push_back(approxResult); return results; } else { // Build a single Markov Automaton - STORM_LOG_INFO("Building Model..."); + STORM_LOG_DEBUG("Building Model..."); storm::builder::ExplicitDFTModelBuilder builder(dft, symmetries, enableDC); typename storm::builder::ExplicitDFTModelBuilder::LabelOptions labeloptions(properties, storm::settings::getModule().isExportExplicitSet()); builder.buildModel(labeloptions, 0, 0.0); std::shared_ptr> model = builder.getModel(); - model->printModelInformationToStream(std::cout); + //model->printModelInformationToStream(std::cout); explorationTimer.stop(); // Export the model if required @@ -373,15 +376,15 @@ namespace storm { // Bisimulation if (model->isOfType(storm::models::ModelType::Ctmc) && storm::settings::getModule().isBisimulationSet()) { bisimulationTimer.start(); - STORM_LOG_INFO("Bisimulation..."); + STORM_LOG_DEBUG("Bisimulation..."); model = storm::api::performDeterministicSparseBisimulationMinimization>(model->template as>(), properties, storm::storage::BisimulationType::Weak)->template as>(); - STORM_LOG_INFO("No. states (Bisimulation): " << model->getNumberOfStates()); - STORM_LOG_INFO("No. transitions (Bisimulation): " << model->getNumberOfTransitions()); + STORM_LOG_DEBUG("No. states (Bisimulation): " << model->getNumberOfStates()); + STORM_LOG_DEBUG("No. transitions (Bisimulation): " << model->getNumberOfTransitions()); bisimulationTimer.stop(); } // Check the model - STORM_LOG_INFO("Model checking..."); + STORM_LOG_DEBUG("Model checking..."); modelCheckingTimer.start(); std::vector results; @@ -390,18 +393,18 @@ namespace storm { for (auto property : properties) { singleModelCheckingTimer.reset(); singleModelCheckingTimer.start(); - STORM_PRINT_AND_LOG("Model checking property " << *property << " ..." << std::endl); + //STORM_PRINT_AND_LOG("Model checking property " << *property << " ..." << std::endl); std::unique_ptr result(storm::api::verifyWithSparseEngine(model, storm::api::createTask(property, true))); STORM_LOG_ASSERT(result, "Result does not exist."); result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); ValueType resultValue = result->asExplicitQuantitativeCheckResult().getValueMap().begin()->second; - STORM_PRINT_AND_LOG("Result (initial states): " << resultValue << std::endl); + //STORM_PRINT_AND_LOG("Result (initial states): " << resultValue << std::endl); results.push_back(resultValue); singleModelCheckingTimer.stop(); - STORM_PRINT_AND_LOG("Time for model checking: " << singleModelCheckingTimer << "." << std::endl); + //STORM_PRINT_AND_LOG("Time for model checking: " << singleModelCheckingTimer << "." << std::endl); } modelCheckingTimer.stop(); - STORM_LOG_INFO("Model checking done."); + STORM_LOG_DEBUG("Model checking done."); return results; } diff --git a/src/storm-dft/modelchecker/dft/DFTModelChecker.h b/src/storm-dft/modelchecker/dft/DFTModelChecker.h index 597feb3cb..6da5d5aaa 100644 --- a/src/storm-dft/modelchecker/dft/DFTModelChecker.h +++ b/src/storm-dft/modelchecker/dft/DFTModelChecker.h @@ -17,12 +17,11 @@ namespace storm { template class DFTModelChecker { + public: typedef std::pair approximation_result; typedef std::vector> dft_results; typedef std::vector> property_vector; - public: - /*! * Constructor. */ @@ -38,8 +37,10 @@ namespace storm { * @param allowModularisation Flag indication if modularisation is allowed * @param enableDC Flag indicating if dont care propagation should be used * @param approximationError Error allowed for approximation. Value 0 indicates no approximation + * + * @return Model checking results for the given properties. */ - void check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0); + dft_results check(storm::storage::DFT const& origDft, property_vector const& properties, bool symred = true, bool allowModularisation = true, bool enableDC = true, double approximationError = 0.0); /*! * Print timings of all operations to stream. diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index c81c2767a..94ef80c67 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -2,12 +2,14 @@ #include #include +#include + #include -#include #include #include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/WrongFormatException.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -15,156 +17,229 @@ namespace storm { namespace parser { template - storm::storage::DFT DFTGalileoParser::parseDFT(const std::string& filename) { - readFile(filename); - storm::storage::DFT dft = builder.build(); - STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString()); - STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); - return dft; - } - - template - std::string DFTGalileoParser::stripQuotsFromName(std::string const& name) { + std::string DFTGalileoParser::parseName(std::string const& name) { size_t firstQuots = name.find("\""); size_t secondQuots = name.find("\"", firstQuots+1); + std::string parsedName; - if(firstQuots == std::string::npos) { - return name; + if (firstQuots == std::string::npos) { + parsedName = name; } else { - STORM_LOG_THROW(secondQuots != std::string::npos, storm::exceptions::FileIoException, "No ending quotation mark found in " << name); - return name.substr(firstQuots+1,secondQuots-1); + STORM_LOG_THROW(secondQuots != std::string::npos, storm::exceptions::WrongFormatException, "No ending quotation mark found in " << name); + parsedName = name.substr(firstQuots+1,secondQuots-1); } - } - - template - std::string DFTGalileoParser::parseNodeIdentifier(std::string const& name) { - return boost::replace_all_copy(name, "'", "__prime__"); + return boost::replace_all_copy(parsedName, "'", "__prime__"); } template - void DFTGalileoParser::readFile(const std::string& filename) { - // constants - std::string toplevelToken = "toplevel"; - std::string toplevelId; - std::string parametricToken = "param"; + storm::storage::DFT DFTGalileoParser::parseDFT(const std::string& filename, bool defaultInclusive, bool binaryDependencies) { + storm::builder::DFTBuilder builder(defaultInclusive, binaryDependencies); + ValueParser valueParser; + // Regular expression to detect comments + // taken from: https://stackoverflow.com/questions/9449887/removing-c-c-style-comments-using-boostregex + const std::regex commentRegex("(/\\*([^*]|(\\*+[^*/]))*\\*+/)|(//.*)"); std::ifstream file; storm::utility::openFile(filename, file); + std::string line; + size_t lineNo = 0; + std::string toplevelId = ""; + bool comment = false; // Indicates whether the current line is part of a multiline comment while (std::getline(file, line)) { - bool success = true; - STORM_LOG_TRACE("Parsing: " << line); - size_t commentstarts = line.find("//"); - line = line.substr(0, commentstarts); - size_t firstsemicolon = line.find(";"); - line = line.substr(0, firstsemicolon); - if (line.find_first_not_of(' ') == std::string::npos) { - // Only whitespace - continue; + ++lineNo; + // First consider comments + if (comment) { + // Line is part of multiline comment -> search for end of this comment + size_t commentEnd = line.find("*/"); + if (commentEnd == std::string::npos) { + continue; + } else { + // Remove comment + line = line.substr(commentEnd + 2); + comment = false; + } + } + // Remove comments + line = std::regex_replace(line, commentRegex, ""); + // Check if multiline comment starts + size_t commentStart = line.find("/*"); + if (commentStart != std::string::npos) { + // Remove comment + line = line.substr(0, commentStart); + comment = true; } - // Top level indicator. - if(boost::starts_with(line, toplevelToken)) { - toplevelId = stripQuotsFromName(line.substr(toplevelToken.size() + 1)); + boost::trim(line); + if (line.empty()) { + // Empty line + continue; } - else if (boost::starts_with(line, parametricToken)) { -#ifdef STORM_HAVE_CARL + + // Remove semicolon + STORM_LOG_THROW(line.back() == ';', storm::exceptions::WrongFormatException, "Semicolon expected at the end of line " << lineNo << "."); + line.pop_back(); + + // Split line into tokens + boost::trim(line); + std::vector tokens; + boost::split(tokens, line, boost::is_any_of(" \t"), boost::token_compress_on); + + if (tokens[0] == "toplevel") { + // Top level indicator + STORM_LOG_THROW(toplevelId == "", storm::exceptions::WrongFormatException, "Toplevel element already defined."); + STORM_LOG_THROW(tokens.size() == 2, storm::exceptions::WrongFormatException, "Expected element id after 'toplevel' in line " << lineNo << "."); + toplevelId = parseName(tokens[1]); + } else if (tokens[0] == "param") { + // Parameters + STORM_LOG_THROW(tokens.size() == 2, storm::exceptions::WrongFormatException, "Expected parameter name after 'param' in line " << lineNo << "."); STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - std::string parameter = stripQuotsFromName(line.substr(parametricToken.size() + 1)); - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser.setIdentifierMapping(identifierMapping); - STORM_LOG_TRACE("Added parameter: " << var.getName()); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); -#endif + valueParser.addParameter(parseName(tokens[1])); } else { - std::vector tokens; - boost::split(tokens, line, boost::is_any_of(" ")); - std::string name(parseNodeIdentifier(stripQuotsFromName(tokens[0]))); + // DFT element + std::string name = parseName(tokens[0]); std::vector childNames; for(unsigned i = 2; i < tokens.size(); ++i) { - childNames.push_back(parseNodeIdentifier(stripQuotsFromName(tokens[i]))); + childNames.push_back(parseName(tokens[i])); } - if(tokens[1] == "and") { + bool success = true; + + // Add element according to type + std::string type = tokens[1]; + if (type == "and") { success = builder.addAndElement(name, childNames); - } else if (tokens[1] == "or") { + } else if (type == "or") { success = builder.addOrElement(name, childNames); - } else if (boost::starts_with(tokens[1], "vot")) { - success = builder.addVotElement(name, boost::lexical_cast(tokens[1].substr(3)), childNames); - } else if (tokens[1].find("of") != std::string::npos) { - size_t pos = tokens[1].find("of"); - unsigned threshold = boost::lexical_cast(tokens[1].substr(0, pos)); - unsigned count = boost::lexical_cast(tokens[1].substr(pos + 2)); - STORM_LOG_THROW(count == childNames.size(), storm::exceptions::FileIoException, "Voting gate does not correspond to number of children."); + } else if (boost::starts_with(type, "vot")) { + unsigned threshold = NumberParser::parse(type.substr(3)); + success = builder.addVotElement(name, threshold, childNames); + } else if (type.find("of") != std::string::npos) { + size_t pos = type.find("of"); + unsigned threshold = NumberParser::parse(type.substr(0, pos)); + unsigned count = NumberParser::parse(type.substr(pos + 2)); + STORM_LOG_THROW(count == childNames.size(), storm::exceptions::WrongFormatException, "Voting gate number " << count << " does not correspond to number of children " << childNames.size() << "in line " << lineNo << "."); success = builder.addVotElement(name, threshold, childNames); - } else if (tokens[1] == "pand") { - success = builder.addPandElement(name, childNames); - } else if (tokens[1] == "pand-inc") { + } else if (type == "pand") { + success = builder.addPandElement(name, childNames, defaultInclusive); + } else if (type == "pand-inc") { success = builder.addPandElement(name, childNames, true); - } else if (tokens[1] == "pand-ex") { + } else if (type == "pand-ex") { success = builder.addPandElement(name, childNames, false); - } else if (tokens[1] == "por") { - success = builder.addPorElement(name, childNames); - } else if (tokens[1] == "por-ex") { + } else if (type == "por") { + success = builder.addPorElement(name, childNames, defaultInclusive); + } else if (type == "por-ex") { success = builder.addPorElement(name, childNames, false); - } else if (tokens[1] == "por-inc") { + } else if (type == "por-inc") { success = builder.addPorElement(name, childNames, true); - } else if (tokens[1] == "wsp" || tokens[1] == "csp") { + } else if (type == "wsp" || type == "csp" || type == "hsp") { success = builder.addSpareElement(name, childNames); - } else if (tokens[1] == "seq") { + } else if (type == "seq") { success = builder.addSequenceEnforcer(name, childNames); - } else if (tokens[1] == "fdep") { + } else if (type == "fdep") { + STORM_LOG_THROW(childNames.size() >= 2, storm::exceptions::WrongFormatException, "FDEP gate needs at least two children in line " << lineNo << "."); success = builder.addDepElement(name, childNames, storm::utility::one()); - } else if (boost::starts_with(tokens[1], "pdep=")) { - ValueType probability = parseRationalExpression(tokens[1].substr(5)); + } else if (boost::starts_with(type, "pdep=")) { + ValueType probability = valueParser.parseValue(type.substr(5)); success = builder.addDepElement(name, childNames, probability); - } else if (boost::starts_with(tokens[1], "lambda=")) { - ValueType failureRate = parseRationalExpression(tokens[1].substr(7)); - ValueType dormancyFactor = parseRationalExpression(tokens[2].substr(5)); - success = builder.addBasicElement(name, failureRate, dormancyFactor, false); // TODO set transient BEs + } else if (type.find("=") != std::string::npos) { + success = parseBasicElement(tokens, builder, valueParser); } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << tokens[1] << " not recognized."); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << type << " in line " << lineNo << " not recognized."); success = false; } - STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << name << "' of line '" << line << "'."); + STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << name << "' in line " << lineNo << "."); } } - if(!builder.setTopLevel(toplevelId)) { - STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id unknown."); + + if (!builder.setTopLevel(toplevelId)) { + STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id '" << toplevelId << "' unknown."); } storm::utility::closeFile(file); + + // Build DFT + storm::storage::DFT dft = builder.build(); + STORM_LOG_DEBUG("DFT Elements:" << std::endl << dft.getElementsString()); + STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); + return dft; } template - ValueType DFTGalileoParser::parseRationalExpression(std::string const& expr) { - STORM_LOG_ASSERT(false, "Specialized method should be called."); - return 0; - } + bool DFTGalileoParser::parseBasicElement(std::vector const& tokens, storm::builder::DFTBuilder& builder, ValueParser& valueParser) { + // Default values + Distribution distribution = Distribution::None; + ValueType firstValDistribution = storm::utility::zero(); + ValueType secondValDistribution = storm::utility::zero(); + ValueType dormancyFactor = storm::utility::one(); + size_t replication = 1; - template<> - double DFTGalileoParser::parseRationalExpression(std::string const& expr) { - return boost::lexical_cast(expr); - } + // Parse properties and determine distribution + for (size_t i = 1; i < tokens.size(); ++i) { + std::string token = tokens[i]; + if (boost::starts_with(token, "prob=")) { + STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(5)); + distribution = Distribution::Constant; + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); + } else if (boost::starts_with(token, "lambda=")) { + STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(7)); + distribution = Distribution::Exponential; + } else if (boost::starts_with(token, "rate=")) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(5)); + distribution = Distribution::Weibull; + } else if (boost::starts_with(token, "shape=")) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + secondValDistribution = valueParser.parseValue(token.substr(6)); + distribution = Distribution::Weibull; + } else if (boost::starts_with(token, "mean=")) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = valueParser.parseValue(token.substr(5)); + distribution = Distribution::LogNormal; + } else if (boost::starts_with(token, "stddev=")) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + secondValDistribution = valueParser.parseValue(token.substr(7)); + distribution = Distribution::LogNormal; + } else if (boost::starts_with(token, "cov=")) { + STORM_LOG_WARN("Coverage is not supported and will be ignored."); + } else if (boost::starts_with(token, "res=")) { + STORM_LOG_WARN("Restoration is not supported and will be ignored."); + } else if (boost::starts_with(token, "repl=")) { + replication = NumberParser::parse(token.substr(5)); + STORM_LOG_THROW(replication == 1, storm::exceptions::NotSupportedException, "Replication > 1 is not supported."); + } else if (boost::starts_with(token, "dorm=")) { + dormancyFactor = valueParser.parseValue(token.substr(5)); + } + } - // Explicitly instantiate the class. - template class DFTGalileoParser; + switch (distribution) { + case Constant: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); + break; + case Exponential: + return builder.addBasicElement(parseName(tokens[0]), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + break; + case Weibull: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); + break; + case LogNormal: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "LogNormal distribution is not supported."); + break; + case None: + // go-through + default: + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "No distribution for basic element defined."); + break; + } + return false; -#ifdef STORM_HAVE_CARL - template<> - storm::RationalFunction DFTGalileoParser::parseRationalExpression(std::string const& expr) { - STORM_LOG_TRACE("Translating expression: " << expr); - storm::expressions::Expression expression = parser.parseFromString(expr); - STORM_LOG_TRACE("Expression: " << expression); - storm::RationalFunction rationalFunction = evaluator.asRational(expression); - STORM_LOG_TRACE("Parsed expression: " << rationalFunction); - return rationalFunction; } + // Explicitly instantiate the class. + template class DFTGalileoParser; template class DFTGalileoParser; -#endif - + } } diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index c2a35bc50..f956d8cb9 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -3,43 +3,57 @@ #include #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm-dft/storage/dft/DFT.h" -#include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm-dft/builder/DFTBuilder.h" +#include "storm-parsers/parser/ValueParser.h" namespace storm { namespace parser { + /*! + * Parser for DFT in the Galileo format. + */ template class DFTGalileoParser { - storm::storage::DFTBuilder builder; - - std::shared_ptr manager; - - storm::parser::ExpressionParser parser; - - storm::expressions::ExpressionEvaluator evaluator; - - std::unordered_map identifierMapping; - public: - DFTGalileoParser(bool defaultInclusive = true, bool binaryDependencies = true) : builder(defaultInclusive, binaryDependencies), manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { - } - storm::storage::DFT parseDFT(std::string const& filename); + /*! + * Parse DFT in Galileo format and build DFT. + * + * @param filename File. + * @param defaultInclusive Flag indicating if priority gates are inclusive by default. + * @param binaryDependencies Flag indicating if dependencies should be converted to binary dependencies. + * + * @return DFT. + */ + static storm::storage::DFT parseDFT(std::string const& filename, bool defaultInclusive = true, bool binaryDependencies = true); private: - void readFile(std::string const& filename); - - std::string stripQuotsFromName(std::string const& name); - std::string parseNodeIdentifier(std::string const& name); - - ValueType parseRationalExpression(std::string const& expr); - - bool defaultInclusive; + /*! + * Parse element name (strip quotation marks, etc.). + * + * @param name Element name. + * + * @return Name. + */ + static std::string parseName(std::string const& name); + + /*! + * Parse basic element and add it to builder. + * + * @param tokens Tokens defining the basic element. + * @param builder DFTBuilder. + * @param valueParser ValueParser. + * + * @return True iff the parsing and creation was successful. + */ + static bool parseBasicElement(std::vector const& tokens, storm::builder::DFTBuilder& builder, ValueParser& valueParser); + + enum Distribution { None, Constant, Exponential, Weibull, LogNormal }; }; } } diff --git a/src/storm-dft/parser/DFTJsonParser.cpp b/src/storm-dft/parser/DFTJsonParser.cpp index 0d6f312f2..e44042980 100644 --- a/src/storm-dft/parser/DFTJsonParser.cpp +++ b/src/storm-dft/parser/DFTJsonParser.cpp @@ -15,54 +15,48 @@ namespace storm { namespace parser { template - storm::storage::DFT DFTJsonParser::parseJson(const std::string& filename) { - readFile(filename); - storm::storage::DFT dft = builder.build(); - STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString()); - STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); - return dft; + storm::storage::DFT DFTJsonParser::parseJsonFromFile(std::string const& filename) { + STORM_LOG_DEBUG("Parsing from JSON file"); + std::ifstream file; + storm::utility::openFile(filename, file); + json jsonInput; + jsonInput << file; + storm::utility::closeFile(file); + return parseJson(jsonInput); } template - std::string DFTJsonParser::generateUniqueName(std::string const& id, std::string const& name) { - std::string newId = name; - std::replace(newId.begin(), newId.end(), ' ', '_'); - std::replace(newId.begin(), newId.end(), '-', '_'); - return newId + "_" + id; + storm::storage::DFT DFTJsonParser::parseJsonFromString(std::string const& jsonString) { + STORM_LOG_DEBUG("Parsing from JSON string"); + json jsonInput = json::parse(jsonString); + return parseJson(jsonInput); } template - void DFTJsonParser::readFile(const std::string& filename) { - STORM_LOG_DEBUG("Parsing from JSON"); - - std::ifstream file; - storm::utility::openFile(filename, file); - json parsedJson; - parsedJson << file; - storm::utility::closeFile(file); - - json parameters = parsedJson.at("parameters"); -#ifdef STORM_HAVE_CARL - for (auto it = parameters.begin(); it != parameters.end(); ++it) { - STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - std::string parameter = it.key(); - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser.setIdentifierMapping(identifierMapping); - STORM_LOG_TRACE("Added parameter: " << var.getName()); + storm::storage::DFT DFTJsonParser::parseJson(json const& jsonInput) { + // Try to parse parameters + if (jsonInput.find("parameters") != jsonInput.end()) { + json parameters = jsonInput.at("parameters"); + STORM_LOG_THROW(parameters.empty() || (std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); + for (auto it = parameters.begin(); it != parameters.end(); ++it) { + std::string parameter = it.key(); + storm::expressions::Variable var = manager->declareRationalVariable(parameter); + identifierMapping.emplace(var.getName(), var); + parser.setIdentifierMapping(identifierMapping); + STORM_LOG_TRACE("Added parameter: " << var.getName()); + } } -#endif - - json nodes = parsedJson.at("nodes"); + json nodes = jsonInput.at("nodes"); // Start by building mapping from ids to their unique names std::map nameMapping; - for (auto& element: nodes) { + for (auto& element : nodes) { json data = element.at("data"); std::string id = data.at("id"); nameMapping[id] = generateUniqueName(id, data.at("name")); } + // Parse nodes for (auto& element : nodes) { STORM_LOG_TRACE("Parsing: " << element); bool success = true; @@ -82,7 +76,7 @@ namespace storm { } else if (type == "or") { success = builder.addOrElement(name, childNames); } else if (type == "vot") { - std::string votThreshold = data.at("voting"); + std::string votThreshold = parseJsonNumber(data.at("voting")); success = builder.addVotElement(name, boost::lexical_cast(votThreshold), childNames); } else if (type == "pand") { success = builder.addPandElement(name, childNames); @@ -95,11 +89,11 @@ namespace storm { } else if (type== "fdep") { success = builder.addDepElement(name, childNames, storm::utility::one()); } else if (type== "pdep") { - ValueType probability = parseRationalExpression(data.at("prob")); + ValueType probability = parseRationalExpression(parseJsonNumber(data.at("prob"))); success = builder.addDepElement(name, childNames, probability); } else if (type == "be") { - ValueType failureRate = parseRationalExpression(data.at("rate")); - ValueType dormancyFactor = parseRationalExpression(data.at("dorm")); + ValueType failureRate = parseRationalExpression(parseJsonNumber(data.at("rate"))); + ValueType dormancyFactor = parseRationalExpression(parseJsonNumber(data.at("dorm"))); bool transient = false; if (data.count("transient") > 0) { transient = data.at("transient"); @@ -110,23 +104,52 @@ namespace storm { success = false; } - // Do not set layout for dependencies - // This does not work because dependencies might be splitted - // TODO: do splitting later in rewriting step - if (type != "fdep" && type != "pdep") { - // Set layout positions - json position = element.at("position"); - double x = position.at("x"); - double y = position.at("y"); - builder.addLayoutInfo(name, x / 7, y / 7); + // Try to set layout information + if (element.find("position") != element.end()) { + // Do not set layout for dependencies + // This does not work because dependencies might be splitted + // TODO: do splitting later in rewriting step + if (type != "fdep" && type != "pdep") { + // Set layout positions + json position = element.at("position"); + double x = position.at("x"); + double y = position.at("y"); + builder.addLayoutInfo(name, x / 7, y / 7); + } } STORM_LOG_THROW(success, storm::exceptions::FileIoException, "Error while adding element '" << element << "'."); } - std::string toplevelName = nameMapping[parsedJson.at("toplevel")]; + std::string toplevelName = nameMapping[parseJsonNumber(jsonInput.at("toplevel"))]; if(!builder.setTopLevel(toplevelName)) { STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Top level id unknown."); } + + // Build DFT + storm::storage::DFT dft = builder.build(); + STORM_LOG_DEBUG("Elements:" << std::endl << dft.getElementsString()); + STORM_LOG_DEBUG("Spare Modules:" << std::endl << dft.getSpareModulesString()); + return dft; + + } + + template + std::string DFTJsonParser::generateUniqueName(std::string const& id, std::string const& name) { + std::string newId = name; + std::replace(newId.begin(), newId.end(), ' ', '_'); + std::replace(newId.begin(), newId.end(), '-', '_'); + return newId + "_" + id; + } + + template + std::string DFTJsonParser::parseJsonNumber(json number) { + if (number.is_string()) { + return number.get(); + } else { + std::stringstream stream; + stream << number; + return stream.str(); + } } template @@ -140,10 +163,6 @@ namespace storm { return boost::lexical_cast(expr); } - // Explicitly instantiate the class. - template class DFTJsonParser; - -#ifdef STORM_HAVE_CARL template<> storm::RationalFunction DFTJsonParser::parseRationalExpression(std::string const& expr) { STORM_LOG_TRACE("Translating expression: " << expr); @@ -154,8 +173,9 @@ namespace storm { return rationalFunction; } + + // Explicitly instantiate the class. + template class DFTJsonParser; template class DFTJsonParser; -#endif - } } diff --git a/src/storm-dft/parser/DFTJsonParser.h b/src/storm-dft/parser/DFTJsonParser.h index d23baf58e..5187e3cc3 100644 --- a/src/storm-dft/parser/DFTJsonParser.h +++ b/src/storm-dft/parser/DFTJsonParser.h @@ -3,11 +3,11 @@ #include #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm-dft/storage/dft/DFT.h" -#include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm-dft/builder/DFTBuilder.h" // JSON parser #include "json.hpp" @@ -19,7 +19,7 @@ namespace storm { template class DFTJsonParser { - storm::storage::DFTBuilder builder; + storm::builder::DFTBuilder builder; std::shared_ptr manager; @@ -33,14 +33,18 @@ namespace storm { DFTJsonParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { } - storm::storage::DFT parseJson(std::string const& filename); - + storm::storage::DFT parseJsonFromString(std::string const& jsonString); + + storm::storage::DFT parseJsonFromFile(std::string const& filename); + private: - void readFile(std::string const& filename); + storm::storage::DFT parseJson(json const& jsonInput); std::string generateUniqueName(std::string const& id, std::string const& name); ValueType parseRationalExpression(std::string const& expr); + + std::string parseJsonNumber(json number); }; } } diff --git a/src/storm-dft/settings/DftSettings.cpp b/src/storm-dft/settings/DftSettings.cpp index 6808e6e44..b5c206d51 100644 --- a/src/storm-dft/settings/DftSettings.cpp +++ b/src/storm-dft/settings/DftSettings.cpp @@ -9,14 +9,17 @@ #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/DebugSettings.h" #include "storm/settings/modules/EigenEquationSolverSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/GmmxxEquationSolverSettings.h" #include "storm/settings/modules/NativeEquationSolverSettings.h" +#include "storm/settings/modules/MultiplierSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/EliminationSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GameSolverSettings.h" #include "storm/settings/modules/BisimulationSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" #include "storm-gspn/settings/modules/GSPNSettings.h" #include "storm-gspn/settings/modules/GSPNExportSettings.h" @@ -34,11 +37,14 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(false); // storm::settings::addModule(); storm::settings::addModule(); diff --git a/src/storm-dft/storage/BucketPriorityQueue.cpp b/src/storm-dft/storage/BucketPriorityQueue.cpp index 3fccf05f9..c9b2adf24 100644 --- a/src/storm-dft/storage/BucketPriorityQueue.cpp +++ b/src/storm-dft/storage/BucketPriorityQueue.cpp @@ -9,7 +9,7 @@ namespace storm { template BucketPriorityQueue::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio) : lowerValue(lowerValue), logBase(std::log(ratio)), nrBuckets(nrBuckets), nrUnsortedItems(0), buckets(nrBuckets), currentBucket(nrBuckets) { - compare = ([this](HeuristicPointer a, HeuristicPointer b) { + compare = ([](HeuristicPointer a, HeuristicPointer b) { return *a < *b; }); } diff --git a/src/storm-dft/storage/dft/DFT.cpp b/src/storm-dft/storage/dft/DFT.cpp index 6f5db6a44..ad89354f3 100644 --- a/src/storm-dft/storage/dft/DFT.cpp +++ b/src/storm-dft/storage/dft/DFT.cpp @@ -7,7 +7,7 @@ #include "storm/utility/iota_n.h" #include "storm/utility/vector.h" -#include "storm-dft/storage/dft/DFTBuilder.h" +#include "storm-dft/builder/DFTBuilder.h" #include "storm-dft/storage/dft/DFTIsomorphism.h" @@ -271,7 +271,7 @@ namespace storm { std::vector> res; for(auto const& subdft : subdfts) { - DFTBuilder builder; + storm::builder::DFTBuilder builder; for(size_t id : subdft.second) { builder.copyElement(mElements[id]); @@ -293,22 +293,22 @@ namespace storm { } return max; } - + template DFT DFT::optimize() const { std::vector modIdea = findModularisationRewrite(); STORM_LOG_DEBUG("Modularisation idea: " << storm::utility::vector::toString(modIdea)); - + if (modIdea.empty()) { // No rewrite needed return *this; } - + std::vector> rewriteIds; rewriteIds.push_back(modIdea); - - DFTBuilder builder; - + + storm::builder::DFTBuilder builder; + // Accumulate elements which must be rewritten std::set rewriteSet; for (std::vector rewrites : rewriteIds) { @@ -320,7 +320,7 @@ namespace storm { builder.copyElement(elem); } } - + // Add rewritten elements for (std::vector rewrites : rewriteIds) { STORM_LOG_ASSERT(rewrites.size() > 1, "No rewritten elements."); @@ -359,7 +359,7 @@ namespace storm { STORM_LOG_ASSERT(false, "Dft type can not be rewritten."); break; } - + // Add parent with the new child newParent and all its remaining children childrenNames.clear(); childrenNames.push_back(newParentName); @@ -371,7 +371,7 @@ namespace storm { } builder.copyGate(originalParent, childrenNames); } - + builder.setTopLevel(mElements[mTopLevelIndex]->name()); // TODO use reference? DFT newDft = builder.build(); @@ -750,11 +750,10 @@ namespace storm { // suitable parent gate! - Lets check the independent submodules of the children auto const& children = std::static_pointer_cast>(e)->children(); for(auto const& child : children) { - - + auto ISD = std::static_pointer_cast>(child)->independentSubDft(true); // In the ISD, check for other children: - + std::vector rewrite = {e->id(), child->id()}; for(size_t isdElemId : ISD) { if(isdElemId == child->id()) continue; @@ -765,13 +764,13 @@ namespace storm { if(rewrite.size() > 2 && rewrite.size() < children.size() - 1) { return rewrite; } - - } + + } } - } + } return {}; } - + template std::tuple, std::vector, std::vector> DFT::getSortedParentAndDependencyIds(size_t index) const { diff --git a/src/storm-dft/storage/dft/DFT.h b/src/storm-dft/storage/dft/DFT.h index 20c42fdb8..aed02807d 100644 --- a/src/storm-dft/storage/dft/DFT.h +++ b/src/storm-dft/storage/dft/DFT.h @@ -18,6 +18,11 @@ #include "storm-dft/storage/dft/DFTLayoutInfo.h" namespace storm { + namespace builder { + // Forward declaration + template class DFTBuilder; + } + namespace storage { template @@ -32,11 +37,8 @@ namespace storm { }; - // Forward declarations + // Forward declaration template class DFTColouring; - - template class DFTBuilder; - /** * Represents a Dynamic Fault Tree @@ -76,10 +78,11 @@ namespace storm { DFT optimize() const; - void copyElements(std::vector elements, DFTBuilder builder) const; + void copyElements(std::vector elements, storm::builder::DFTBuilder builder) const; - size_t stateVectorSize() const { - return mStateVectorSize; + size_t stateBitVectorSize() const { + // Ensure multiple of 64 + return (mStateVectorSize / 64 + (mStateVectorSize % 64 != 0)) * 64; } size_t nrElements() const { diff --git a/src/storm-dft/storage/dft/DFTState.cpp b/src/storm-dft/storage/dft/DFTState.cpp index 29c1e525f..9d8a4d9d2 100644 --- a/src/storm-dft/storage/dft/DFTState.cpp +++ b/src/storm-dft/storage/dft/DFTState.cpp @@ -6,7 +6,7 @@ namespace storm { namespace storage { template - DFTState::DFTState(DFT const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo) { + DFTState::DFTState(DFT const& dft, DFTStateGenerationInfo const& stateGenerationInfo, size_t id) : mStatus(dft.stateBitVectorSize()), mId(id), mPseudoState(false), mDft(dft), mStateGenerationInfo(stateGenerationInfo) { // TODO Matthias: use construct() // Initialize uses diff --git a/src/storm-dft/storage/dft/DftJsonExporter.cpp b/src/storm-dft/storage/dft/DftJsonExporter.cpp index 30e0d2eec..d1bf4f42d 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.cpp +++ b/src/storm-dft/storage/dft/DftJsonExporter.cpp @@ -9,9 +9,6 @@ namespace storm { namespace storage { - template - size_t DftJsonExporter::currentId = 0; - template void DftJsonExporter::toFile(storm::storage::DFT const& dft, std::string const& filepath) { std::ofstream ofs; @@ -31,94 +28,76 @@ namespace storm { template modernjson::json DftJsonExporter::translate(storm::storage::DFT const& dft) { - modernjson::json jsonDft; - currentId = 0; - // Nodes modernjson::json jsonNodes; for (size_t i = 0; i < dft.nrElements(); ++i) { modernjson::json jsonNode = translateNode(dft.getElement(i)); - jsonDft.push_back(jsonNode); - } - - // Edges - modernjson::json jsonEdges; - for (size_t i = 0; i < dft.nrElements(); ++i) { - if (dft.isGate(i)) { - std::shared_ptr const> gate = dft.getGate(i); - for (size_t index = 0; index < gate->nrChildren(); ++index) { - DFTElementPointer child = gate->children()[index]; - modernjson::json jsonEdge = translateEdge(gate, child, index); - jsonDft.push_back(jsonEdge); - } - } + jsonNodes.push_back(jsonNode); } + modernjson::json jsonDft; + jsonDft["toplevel"] = std::to_string(dft.getTopLevelIndex()); + jsonDft["nodes"] = jsonNodes; return jsonDft; } template modernjson::json DftJsonExporter::translateNode(DFTElementCPointer const& element) { modernjson::json nodeData; - nodeData["id"] = element->id(); - ++currentId; - STORM_LOG_ASSERT(element->id() == currentId-1, "Ids do not correspond"); + nodeData["id"] = std::to_string(element->id()); nodeData["name"] = element->name(); + std::string type = storm::storage::toString(element->type()); + std::transform(type.begin(), type.end(), type.begin(), ::tolower); + nodeData["type"] = type; if (element->isGate()) { // Set children for gate std::shared_ptr const> gate = std::static_pointer_cast const>(element); - std::vector children; + std::vector children; for (DFTElementPointer const& child : gate->children()) { - children.push_back(child->id()); + children.push_back(std::to_string(child->id())); } nodeData["children"] = children; + // Gate dependent export + switch (element->type()) { + case storm::storage::DFTElementType::VOT: + nodeData["voting"] = std::static_pointer_cast const>(element)->threshold(); + break; + case storm::storage::DFTElementType::PDEP: + { + ValueType probability = std::static_pointer_cast const>(element)->probability(); + if (!storm::utility::isOne(probability)) { + std::stringstream stream; + stream << probability; + nodeData["prob"] = stream.str(); + } + break; + } + default: + break; + } } else if (element->isBasicElement()) { // Set rates for BE std::shared_ptr const> be = std::static_pointer_cast const>(element); std::stringstream stream; stream << be->activeFailureRate(); nodeData["rate"] = stream.str(); - stream.clear(); - stream << (be->passiveFailureRate() / be->activeFailureRate()); + stream.str(std::string()); // Clear stringstream + ValueType dormancy = be->passiveFailureRate() / be->activeFailureRate(); + stream << dormancy; nodeData["dorm"] = stream.str(); } modernjson::json jsonNode; jsonNode["data"] = nodeData; - jsonNode["group"] = "nodes"; - std::string type = storm::storage::toString(element->type()); - std::transform(type.begin(), type.end(), type.begin(), ::tolower); jsonNode["classes"] = type; return jsonNode; } - template - modernjson::json DftJsonExporter::translateEdge(std::shared_ptr const> const& gate, DFTElementCPointer const& child, size_t index) { - modernjson::json nodeData; - std::stringstream stream; - stream << gate->id() << "e" << child->id(); - nodeData["id"] = stream.str(); - ++currentId; - nodeData["source"] = gate->id(); - nodeData["target"] = child->id(); - nodeData["index"] = index; - - modernjson::json jsonNode; - jsonNode["data"] = nodeData; - - jsonNode["group"] = "edges"; - jsonNode["classes"] = ""; - return jsonNode; - } - // Explicitly instantiate the class. template class DftJsonExporter; - -#ifdef STORM_HAVE_CARL template class DftJsonExporter; -#endif } } diff --git a/src/storm-dft/storage/dft/DftJsonExporter.h b/src/storm-dft/storage/dft/DftJsonExporter.h index ef04750ba..646821bb6 100644 --- a/src/storm-dft/storage/dft/DftJsonExporter.h +++ b/src/storm-dft/storage/dft/DftJsonExporter.h @@ -29,19 +29,12 @@ namespace storm { static void toStream(storm::storage::DFT const& dft, std::ostream& os); - static modernjson::json translate(storm::storage::DFT const& dft); - - private: - static size_t currentId; + static modernjson::json translate(storm::storage::DFT const& dft); static modernjson::json translateNode(DFTElementCPointer const& element); - static modernjson::json translateEdge(std::shared_ptr const> const& gate, DFTElementCPointer const& child, size_t index); - - }; - } } diff --git a/src/storm-gspn-cli/CMakeLists.txt b/src/storm-gspn-cli/CMakeLists.txt index 39d656a4c..7b9ebf7aa 100644 --- a/src/storm-gspn-cli/CMakeLists.txt +++ b/src/storm-gspn-cli/CMakeLists.txt @@ -1,3 +1,4 @@ +# Create storm-gspn. add_executable(storm-gspn-cli ${PROJECT_SOURCE_DIR}/src/storm-gspn-cli/storm-gspn.cpp) target_link_libraries(storm-gspn-cli storm-gspn storm-cli-utilities) # Adding headers for xcode set_target_properties(storm-gspn-cli PROPERTIES OUTPUT_NAME "storm-gspn") @@ -5,4 +6,4 @@ set_target_properties(storm-gspn-cli PROPERTIES OUTPUT_NAME "storm-gspn") add_dependencies(binaries storm-gspn-cli) # installation -install(TARGETS storm-gspn-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) \ No newline at end of file +install(TARGETS storm-gspn-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-gspn-cli/storm-gspn.cpp b/src/storm-gspn-cli/storm-gspn.cpp index d6a493981..9d6924297 100644 --- a/src/storm-gspn-cli/storm-gspn.cpp +++ b/src/storm-gspn-cli/storm-gspn.cpp @@ -3,18 +3,17 @@ #include "storm-gspn/storage/gspn/GSPN.h" #include "storm-gspn/storage/gspn/GspnBuilder.h" #include "storm-gspn/builder/JaniGSPNBuilder.h" -#include "storm-gspn/storm-gspn.h" - -#include "storm/exceptions/BaseException.h" -#include "storm/exceptions/WrongFormatException.h" +#include "storm-gspn/api/storm-gspn.h" #include "storm/utility/macros.h" #include "storm/utility/initialize.h" #include "api/storm.h" + +#include "storm-parsers/api/storm-parsers.h" #include "storm-cli-utilities/cli.h" -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/jani/Model.h" @@ -27,12 +26,13 @@ #include "storm/exceptions/FileIoException.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm-gspn/settings/modules/GSPNSettings.h" #include "storm-gspn/settings/modules/GSPNExportSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/ResourceSettings.h" @@ -44,6 +44,7 @@ void initializeSettings() { // Register all known settings modules. storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); @@ -53,25 +54,6 @@ void initializeSettings() { } -std::unordered_map parseCapacitiesList(std::string const& filename) { - std::unordered_map map; - - std::ifstream stream; - storm::utility::openFile(filename, stream); - - std::string line; - while ( std::getline(stream, line) ) { - std::vector strs; - boost::split(strs, line, boost::is_any_of("\t ")); - STORM_LOG_THROW(strs.size() == 2, storm::exceptions::WrongFormatException, "Expect key value pairs"); - std::cout << std::stoll(strs[1]) << std::endl; - map[strs[0]] = std::stoll(strs[1]); - } - storm::utility::closeFile(stream); - return map; -} - - int main(const int argc, const char **argv) { try { storm::utility::setUp(); @@ -82,67 +64,57 @@ int main(const int argc, const char **argv) { if (!optionsCorrect) { return -1; } + + auto gspnSettings = storm::settings::getModule(); // parse gspn from file - if (!storm::settings::getModule().isGspnFileSet()) { - return -1; + if (!gspnSettings.isGspnFileSet()) { + // If no gspn file is given, nothing needs to be done. + return 0; + } + + std::string constantDefinitionString = ""; + if (gspnSettings.isConstantsSet()) { + constantDefinitionString = gspnSettings.getConstantDefinitionString(); } auto parser = storm::parser::GspnParser(); - auto gspn = parser.parse(storm::settings::getModule().getGspnFilename()); + auto gspn = parser.parse(gspnSettings.getGspnFilename(), constantDefinitionString); std::string formulaString = ""; - if (!storm::settings::getModule().isPropertySet()) { + if (storm::settings::getModule().isPropertySet()) { formulaString = storm::settings::getModule().getProperty(); } boost::optional> propertyFilter; storm::parser::FormulaParser formulaParser(gspn->getExpressionManager()); std::vector properties = storm::api::parseProperties(formulaParser, formulaString, propertyFilter); - + properties = storm::api::substituteConstantsInProperties(properties, gspn->getConstantsSubstitution()); + if (!gspn->isValid()) { STORM_LOG_ERROR("The gspn is not valid."); } - if(storm::settings::getModule().isCapacitiesFileSet()) { - auto capacities = parseCapacitiesList(storm::settings::getModule().getCapacitiesFilename()); + if(gspnSettings.isCapacitiesFileSet()) { + auto capacities = storm::api::parseCapacitiesList(gspnSettings.getCapacitiesFilename(), *gspn); + gspn->setCapacities(capacities); + } else if (gspnSettings.isCapacitySet()) { + uint64_t capacity = gspnSettings.getCapacity(); + std::unordered_map capacities; + for (auto const& place : gspn->getPlaces()) { + capacities.emplace(place.getName(), capacity); + } gspn->setCapacities(capacities); } - storm::handleGSPNExportSettings(*gspn); + storm::api::handleGSPNExportSettings(*gspn, [&](storm::builder::JaniGSPNBuilder const&) { return properties; }); - if(storm::settings::getModule().isJaniFileSet()) { - storm::jani::Model* model = storm::buildJani(*gspn); - storm::api::exportJaniModel(*model, properties, storm::settings::getModule().getJaniFilename()); - delete model; - } - delete gspn; return 0; -// // // construct ma // auto builder = storm::builder::ExplicitGspnModelBuilder<>(); // auto ma = builder.translateGspn(gspn, formula); // -// // write gspn into output file -// if (!outputFile.empty()) { -// std::ofstream file; -// file.open(outputFile); -// if (outputType == "pnml") { -// gspn.toPnml(file); -// } -// if (outputType == "pnpro") { -// gspn.toPnpro(file); -// } -// if (outputType == "dot") { -// gspn.writeDotToStream(file); -// } -// if (outputType == "ma") { -// ma.writeDotToStream(file); -// } -// file.close(); -// } - // All operations have now been performed, so we clean up everything and terminate. storm::utility::cleanUp(); return 0; diff --git a/src/storm-gspn/CMakeLists.txt b/src/storm-gspn/CMakeLists.txt index cf80ff6aa..c2b8dd896 100644 --- a/src/storm-gspn/CMakeLists.txt +++ b/src/storm-gspn/CMakeLists.txt @@ -8,11 +8,31 @@ file(GLOB_RECURSE STORM_GSPN_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-gspn/*/*.cp file(GLOB_RECURSE STORM_GSPN_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-gspn/*/*.h) -# Create storm-pgcl. +# Create storm-gspn. add_library(storm-gspn SHARED ${STORM_GSPN_SOURCES} ${STORM_GSPN_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-gspn PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) list(APPEND STORM_TARGETS storm-gspn) set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) -target_link_libraries(storm-gspn storm ${STORM_GSPN_LINK_LIBRARIES}) +target_link_libraries(storm-gspn PUBLIC storm storm-conv storm-parsers ${STORM_GSPN_LINK_LIBRARIES}) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_GSPN_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_GSPN_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_gspn_headers DEPENDS ${STORM_GSPN_OUTPUT_HEADERS} ${STORM_GSPN_HEADERS}) +add_dependencies(storm-gspn copy_storm_gspn_headers) # installation -install(TARGETS storm-gspn RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-gspn EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-gspn/api/storm-gspn.cpp b/src/storm-gspn/api/storm-gspn.cpp new file mode 100644 index 000000000..e9f23fe48 --- /dev/null +++ b/src/storm-gspn/api/storm-gspn.cpp @@ -0,0 +1,112 @@ +#include "storm-gspn/api/storm-gspn.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/utility/file.h" +#include "storm-gspn/settings/modules/GSPNExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" +#include "storm-conv/api/storm-conv.h" +#include "storm-parsers/parser/ExpressionParser.h" +#include "storm/exceptions/WrongFormatException.h" + +namespace storm { + namespace api { + + storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn) { + storm::builder::JaniGSPNBuilder builder(gspn); + return builder.build(); + } + + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, std::function(storm::builder::JaniGSPNBuilder const&)> const& janiProperyGetter) { + storm::settings::modules::GSPNExportSettings const& exportSettings = storm::settings::getModule(); + if (exportSettings.isWriteToDotSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToDotFilename(), fs); + gspn.writeDotToStream(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToPnproSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToPnproFilename(), fs); + gspn.toPnpro(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToPnmlSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToPnmlFilename(), fs); + gspn.toPnml(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToJsonSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteToJsonFilename(), fs); + gspn.toJson(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isDisplayStatsSet()) { + std::cout << "============GSPN Statistics==============" << std::endl; + gspn.writeStatsToStream(std::cout); + std::cout << "=========================================" << std::endl; + } + + if (exportSettings.isWriteStatsToFileSet()) { + std::ofstream fs; + storm::utility::openFile(exportSettings.getWriteStatsFilename(), fs); + gspn.writeStatsToStream(fs); + storm::utility::closeFile(fs); + } + + if (exportSettings.isWriteToJaniSet()) { + auto const& jani = storm::settings::getModule(); + storm::converter::JaniConversionOptions options(jani); + + storm::builder::JaniGSPNBuilder builder(gspn); + storm::jani::Model* model = builder.build("gspn_automaton", exportSettings.isAddJaniPropertiesSet()); + + auto properties = janiProperyGetter(builder); + if (exportSettings.isAddJaniPropertiesSet()) { + properties.insert(properties.end(), builder.getStandardProperties().begin(), builder.getStandardProperties().end()); + } + + storm::api::transformJani(*model, properties, options); + + storm::api::exportJaniToFile(*model, properties, exportSettings.getWriteToJaniFilename(), jani.isCompactJsonSet()); + delete model; + } + } + + std::unordered_map parseCapacitiesList(std::string const& filename, storm::gspn::GSPN const& gspn) { + storm::parser::ExpressionParser expressionParser(*gspn.getExpressionManager()); + std::unordered_map identifierMapping; + for (auto const& var : gspn.getExpressionManager()->getVariables()) { + identifierMapping.emplace(var.getName(), var.getExpression()); + } + expressionParser.setIdentifierMapping(identifierMapping); + expressionParser.setAcceptDoubleLiterals(false); + + std::unordered_map map; + + std::ifstream stream; + storm::utility::openFile(filename, stream); + + std::string line; + while ( std::getline(stream, line) ) { + std::vector strs; + boost::split(strs, line, boost::is_any_of("\t ")); + STORM_LOG_THROW(strs.size() == 2, storm::exceptions::WrongFormatException, "Expect key value pairs"); + storm::expressions::Expression expr = expressionParser.parseFromString(strs[1]); + if (!gspn.getConstantsSubstitution().empty()) { + expr = expr.substitute(gspn.getConstantsSubstitution()); + } + STORM_LOG_THROW(!expr.containsVariables(), storm::exceptions::WrongFormatException, "The capacity expression '" << strs[1] << "' still contains undefined constants."); + map[strs[0]] = expr.evaluateAsInt(); + } + storm::utility::closeFile(stream); + return map; + } + } +} + diff --git a/src/storm-gspn/api/storm-gspn.h b/src/storm-gspn/api/storm-gspn.h new file mode 100644 index 000000000..a54bd6e28 --- /dev/null +++ b/src/storm-gspn/api/storm-gspn.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "storm/storage/jani/Model.h" +#include "storm-gspn/storage/gspn/GSPN.h" +#include "storm-gspn/builder/JaniGSPNBuilder.h" + +namespace storm { + namespace api { + + /** + * Builds JANI model from GSPN. + */ + storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn); + + void handleGSPNExportSettings(storm::gspn::GSPN const& gspn, + std::function(storm::builder::JaniGSPNBuilder const&)> const& janiProperyGetter = [](storm::builder::JaniGSPNBuilder const&) { return std::vector(); }); + + std::unordered_map parseCapacitiesList(std::string const& filename, storm::gspn::GSPN const& gspn); + + } +} diff --git a/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp b/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp index 1960a623a..23ba78594 100644 --- a/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp +++ b/src/storm-gspn/builder/ExplicitGspnModelBuilder.cpp @@ -5,7 +5,7 @@ //#include "storm/utility/macros.h" //#include "storm/exceptions/NotImplementedException.h" //#include "storm/storage/expressions/ExpressionManager.h" -//#include "storm/parser/FormulaParser.h" +//#include "storm-parsers/parser/FormulaParser.h" //#include "storm/storage/expressions/ExpressionEvaluator.h" // //namespace storm { diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.cpp b/src/storm-gspn/builder/JaniGSPNBuilder.cpp index cd81bb266..a8669b1b8 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.cpp +++ b/src/storm-gspn/builder/JaniGSPNBuilder.cpp @@ -1,18 +1,38 @@ #include "JaniGSPNBuilder.h" +#include + +#include "storm/logic/Formulas.h" + +#include "storm/exceptions/InvalidModelException.h" namespace storm { namespace builder { - storm::jani::Model* JaniGSPNBuilder::build(std::string const& automatonName) { - storm::jani::Model* model = new storm::jani::Model(gspn.getName(), storm::jani::ModelType::MA, janiVersion, expressionManager); + storm::jani::Model* JaniGSPNBuilder::build(std::string const& automatonName, bool buildStandardProperties) { + storm::jani::ModelType modelType = storm::jani::ModelType::MA; + if (gspn.getNumberOfTimedTransitions() == 0) { + modelType = storm::jani::ModelType::MDP; + } else if (gspn.getNumberOfImmediateTransitions() == 0) { + modelType = storm::jani::ModelType::CTMC; + } + storm::jani::Model* model = new storm::jani::Model(gspn.getName(), modelType, janiVersion, expressionManager); storm::jani::Automaton mainAutomaton(automatonName, expressionManager->declareIntegerVariable("loc")); addVariables(model); uint64_t locId = addLocation(mainAutomaton); addEdges(mainAutomaton, locId); model->addAutomaton(mainAutomaton); model->setStandardSystemComposition(); + if (buildStandardProperties) { + buildProperties(model); + } + model->getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + model->finalize(); return model; } + + std::vector const& JaniGSPNBuilder::getStandardProperties() const { + return standardProperties; + } void JaniGSPNBuilder::addVariables(storm::jani::Model* model) { for (auto const& place : gspn.getPlaces()) { @@ -88,7 +108,7 @@ namespace storm { for (auto const& inPlaceEntry : trans.getInputPlaces()) { destguard = destguard && (vars[inPlaceEntry.first]->getExpressionVariable() >= inPlaceEntry.second); if (trans.getOutputPlaces().count(inPlaceEntry.first) == 0) { - assignments.emplace_back( *vars[inPlaceEntry.first], (vars[inPlaceEntry.first])->getExpressionVariable() - inPlaceEntry.second); + assignments.emplace_back(storm::jani::LValue(*vars[inPlaceEntry.first]), (vars[inPlaceEntry.first])->getExpressionVariable() - inPlaceEntry.second); } } for (auto const& inhibPlaceEntry : trans.getInhibitionPlaces()) { @@ -96,9 +116,9 @@ namespace storm { } for (auto const& outputPlaceEntry : trans.getOutputPlaces()) { if (trans.getInputPlaces().count(outputPlaceEntry.first) == 0) { - assignments.emplace_back( *vars[outputPlaceEntry.first], (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second ); + assignments.emplace_back(storm::jani::LValue(*vars[outputPlaceEntry.first]), (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second ); } else { - assignments.emplace_back( *vars[outputPlaceEntry.first], (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second - trans.getInputPlaces().at(outputPlaceEntry.first)); + assignments.emplace_back(storm::jani::LValue(*vars[outputPlaceEntry.first]), (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second - trans.getInputPlaces().at(outputPlaceEntry.first)); } } destguard = destguard.simplify(); @@ -122,12 +142,12 @@ namespace storm { } for (auto const& trans : gspn.getTimedTransitions()) { storm::expressions::Expression guard = expressionManager->boolean(true); - + std::vector assignments; for (auto const& inPlaceEntry : trans.getInputPlaces()) { guard = guard && (vars[inPlaceEntry.first]->getExpressionVariable() >= inPlaceEntry.second); if (trans.getOutputPlaces().count(inPlaceEntry.first) == 0) { - assignments.emplace_back( *vars[inPlaceEntry.first], (vars[inPlaceEntry.first])->getExpressionVariable() - inPlaceEntry.second); + assignments.emplace_back(storm::jani::LValue(*vars[inPlaceEntry.first]), (vars[inPlaceEntry.first])->getExpressionVariable() - inPlaceEntry.second); } } for (auto const& inhibPlaceEntry : trans.getInhibitionPlaces()) { @@ -135,20 +155,152 @@ namespace storm { } for (auto const& outputPlaceEntry : trans.getOutputPlaces()) { if (trans.getInputPlaces().count(outputPlaceEntry.first) == 0) { - assignments.emplace_back( *vars[outputPlaceEntry.first], (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second ); + assignments.emplace_back(storm::jani::LValue(*vars[outputPlaceEntry.first]), (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second ); } else { - assignments.emplace_back( *vars[outputPlaceEntry.first], (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second - trans.getInputPlaces().at(outputPlaceEntry.first)); + assignments.emplace_back(storm::jani::LValue(*vars[outputPlaceEntry.first]), (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second - trans.getInputPlaces().at(outputPlaceEntry.first)); } } std::shared_ptr templateEdge = std::make_shared(guard); automaton.registerTemplateEdge(templateEdge); + + storm::expressions::Expression rate = expressionManager->rational(trans.getRate()); + if (trans.hasInfiniteServerSemantics() || (trans.hasKServerSemantics() && !trans.hasSingleServerSemantics())) { + STORM_LOG_THROW(trans.hasKServerSemantics() || !trans.getInputPlaces().empty(), storm::exceptions::InvalidModelException, "Unclear semantics: Found a transition with infinite-server semantics and without input place."); + storm::expressions::Expression enablingDegree; + bool firstArgumentOfMinExpression = true; + if (trans.hasKServerSemantics()) { + enablingDegree = expressionManager->integer(trans.getNumberOfServers()); + firstArgumentOfMinExpression = false; + } + for (auto const& inPlaceEntry : trans.getInputPlaces()) { + storm::expressions::Expression enablingDegreeInPlace = vars[inPlaceEntry.first]->getExpressionVariable() / expressionManager->integer(inPlaceEntry.second); // Integer division! + if (firstArgumentOfMinExpression == true) { + enablingDegree = enablingDegreeInPlace; + } else { + enablingDegree = storm::expressions::minimum(enablingDegree, enablingDegreeInPlace); + } + } + rate = rate * enablingDegree; + } templateEdge->addDestination(assignments); - storm::jani::Edge e(locId, storm::jani::Model::SILENT_ACTION_INDEX, expressionManager->rational(trans.getRate()), templateEdge, {locId}, {expressionManager->integer(1)}); + storm::jani::Edge e(locId, storm::jani::Model::SILENT_ACTION_INDEX, rate, templateEdge, {locId}, {expressionManager->integer(1)}); automaton.addEdge(e); } } + + storm::jani::Variable const& JaniGSPNBuilder::addDeadlockTransientVariable(storm::jani::Model* model, std::string name, bool ignoreCapacities, bool ignoreInhibitorArcs, bool ignoreEmptyPlaces) { + + storm::expressions::Expression transientValue = expressionManager->boolean(true); + + // build the conjunction over all transitions + std::vector transitions; + transitions.reserve(gspn.getNumberOfImmediateTransitions() + gspn.getNumberOfTimedTransitions()); + for (auto const& t : gspn.getImmediateTransitions()) { + transitions.push_back(&t); + } + for (auto const& t : gspn.getTimedTransitions()) { + transitions.push_back(&t); + } + bool firstTransition = true; + for (auto const& transition : transitions) { + + // build the disjunction over all in/out places and inhibitor arcs + storm::expressions::Expression transitionDisabled = expressionManager->boolean(false); + bool firstPlace = true; + if (!ignoreEmptyPlaces) { + for (auto const& placeIdMult : transition->getInputPlaces()) { + storm::expressions::Expression placeBlocksTransition = (vars.at(placeIdMult.first)->getExpressionVariable() < expressionManager->integer(placeIdMult.second)); + if (firstPlace) { + transitionDisabled = placeBlocksTransition; + firstPlace = false; + } else { + transitionDisabled = transitionDisabled || placeBlocksTransition; + } + } + } + if (!ignoreInhibitorArcs) { + for (auto const& placeIdMult : transition->getInhibitionPlaces()) { + storm::expressions::Expression placeBlocksTransition = (vars.at(placeIdMult.first)->getExpressionVariable() >= expressionManager->integer(placeIdMult.second)); + if (firstPlace) { + transitionDisabled = placeBlocksTransition; + firstPlace = false; + } else { + transitionDisabled = transitionDisabled || placeBlocksTransition; + } + } + } + if (!ignoreCapacities) { + for (auto const& placeIdMult : transition->getOutputPlaces()) { + auto const& place = gspn.getPlace(placeIdMult.first); + if (place->hasRestrictedCapacity()) { + storm::expressions::Expression placeBlocksTransition = (vars.at(placeIdMult.first)->getExpressionVariable() + expressionManager->integer(placeIdMult.second) > expressionManager->integer(place->getCapacity())); + if (firstPlace) { + transitionDisabled = placeBlocksTransition; + firstPlace = false; + } else { + transitionDisabled = transitionDisabled || placeBlocksTransition; + } + } + } + } + + if (firstTransition) { + transientValue = transitionDisabled; + firstTransition = false; + } else { + transientValue = transientValue && transitionDisabled; + } + } + + auto exprVar = expressionManager->declareBooleanVariable(name); + auto const& janiVar = model->addVariable(*storm::jani::makeBooleanVariable(name, exprVar, expressionManager->boolean(false), true)); + storm::jani::Assignment assignment(storm::jani::LValue(janiVar), transientValue); + model->getAutomata().front().getLocations().front().addTransientAssignment(assignment); + return janiVar; + } + + + std::string getUniqueVarName(storm::expressions::ExpressionManager const& manager, std::string name) { + std::string res = name; + while (manager.hasVariable(res)) { + res.append("_"); + } + return res; + } + + void JaniGSPNBuilder::buildProperties(storm::jani::Model* model) { + standardProperties.clear(); + + auto const& deadlockVar = addDeadlockTransientVariable(model, getUniqueVarName(*expressionManager, "deadl")); + auto deadlock = std::make_shared(deadlockVar.getExpressionVariable().getExpression()); + auto trueFormula = std::make_shared(true); + std::set emptyVariableSet; + + auto maxReachDeadlock = std::make_shared( + std::make_shared(deadlock, storm::logic::FormulaContext::Probability), + storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); + standardProperties.emplace_back("MaxPrReachDeadlock", maxReachDeadlock, emptyVariableSet, "The maximal probability to eventually reach a deadlock."); + + auto exprTB = expressionManager->declareRationalVariable(getUniqueVarName(*expressionManager, "TIME_BOUND")); + auto janiTB = storm::jani::Constant(exprTB.getName(), exprTB); + model->addConstant(janiTB); + storm::logic::TimeBound tb(false, janiTB.getExpressionVariable().getExpression()); + storm::logic::TimeBoundReference tbr(storm::logic::TimeBoundType::Time); + auto maxReachDeadlockTimeBounded = std::make_shared( + std::make_shared(trueFormula, deadlock, boost::none, tb, tbr), + storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); + standardProperties.emplace_back("MaxPrReachDeadlockTB", maxReachDeadlockTimeBounded, emptyVariableSet, "The maximal probability to reach a deadlock within 'TIME_BOUND' steps."); + + auto expTimeDeadlock = std::make_shared( + std::make_shared(deadlock, storm::logic::FormulaContext::Time), + storm::logic::OperatorInformation(storm::solver::OptimizationDirection::Maximize)); + standardProperties.emplace_back("MinExpTimeDeadlock", expTimeDeadlock, emptyVariableSet, "The minimal expected time to reach a deadlock."); + + } + + } -} \ No newline at end of file +} diff --git a/src/storm-gspn/builder/JaniGSPNBuilder.h b/src/storm-gspn/builder/JaniGSPNBuilder.h index 474d04807..205f248e1 100644 --- a/src/storm-gspn/builder/JaniGSPNBuilder.h +++ b/src/storm-gspn/builder/JaniGSPNBuilder.h @@ -19,11 +19,13 @@ namespace storm { } - storm::jani::Model* build(std::string const& automatonName = "gspn_automaton"); + storm::jani::Model* build(std::string const& automatonName = "gspn_automaton", bool buildStandardProperties = false); - storm::jani::Variable const& getPlaceVariable(uint64_t placeId) { + storm::jani::Variable const& getPlaceVariable(uint64_t placeId) const { return *vars.at(placeId); } + + std::vector const& getStandardProperties() const; private: @@ -33,11 +35,16 @@ namespace storm { void addEdges(storm::jani::Automaton& automaton, uint64_t locId); + storm::jani::Variable const& addDeadlockTransientVariable(storm::jani::Model* model, std::string name, bool ignoreCapacities = false, bool ignoreInhibitorArcs = false, bool ignoreEmptyPlaces = false); + void buildProperties(storm::jani::Model* model); + const uint64_t janiVersion = 1; storm::gspn::GSPN const& gspn; std::map vars; std::shared_ptr expressionManager; + std::vector standardProperties; + }; } } diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp index 2ab73ac91..4c77bc3a2 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.cpp @@ -9,6 +9,7 @@ #include "storm/exceptions/UnexpectedException.h" #include "storm/exceptions/WrongFormatException.h" +#include "storm/exceptions/NotSupportedException.h" #include "storm/utility/macros.h" namespace { @@ -22,17 +23,27 @@ namespace { namespace storm { namespace parser { - + GreatSpnEditorProjectParser::GreatSpnEditorProjectParser(std::string const& constantDefinitionString) : manager(std::make_shared()) { + if (constantDefinitionString != "") { + std::vector constDefs; + boost::split( constDefs, constantDefinitionString, boost::is_any_of(",")); + for (auto const& pair : constDefs) { + std::vector keyvaluepair; + boost::split( keyvaluepair, pair, boost::is_any_of("=")); + STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::WrongFormatException, "Expected a constant definition of the form N=42 but got " << pair); + constantDefinitions.emplace(keyvaluepair.at(0), keyvaluepair.at(1)); + } + } + } + storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) { if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") { traverseProjectElement(elementRoot); - return builder.buildGspn(); + return builder.buildGspn(manager, constantsSubstitution); } else { // If the top-level node is not a "pnml" or "" node, then throw an exception. STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n"); } - - } void GreatSpnEditorProjectParser::traverseProjectElement(xercesc::DOMNode const* const node) { @@ -118,6 +129,25 @@ namespace storm { } // traverse children + // First pass: find constant definitions + constantsSubstitution.clear(); + expressionParser = std::make_shared(*manager); + std::unordered_map identifierMapping; + expressionParser->setIdentifierMapping(identifierMapping); + for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { + auto child = node->getChildNodes()->item(i); + auto name = storm::adapters::getName(child); + if (name.compare("constant") == 0 || name.compare("template") == 0) { + traverseConstantOrTemplateElement(child); + } + } + // Update the expression parser to make the newly created variables known to it + expressionParser = std::make_shared(*manager); + for (auto const& var : manager->getVariables()) { + identifierMapping.emplace(var.getName(), var.getExpression()); + } + expressionParser->setIdentifierMapping(identifierMapping); + // Second pass: traverse other children for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); auto name = storm::adapters::getName(child); @@ -126,6 +156,8 @@ namespace storm { traversePlaceElement(child); } else if(name.compare("transition") == 0) { traverseTransitionElement(child); + } else if(name.compare("constant") == 0 || name.compare("template") == 0) { + // Ignore constant def in second pass } else if (isOnlyWhitespace(name)) { // ignore node (contains only whitespace) } else { @@ -136,6 +168,70 @@ namespace storm { } } + void GreatSpnEditorProjectParser::traverseConstantOrTemplateElement(xercesc::DOMNode const* const node) { + std::string identifier; + storm::expressions::Type type; + std::string valueStr = ""; + + // traverse attributes + for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { + auto attr = node->getAttributes()->item(i); + auto name = storm::adapters::getName(attr); + + if (name.compare("name") == 0) { + identifier = storm::adapters::XMLtoString(attr->getNodeValue()); + } else if (name.compare("consttype") == 0 || name.compare("type") == 0) { + if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("REAL") == 0) { + type = manager->getRationalType(); + } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("INTEGER") == 0) { + type = manager->getIntegerType(); + } else { + STORM_PRINT_AND_LOG("Unknown consttype: " << storm::adapters::XMLtoString(attr->getNodeValue()) << std::endl); + } + } else if (name.compare("value") == 0) { + valueStr = storm::adapters::XMLtoString(attr->getNodeValue()); + } else if ((name == "x") || (name == "y")) { + // Ignore + } else { + // Found node or attribute which is at the moment not handled by this parser. + // Notify the user and continue the parsing. + STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); + } + } + + STORM_LOG_THROW(!manager->hasVariable(identifier), storm::exceptions::NotSupportedException, "Multiple definitions of constant '" << identifier << "' were found."); + if (valueStr == "") { + auto constDef = constantDefinitions.find(identifier); + STORM_LOG_THROW(constDef != constantDefinitions.end(), storm::exceptions::NotSupportedException, "Constant '" << identifier << "' has no value defined."); + valueStr = constDef->second; + } + storm::expressions::Variable var; + if (type.isRationalType()) { + var = manager->declareRationalVariable(identifier); + expressionParser->setAcceptDoubleLiterals(true); + } else if (type.isIntegerType()) { + var = manager->declareIntegerVariable(identifier); + expressionParser->setAcceptDoubleLiterals(false); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unknown type of constant" << type << "."); + } + constantsSubstitution.emplace(var, expressionParser->parseFromString(valueStr)); + + // traverse children + for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { + auto child = node->getChildNodes()->item(i); + auto name = storm::adapters::getName(child); + + if (isOnlyWhitespace(name)) { + // ignore node (contains only whitespace) + } else { + // Found node or attribute which is at the moment nod handled by this parser. + // Notify the user and continue the parsing. + STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); + } + } + } + void GreatSpnEditorProjectParser::traverseEdgesElement(xercesc::DOMNode const* const node) { // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { @@ -187,7 +283,7 @@ namespace storm { if (name.compare("name") == 0) { placeName = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("marking") == 0) { - initialTokens = std::stoull(storm::adapters::XMLtoString(attr->getNodeValue())); + initialTokens = parseInt(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignorePlaceAttribute(name)) { // ignore node } else { @@ -212,12 +308,12 @@ namespace storm { STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } - builder.addPlace(-1, initialTokens, placeName); + builder.addPlace(boost::none, initialTokens, placeName); } bool ignoreTransitionAttribute(std::string const& name) { // TODO we should probably not ignore x-servers but check that it is 0.5. - if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y") || (name == "nservers-x")) { + if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y") || (name == "nservers-x") || (name == "delay-x") || (name == "delay-y") || (name == "rotation")) { return true; } return false; @@ -227,6 +323,9 @@ namespace storm { std::string transitionName; bool immediateTransition; double rate = 1.0; // The default rate in GreatSPN. + double weight = 1.0; // The default weight in GreatSpn + uint64_t priority = 1; // The default priority in GreatSpn + boost::optional numServers; // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { @@ -238,11 +337,26 @@ namespace storm { } else if (name.compare("type") == 0) { if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("EXP") == 0) { immediateTransition = false; - } else { + } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("IMM") == 0) { immediateTransition = true; + } else { + STORM_PRINT_AND_LOG("unknown transition type: " << storm::adapters::XMLtoString(attr->getNodeValue())); } } else if(name.compare("delay") == 0) { - rate = std::stod(storm::adapters::XMLtoString(attr->getNodeValue())); + rate = parseReal(storm::adapters::XMLtoString(attr->getNodeValue())); + } else if(name.compare("weight") == 0) { + weight = parseReal(storm::adapters::XMLtoString(attr->getNodeValue())); + } else if(name.compare("priority") == 0) { + priority = parseInt(storm::adapters::XMLtoString(attr->getNodeValue())); + } else if (name.compare("nservers") == 0) { + std::string nservers = storm::adapters::XMLtoString(attr->getNodeValue()); + if (nservers == "Single") { + numServers = 1; + } else if (nservers == "Infinite") { + // Ignore this case as we assume infinite by default (similar to GreatSpn) + } else { + numServers = parseInt(nservers); + } } else if (ignoreTransitionAttribute(name)) { // ignore node } else { @@ -254,9 +368,9 @@ namespace storm { } if (immediateTransition) { - builder.addImmediateTransition(0, 0, transitionName); + builder.addImmediateTransition(priority, weight, transitionName); } else { - builder.addTimedTransition(0, rate, transitionName); + builder.addTimedTransition(0, rate, numServers, transitionName); } // traverse children @@ -303,10 +417,10 @@ namespace storm { head = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("tail") == 0) { tail = storm::adapters::XMLtoString(attr->getNodeValue()); - } else if (name.compare("kind") == 0) { + } else if (name.compare("kind") == 0 || name.compare("type") == 0) { kind = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("mult") == 0) { - mult = std::stoull(storm::adapters::XMLtoString(attr->getNodeValue())); + mult = parseInt(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignoreArcAttribute(name)) { // ignore node } else { @@ -349,6 +463,21 @@ namespace storm { } } + int64_t GreatSpnEditorProjectParser::parseInt(std::string str) { + expressionParser->setAcceptDoubleLiterals(false); + auto expr = expressionParser->parseFromString(str).substitute(constantsSubstitution); + STORM_LOG_ASSERT(!expr.containsVariables(), "Can not evaluate expression " << str << " as it contains undefined variables."); + return expr.evaluateAsInt(); + } + + double GreatSpnEditorProjectParser::parseReal(std::string str) { + expressionParser->setAcceptDoubleLiterals(true); + auto expr = expressionParser->parseFromString(str).substitute(constantsSubstitution); + STORM_LOG_ASSERT(!expr.containsVariables(), "Can not evaluate expression " << str << " as it contains undefined variables."); + return expr.evaluateAsDouble(); + } + + } } #endif diff --git a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h index 7c0f5e713..7663d2a23 100644 --- a/src/storm-gspn/parser/GreatSpnEditorProjectParser.h +++ b/src/storm-gspn/parser/GreatSpnEditorProjectParser.h @@ -7,6 +7,9 @@ #include #include +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm-parsers/parser/ExpressionParser.h" + #include "storm-gspn/storage/gspn/GSPN.h" #include "storm-gspn/storage/gspn/GspnBuilder.h" @@ -17,6 +20,8 @@ namespace storm { public: + GreatSpnEditorProjectParser(std::string const& constantDefinitionString); + /*! * Parses the given file into the GSPN. * @@ -31,14 +36,20 @@ namespace storm { void traverseNodesElement(xercesc::DOMNode const* const node); void traverseEdgesElement(xercesc::DOMNode const* const node); + void traverseConstantOrTemplateElement(xercesc::DOMNode const* const node); void traversePlaceElement(xercesc::DOMNode const* const node); void traverseTransitionElement(xercesc::DOMNode const* const node); void traverseArcElement(xercesc::DOMNode const* const node); + int64_t parseInt(std::string str); + double parseReal(std::string str); // the constructed gspn storm::gspn::GspnBuilder builder; - + std::shared_ptr manager; + std::shared_ptr expressionParser; + std::unordered_map constantDefinitions; + std::map constantsSubstitution; }; } } diff --git a/src/storm-gspn/parser/GspnParser.cpp b/src/storm-gspn/parser/GspnParser.cpp index b92b6f006..89a2f57e9 100644 --- a/src/storm-gspn/parser/GspnParser.cpp +++ b/src/storm-gspn/parser/GspnParser.cpp @@ -12,7 +12,7 @@ namespace storm { namespace parser { - storm::gspn::GSPN* GspnParser::parse(std::string const& filename) { + storm::gspn::GSPN* GspnParser::parse(std::string const& filename, std::string const& constantDefinitions) { #ifdef STORM_HAVE_XERCES // initialize xercesc try { @@ -62,10 +62,11 @@ namespace storm { xercesc::DOMElement* elementRoot = parser->getDocument()->getDocumentElement(); if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "pnml") { + STORM_LOG_WARN_COND(constantDefinitions == "", "Constant definitions for pnml files are currently not supported."); PnmlParser p; return p.parse(elementRoot); } else if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") { - GreatSpnEditorProjectParser p; + GreatSpnEditorProjectParser p(constantDefinitions); return p.parse(elementRoot); } else { // If the top-level node is not a "pnml" or "" node, then throw an exception. diff --git a/src/storm-gspn/parser/GspnParser.h b/src/storm-gspn/parser/GspnParser.h index 862dfc757..512f0ddd6 100644 --- a/src/storm-gspn/parser/GspnParser.h +++ b/src/storm-gspn/parser/GspnParser.h @@ -4,7 +4,7 @@ namespace storm { namespace parser { class GspnParser { public: - static storm::gspn::GSPN* parse(std::string const& filename); + static storm::gspn::GSPN* parse(std::string const& filename, std::string const& constantDefinitions = ""); }; } } diff --git a/src/storm-gspn/parser/PnmlParser.cpp b/src/storm-gspn/parser/PnmlParser.cpp index 71757defc..189e34266 100644 --- a/src/storm-gspn/parser/PnmlParser.cpp +++ b/src/storm-gspn/parser/PnmlParser.cpp @@ -104,7 +104,7 @@ namespace storm { std::string placeName; // the first entry is false if the corresponding information was not found in the pnml file std::pair numberOfInitialTokens(false, defaultNumberOfInitialTokens); - std::pair capacity(false, defaultCapacity); + std::pair> capacity(false, boost::none); // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { @@ -150,10 +150,9 @@ namespace storm { } if (!capacity.first) { // no information about the capacity is found - // use default capacity STORM_PRINT_AND_LOG("unknown capacity (place=" + placeName + ")\n"); } - builder.addPlace(capacity.first ? capacity.second : -1, numberOfInitialTokens.first ? numberOfInitialTokens.second : 0, placeName); + builder.addPlace(capacity.second, numberOfInitialTokens.first ? numberOfInitialTokens.second : 0, placeName); } void PnmlParser::traverseTransition(xercesc::DOMNode const* const node) { diff --git a/src/storm-gspn/settings/modules/GSPNExportSettings.cpp b/src/storm-gspn/settings/modules/GSPNExportSettings.cpp index 5b7653eef..895866cdf 100644 --- a/src/storm-gspn/settings/modules/GSPNExportSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNExportSettings.cpp @@ -1,5 +1,4 @@ #include "storm-gspn/settings/modules/GSPNExportSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/SettingMemento.h" @@ -20,6 +19,8 @@ namespace storm { const std::string GSPNExportSettings::writeToPnmlOptionName = "to-pnml"; const std::string GSPNExportSettings::writeToPnproOptionName = "to-pnpro"; const std::string GSPNExportSettings::writeToJsonOptionName = "to-json"; + const std::string GSPNExportSettings::writeToJaniOptionName = "to-jani"; + const std::string GSPNExportSettings::addJaniPropertiesOptionName = "addprops"; const std::string GSPNExportSettings::writeStatsOptionName = "to-stats"; const std::string GSPNExportSettings::displayStatsOptionName = "show-stats"; @@ -31,6 +32,8 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, writeToPnmlOptionName, false, "Destination for the pnml output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeToPnproOptionName, false, "Destination for the pnpro output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeToJsonOptionName, false, "Destination for the json output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, writeToJaniOptionName, false, "Destination for the jani output").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, addJaniPropertiesOptionName, false, "If set, a set of standard properties is added to the exported jani model.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, writeStatsOptionName, false, "Destination for the stats file").addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, displayStatsOptionName, false, "Print stats to stdout").build()); } @@ -67,6 +70,18 @@ namespace storm { return this->getOption(writeToJsonOptionName).getArgumentByName("filename").getValueAsString(); } + bool GSPNExportSettings::isWriteToJaniSet() const { + return this->getOption(writeToJaniOptionName).getHasOptionBeenSet(); + } + + std::string GSPNExportSettings::getWriteToJaniFilename() const { + return this->getOption(writeToJaniOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool GSPNExportSettings::isAddJaniPropertiesSet() const { + return this->getOption(addJaniPropertiesOptionName).getHasOptionBeenSet(); + } + bool GSPNExportSettings::isDisplayStatsSet() const { return this->getOption(displayStatsOptionName).getHasOptionBeenSet(); } diff --git a/src/storm-gspn/settings/modules/GSPNExportSettings.h b/src/storm-gspn/settings/modules/GSPNExportSettings.h index ce203a841..5ebb3ac5a 100644 --- a/src/storm-gspn/settings/modules/GSPNExportSettings.h +++ b/src/storm-gspn/settings/modules/GSPNExportSettings.h @@ -10,7 +10,7 @@ namespace storm { class GSPNExportSettings : public ModuleSettings { public: /*! - * Creates a new JaniExport setting + * Creates a new GSPNExport setting */ GSPNExportSettings(); @@ -45,6 +45,19 @@ namespace storm { */ std::string getWriteToJsonFilename() const; + + bool isWriteToJaniSet() const; + + /** + * + */ + std::string getWriteToJaniFilename() const; + + /*! + * Returns whether a set of standard properties is to be added when exporting to jani + */ + bool isAddJaniPropertiesSet() const; + bool isDisplayStatsSet() const; bool isWriteStatsToFileSet() const; @@ -62,6 +75,8 @@ namespace storm { static const std::string writeToPnmlOptionName; static const std::string writeToPnproOptionName; static const std::string writeToJsonOptionName; + static const std::string writeToJaniOptionName; + static const std::string addJaniPropertiesOptionName; static const std::string displayStatsOptionName; static const std::string writeStatsOptionName; diff --git a/src/storm-gspn/settings/modules/GSPNSettings.cpp b/src/storm-gspn/settings/modules/GSPNSettings.cpp index 2a0588b3d..b114559a5 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.cpp +++ b/src/storm-gspn/settings/modules/GSPNSettings.cpp @@ -16,16 +16,19 @@ namespace storm { const std::string GSPNSettings::gspnFileOptionName = "gspnfile"; const std::string GSPNSettings::gspnFileOptionShortName = "gspn"; - const std::string GSPNSettings::gspnToJaniOptionName = "to-jani"; - const std::string GSPNSettings::gspnToJaniOptionShortName = "tj"; const std::string GSPNSettings::capacitiesFileOptionName = "capacitiesfile"; const std::string GSPNSettings::capacitiesFileOptionShortName = "capacities"; + const std::string GSPNSettings::capacityOptionName = "capacity"; + const std::string GSPNSettings::constantsOptionName = "constants"; + const std::string GSPNSettings::constantsOptionShortName = "const"; + GSPNSettings::GSPNSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, gspnFileOptionName, false, "Parses the GSPN.").setShortName(gspnFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, gspnToJaniOptionName, false, "Transform to JANI.").setShortName(gspnToJaniOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, capacitiesFileOptionName, false, "Capacaties as invariants for places.").setShortName(capacitiesFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, capacityOptionName, false, "Global capacity as invariants for all places.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("value", "capacity").addValidatorUnsignedInteger(ArgumentValidatorFactory::createUnsignedGreaterValidator(0)).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, constantsOptionName, false, "Specifies the constant replacements to use.").setShortName(constantsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("values", "A comma separated list of constants and their value, e.g. a=1,b=2,c=3.").setDefaultValueString("").build()).build()); } bool GSPNSettings::isGspnFileSet() const { @@ -36,10 +39,6 @@ namespace storm { return this->getOption(gspnFileOptionName).getArgumentByName("filename").getValueAsString(); } - bool GSPNSettings::isToJaniSet() const { - return this->getOption(gspnToJaniOptionName).getHasOptionBeenSet(); - } - bool GSPNSettings::isCapacitiesFileSet() const { return this->getOption(capacitiesFileOptionName).getHasOptionBeenSet(); } @@ -48,19 +47,37 @@ namespace storm { return this->getOption(capacitiesFileOptionName).getArgumentByName("filename").getValueAsString(); } + bool GSPNSettings::isCapacitySet() const { + return this->getOption(capacityOptionName).getHasOptionBeenSet(); + } + + uint64_t GSPNSettings::getCapacity() const { + return this->getOption(capacityOptionName).getArgumentByName("value").getValueAsUnsignedInteger(); + } + + bool GSPNSettings::isConstantsSet() const { + return this->getOption(constantsOptionName).getHasOptionBeenSet(); + } + + std::string GSPNSettings::getConstantDefinitionString() const { + return this->getOption(constantsOptionName).getArgumentByName("values").getValueAsString(); + } + void GSPNSettings::finalize() { } bool GSPNSettings::check() const { if(!isGspnFileSet()) { - if(isToJaniSet()) { - return false; - } if(isCapacitiesFileSet()) { return false; } } + + if (isCapacitiesFileSet() && isCapacitySet()) { + STORM_LOG_ERROR("Conflicting settings: Capacity file AND capacity was set."); + return false; + } return true; } } diff --git a/src/storm-gspn/settings/modules/GSPNSettings.h b/src/storm-gspn/settings/modules/GSPNSettings.h index f4ff4ff2c..78586cf9c 100644 --- a/src/storm-gspn/settings/modules/GSPNSettings.h +++ b/src/storm-gspn/settings/modules/GSPNSettings.h @@ -24,11 +24,6 @@ namespace storm { */ std::string getGspnFilename() const; - /** - * Whether the gspn should be transformed to Jani - */ - bool isToJaniSet() const; - /** * Retrievew whether the pgcl file option was set */ @@ -39,6 +34,26 @@ namespace storm { */ std::string getCapacitiesFilename() const; + /** + * Retrievew whether a global capacity was set + */ + bool isCapacitySet() const; + + /** + * Retrieves the global capacity + */ + uint64_t getCapacity() const; + + /*! + * Retrieves whether the constants ption was set. + */ + bool isConstantsSet() const; + + /*! + * Retrieves the string that defines the constants of a gspn + */ + std::string getConstantDefinitionString() const; + bool check() const override; void finalize() override; @@ -48,11 +63,11 @@ namespace storm { private: static const std::string gspnFileOptionName; static const std::string gspnFileOptionShortName; - static const std::string gspnToJaniOptionName; - static const std::string gspnToJaniOptionShortName; static const std::string capacitiesFileOptionName; static const std::string capacitiesFileOptionShortName; - + static const std::string capacityOptionName; + static const std::string constantsOptionName; + static const std::string constantsOptionShortName; }; } } diff --git a/src/storm-gspn/storage/gspn/GSPN.cpp b/src/storm-gspn/storage/gspn/GSPN.cpp index f26c71540..903425735 100644 --- a/src/storm-gspn/storage/gspn/GSPN.cpp +++ b/src/storm-gspn/storage/gspn/GSPN.cpp @@ -26,8 +26,8 @@ namespace storm { return tId; } - GSPN::GSPN(std::string const& name, std::vector const& places, std::vector> const& itransitions, std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager) - : name(name), places(places), immediateTransitions(itransitions), timedTransitions(ttransitions), partitions(partitions), exprManager(exprManager) + GSPN::GSPN(std::string const& name, std::vector const& places, std::vector> const& itransitions, std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager, std::map const& constantsSubstitution) + : name(name), places(places), immediateTransitions(itransitions), timedTransitions(ttransitions), partitions(partitions), exprManager(exprManager), constantsSubstitution(constantsSubstitution) { } @@ -134,12 +134,16 @@ namespace storm { return getImmediateTransition(id); } + + std::shared_ptr const& GSPN::getExpressionManager() const { + return exprManager; + } + + std::map const& GSPN::getConstantsSubstitution() const { + return constantsSubstitution; + } - std::shared_ptr const& GSPN::getExpressionManager() const { - return exprManager; - } - - void GSPN::setCapacities(std::unordered_map const& mapping) { + void GSPN::setCapacities(std::unordered_map const& mapping) { for(auto const& entry : mapping) { storm::gspn::Place* place = getPlace(entry.first); STORM_LOG_THROW(place != nullptr, storm::exceptions::InvalidArgumentException, "No place with name " << entry.first); @@ -168,6 +172,7 @@ namespace storm { for (auto& trans : this->getTimedTransitions()) { outStream << "\t" << trans.getName() << " [label=\"" << trans.getName(); outStream << "(" << trans.getRate() << ")\"];" << std::endl; + STORM_LOG_WARN_COND(trans.hasSingleServerSemantics(), "Unable to export non-trivial transition semantics"); // TODO } // print arcs @@ -533,6 +538,11 @@ namespace storm { stream << space3 << "" << std::endl; stream << space4 << "Default," << place.getNumberOfInitialTokens() << "" << std::endl; stream << space3 << "" << std::endl; + if(place.hasRestrictedCapacity()) { + stream << space3 << "" << std::endl; + stream << space4 << "Default," << place.getCapacity() << "" << std::endl; + stream << space3 << "" << std::endl; + } stream << space2 << "" << std::endl; } @@ -550,6 +560,7 @@ namespace storm { // add timed transitions for (const auto &trans : timedTransitions) { + STORM_LOG_WARN_COND(trans.hasInfiniteServerSemantics(), "Unable to export non-trivial transition semantics"); // TODO stream << space2 << "" << std::endl; stream << space3 << "" << std::endl; stream << space4 << "" << trans.getRate() << "" << std::endl; @@ -615,6 +626,60 @@ namespace storm { } } + // add arcs for immediate transitions + for (const auto &trans : timedTransitions) { + // add input arcs + for (auto const& inEntry : trans.getInputPlaces()) { + stream << space2 << "" << std::endl; + + stream << space3 << "" << std::endl; + stream << space4 << "Default," << inEntry.second << "" << std::endl; + stream << space3 << "" << std::endl; + + stream << space3 << "" << std::endl; + + stream << space2 << "" << std::endl; + } + + // add inhibition arcs + for (auto const& inhEntry : trans.getInhibitionPlaces()) { + stream << space2 << "" << std::endl; + + stream << space3 << "" << std::endl; + stream << space4 << "Default," << inhEntry.second << "" << std::endl; + stream << space3 << "" << std::endl; + + stream << space3 << "" << std::endl; + + stream << space2 << "" << std::endl; + } + + // add output arcs + for (auto const& outEntry : trans.getOutputPlaces()) { + stream << space2 << "" << std::endl; + + stream << space3 << "" << std::endl; + stream << space4 << "Default," << outEntry.second << "" << std::endl; + stream << space3 << "" << std::endl; + + stream << space3 << "" << std::endl; + + stream << space2 << "" << std::endl; + } + } + stream << space << "" << std::endl; stream << "" << std::endl; } diff --git a/src/storm-gspn/storage/gspn/GSPN.h b/src/storm-gspn/storage/gspn/GSPN.h index 7b37ed5cb..343dcd887 100644 --- a/src/storm-gspn/storage/gspn/GSPN.h +++ b/src/storm-gspn/storage/gspn/GSPN.h @@ -32,7 +32,7 @@ namespace storm { GSPN(std::string const& name, std::vector const& places, std::vector> const& itransitions, - std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager); + std::vector> const& ttransitions, std::vector const& partitions, std::shared_ptr const& exprManager, std::map const& constantsSubstitution = std::map()); /*! * Returns the number of places in this gspn. @@ -145,8 +145,13 @@ namespace storm { */ std::shared_ptr const& getExpressionManager() const; + /*! + * Gets an assignment of occurring constants of the GSPN to their value + */ + std::map const& getConstantsSubstitution() const; + /** - * Set Capacities according to name->capacity map. + * Set Capacities of places according to name->capacity map. */ void setCapacities(std::unordered_map const& mapping); @@ -217,6 +222,8 @@ namespace storm { std::vector partitions; std::shared_ptr exprManager; + + std::map constantsSubstitution; // Layout information mutable std::map placeLayout; diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.cpp b/src/storm-gspn/storage/gspn/GspnBuilder.cpp index 5303a89c6..c39b5c0f7 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.cpp +++ b/src/storm-gspn/storage/gspn/GspnBuilder.cpp @@ -13,7 +13,7 @@ namespace storm { gspnName = name; } - uint_fast64_t GspnBuilder::addPlace(int_fast64_t const& capacity, uint_fast64_t const& initialTokens, std::string const& name) { + uint_fast64_t GspnBuilder::addPlace(boost::optional capacity, uint_fast64_t const& initialTokens, std::string const& name) { auto newId = places.size(); auto place = storm::gspn::Place(newId); place.setCapacity(capacity); @@ -65,13 +65,22 @@ namespace storm { return newId; } - + uint_fast64_t GspnBuilder::addTimedTransition(uint_fast64_t const &priority, double const &rate, std::string const& name) { + return addTimedTransition(priority, rate, 1, name); + } + + uint_fast64_t GspnBuilder::addTimedTransition(uint_fast64_t const &priority, double const &rate, boost::optional numServers, std::string const& name) { auto trans = storm::gspn::TimedTransition(); auto newId = GSPN::timedTransitionIdToTransitionId(timedTransitions.size()); trans.setName(name); trans.setPriority(priority); trans.setRate(rate); + if (numServers) { + trans.setKServerSemantics(numServers.get()); + } else { + trans.setInfiniteServerSemantics(); + } trans.setID(newId); timedTransitions.push_back(trans); @@ -162,8 +171,13 @@ namespace storm { - storm::gspn::GSPN* GspnBuilder::buildGspn() const { - std::shared_ptr exprManager(new storm::expressions::ExpressionManager()); + storm::gspn::GSPN* GspnBuilder::buildGspn(std::shared_ptr const& exprManager, std::map const& constantsSubstitution) const { + std::shared_ptr actualExprManager; + if (exprManager) { + actualExprManager = exprManager; + } else { + actualExprManager = std::make_shared(); + } std::vector orderedPartitions; for(auto const& priorityPartitions : partitions) { @@ -179,10 +193,10 @@ namespace storm { } std::reverse(orderedPartitions.begin(), orderedPartitions.end()); for(auto const& placeEntry : placeNames) { - exprManager->declareIntegerVariable(placeEntry.first, false); + actualExprManager->declareIntegerVariable(placeEntry.first, false); } - GSPN* result = new GSPN(gspnName, places, immediateTransitions, timedTransitions, orderedPartitions, exprManager); + GSPN* result = new GSPN(gspnName, places, immediateTransitions, timedTransitions, orderedPartitions, actualExprManager, constantsSubstitution); result->setTransitionLayoutInfo(transitionLayout); result->setPlaceLayoutInfo(placeLayout); return result; diff --git a/src/storm-gspn/storage/gspn/GspnBuilder.h b/src/storm-gspn/storage/gspn/GspnBuilder.h index 79fb2e712..5e4db4a34 100644 --- a/src/storm-gspn/storage/gspn/GspnBuilder.h +++ b/src/storm-gspn/storage/gspn/GspnBuilder.h @@ -25,7 +25,7 @@ namespace storm { * A capacity of -1 indicates an unbounded place. * @param initialTokens The number of inital tokens in the place. */ - uint_fast64_t addPlace(int_fast64_t const& capacity = 1, uint_fast64_t const& initialTokens = 0, std::string const& name = ""); + uint_fast64_t addPlace(boost::optional capacity = 1, uint_fast64_t const& initialTokens = 0, std::string const& name = ""); void setPlaceLayoutInfo(uint64_t placeId, LayoutInfo const& layoutInfo); @@ -39,11 +39,20 @@ namespace storm { /** * Adds an timed transition to the gspn. + * The transition is assumed to have Single-Server-Semantics * @param priority The priority for the transtion. - * @param weight The weight for the transition. + * @param rate The rate for the transition. */ uint_fast64_t addTimedTransition(uint_fast64_t const &priority, RateType const& rate, std::string const& name = ""); + /** + * Adds an timed transition to the gspn. + * @param priority The priority for the transtion. + * @param rate The rate for the transition. + * @param numServers The number of servers this transition has (in case of K-Server semantics) or boost::none (in case of Infinite-Server-Semantics). + */ + uint_fast64_t addTimedTransition(uint_fast64_t const &priority, RateType const& rate, boost::optional numServers, std::string const& name = ""); + void setTransitionLayoutInfo(uint64_t transitionId, LayoutInfo const& layoutInfo); @@ -91,10 +100,10 @@ namespace storm { /** - * + * @param exprManager The expression manager that will be associated with the new gspn. If this is nullptr, a new expressionmanager will be created. * @return The gspn which is constructed by the builder. */ - storm::gspn::GSPN* buildGspn() const; + storm::gspn::GSPN* buildGspn(std::shared_ptr const& exprManager = nullptr, std::map const& constantsSubstitution = std::map()) const; private: bool isImmediateTransitionId(uint64_t) const; bool isTimedTransitionId(uint64_t) const; diff --git a/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp b/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp index 4e451d094..f4e910b81 100644 --- a/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp +++ b/src/storm-gspn/storage/gspn/GspnJsonExporter.cpp @@ -160,7 +160,16 @@ namespace storm { data["name"] = transition.getName(); data["rate"] = transition.getRate(); data["priority"] = transition.getPriority(); - + if (!transition.hasSingleServerSemantics()) { + if (transition.hasInfiniteServerSemantics()) { + data["server-semantics"] = "infinite"; + } else if (transition.hasKServerSemantics()) { + data["server-semantics"] = transition.getNumberOfServers(); + } else { + STORM_LOG_WARN("Unable to export transition semantics."); + } + } + modernjson::json position; position["x"] = x * scaleFactor; position["y"] = y * scaleFactor; diff --git a/src/storm-gspn/storage/gspn/Place.cpp b/src/storm-gspn/storage/gspn/Place.cpp index a78b7c585..ca9a4a9e1 100644 --- a/src/storm-gspn/storage/gspn/Place.cpp +++ b/src/storm-gspn/storage/gspn/Place.cpp @@ -29,11 +29,12 @@ namespace storm { return this->numberOfInitialTokens; } - void Place::setCapacity(uint64_t cap) { + void Place::setCapacity(boost::optional cap) { this->capacity = cap; } uint64_t Place::getCapacity() const { + assert(hasRestrictedCapacity()); return capacity.get(); } diff --git a/src/storm-gspn/storage/gspn/Place.h b/src/storm-gspn/storage/gspn/Place.h index e995f6a93..55c9da6fb 100644 --- a/src/storm-gspn/storage/gspn/Place.h +++ b/src/storm-gspn/storage/gspn/Place.h @@ -54,9 +54,9 @@ namespace storm { * Sets the capacity of tokens of this place. * * @param capacity The capacity of this place. A non-negative number represents the capacity. - * The value -1 indicates that the capacity is not set. + * boost::none indicates that the flag is not set. */ - void setCapacity(uint64_t capacity); + void setCapacity(boost::optional capacity); /*! * Returns the capacity of tokens of this place. diff --git a/src/storm-gspn/storage/gspn/TimedTransition.h b/src/storm-gspn/storage/gspn/TimedTransition.h index d8399319d..37b5476f6 100644 --- a/src/storm-gspn/storage/gspn/TimedTransition.h +++ b/src/storm-gspn/storage/gspn/TimedTransition.h @@ -1,12 +1,18 @@ #pragma once #include "storm-gspn/storage/gspn/Transition.h" +#include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace gspn { template class TimedTransition : public storm::gspn::Transition { public: + + TimedTransition() { + setSingleServerSemantics(); + } + /*! * Sets the rate of this transition to the given value. * @@ -15,7 +21,43 @@ namespace storm { void setRate(RateType const& rate) { this->rate = rate; } - + + /*! + * Sets the semantics of this transition + */ + void setKServerSemantics(uint64_t k) { + STORM_LOG_THROW(k>0, storm::exceptions::InvalidArgumentException, "Invalid Parameter for server semantics: 0"); + nServers = k; + } + + void setSingleServerSemantics() { + nServers = 1; + } + + void setInfiniteServerSemantics() { + nServers = 0; + } + + /*! + * Retrieves the semantics of this transition + */ + bool hasKServerSemantics() const { + return nServers > 0; + } + + bool hasSingleServerSemantics() const { + return nServers == 1; + } + + bool hasInfiniteServerSemantics() const { + return nServers == 0; + } + + uint64_t getNumberOfServers() const { + STORM_LOG_ASSERT(hasKServerSemantics(), "Tried to get the number of servers of a timed transition although it does not have K-Server-Semantics."); + return nServers; + } + /*! * Retrieves the rate of this transition. * @@ -28,6 +70,9 @@ namespace storm { private: // the rate of the transition RateType rate; + + // the number of servers of this transition. 0 means infinite server semantics. + uint64_t nServers; }; } } \ No newline at end of file diff --git a/src/storm-gspn/storm-gspn.h b/src/storm-gspn/storm-gspn.h deleted file mode 100644 index cc9fd9add..000000000 --- a/src/storm-gspn/storm-gspn.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include "storm/storage/jani/Model.h" - -#include "storm-gspn/builder/JaniGSPNBuilder.h" -#include "storm-gspn/storage/gspn/GSPN.h" - -#include "storm/settings/SettingsManager.h" -#include "storm-gspn/settings/modules/GSPNExportSettings.h" - -#include "storm/utility/file.h" - -namespace storm { - /** - * Builds JANI model from GSPN. - */ - storm::jani::Model* buildJani(storm::gspn::GSPN const& gspn) { - storm::builder::JaniGSPNBuilder builder(gspn); - return builder.build(); - } - - void handleGSPNExportSettings(storm::gspn::GSPN const& gspn) { - storm::settings::modules::GSPNExportSettings const& exportSettings = storm::settings::getModule(); - if (exportSettings.isWriteToDotSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToDotFilename(), fs); - gspn.writeDotToStream(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isWriteToPnproSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToPnproFilename(), fs); - gspn.toPnpro(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isWriteToPnmlSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToPnmlFilename(), fs); - gspn.toPnml(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isWriteToJsonSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteToJsonFilename(), fs); - gspn.toJson(fs); - storm::utility::closeFile(fs); - } - - if (exportSettings.isDisplayStatsSet()) { - std::cout << "============GSPN Statistics==============" << std::endl; - gspn.writeStatsToStream(std::cout); - std::cout << "=========================================" << std::endl; - } - - if (exportSettings.isWriteStatsToFileSet()) { - std::ofstream fs; - storm::utility::openFile(exportSettings.getWriteStatsFilename(), fs); - gspn.writeStatsToStream(fs); - storm::utility::closeFile(fs); - } - - - - } - -} diff --git a/src/storm-pars-cli/CMakeLists.txt b/src/storm-pars-cli/CMakeLists.txt index 9e2f6f315..955ee93c8 100644 --- a/src/storm-pars-cli/CMakeLists.txt +++ b/src/storm-pars-cli/CMakeLists.txt @@ -6,4 +6,4 @@ set_target_properties(storm-pars-cli PROPERTIES OUTPUT_NAME "storm-pars") add_dependencies(binaries storm-pars-cli) # installation -install(TARGETS storm-pars-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-pars-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index 8546f81d1..badcb0212 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/src/storm-pars-cli/storm-pars.cpp @@ -15,6 +15,8 @@ #include "storm/utility/Stopwatch.h" #include "storm/utility/macros.h" +#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" + #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" @@ -29,7 +31,20 @@ namespace storm { typedef typename storm::cli::SymbolicInput SymbolicInput; - + template + struct SampleInformation { + SampleInformation(bool graphPreserving = false, bool exact = false) : graphPreserving(graphPreserving), exact(exact) { + // Intentionally left empty. + } + + bool empty() const { + return cartesianProducts.empty(); + } + + std::vector::type, std::vector::type>>> cartesianProducts; + bool graphPreserving; + bool exact; + }; template std::vector> parseRegions(std::shared_ptr const& model) { @@ -41,6 +56,76 @@ namespace storm { return result; } + template + SampleInformation parseSamples(std::shared_ptr const& model, std::string const& sampleString, bool graphPreserving) { + STORM_LOG_THROW(!model || model->isSparseModel(), storm::exceptions::NotSupportedException, "Sampling is only supported for sparse models."); + + SampleInformation sampleInfo(graphPreserving); + if (sampleString.empty()) { + return sampleInfo; + } + + // Get all parameters from the model. + std::set::type> modelParameters; + auto const& sparseModel = *model->as>(); + modelParameters = storm::models::sparse::getProbabilityParameters(sparseModel); + auto rewParameters = storm::models::sparse::getRewardParameters(sparseModel); + modelParameters.insert(rewParameters.begin(), rewParameters.end()); + + std::vector cartesianProducts; + boost::split(cartesianProducts, sampleString, boost::is_any_of(";")); + for (auto& product : cartesianProducts) { + boost::trim(product); + + // Get the values string for each variable. + std::vector valuesForVariables; + boost::split(valuesForVariables, product, boost::is_any_of(",")); + for (auto& values : valuesForVariables) { + boost::trim(values); + } + + std::set::type> encounteredParameters; + sampleInfo.cartesianProducts.emplace_back(); + auto& newCartesianProduct = sampleInfo.cartesianProducts.back(); + for (auto const& varValues : valuesForVariables) { + auto equalsPosition = varValues.find("="); + STORM_LOG_THROW(equalsPosition != varValues.npos, storm::exceptions::WrongFormatException, "Incorrect format of samples."); + std::string variableName = varValues.substr(0, equalsPosition); + boost::trim(variableName); + std::string values = varValues.substr(equalsPosition + 1); + boost::trim(values); + + bool foundParameter = false; + typename utility::parametric::VariableType::type theParameter; + for (auto const& parameter : modelParameters) { + std::stringstream parameterStream; + parameterStream << parameter; + if (parameterStream.str() == variableName) { + foundParameter = true; + theParameter = parameter; + encounteredParameters.insert(parameter); + } + } + STORM_LOG_THROW(foundParameter, storm::exceptions::WrongFormatException, "Unknown parameter '" << variableName << "'."); + + std::vector splitValues; + boost::split(splitValues, values, boost::is_any_of(":")); + STORM_LOG_THROW(!splitValues.empty(), storm::exceptions::WrongFormatException, "Expecting at least one value per parameter."); + + auto& list = newCartesianProduct[theParameter]; + + for (auto& value : splitValues) { + boost::trim(value); + list.push_back(storm::utility::convertNumber::type>(value)); + } + } + + STORM_LOG_THROW(encounteredParameters == modelParameters, storm::exceptions::WrongFormatException, "Variables for all parameters are required when providing samples."); + } + + return sampleInfo; + } + template std::pair, bool> preprocessSparseModel(std::shared_ptr> const& model, SymbolicInput const& input) { auto generalSettings = storm::settings::getModule(); @@ -106,9 +191,24 @@ namespace storm { } template - void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr) { + void printInitialStatesResult(std::unique_ptr const& result, storm::jani::Property const& property, storm::utility::Stopwatch* watch = nullptr, storm::utility::parametric::Valuation const* valuation = nullptr) { if (result) { - STORM_PRINT_AND_LOG("Result (initial states): " << std::endl); + STORM_PRINT_AND_LOG("Result (initial states)"); + if (valuation) { + bool first = true; + std::stringstream ss; + for (auto const& entry : *valuation) { + if (!first) { + ss << ", "; + } else { + first = false; + } + ss << entry.first << "=" << entry.second; + } + + STORM_PRINT_AND_LOG(" for instance [" << ss.str() << "]"); + } + STORM_PRINT_AND_LOG(": ") auto const* regionCheckResult = dynamic_cast const*>(result.get()); if (regionCheckResult != nullptr) { @@ -132,7 +232,7 @@ namespace storm { STORM_PRINT_AND_LOG(*result << std::endl); } if (watch) { - STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl); + STORM_PRINT_AND_LOG("Time for model checking: " << *watch << "." << std::endl << std::endl); } } else { STORM_PRINT_AND_LOG(" failed, property is unsupported by selected engine/settings." << std::endl); @@ -151,24 +251,118 @@ namespace storm { } } + template class ModelCheckerType, typename ModelType, typename ValueType, typename SolveValueType = double> + void verifyPropertiesAtSamplePoints(ModelType const& model, SymbolicInput const& input, SampleInformation const& samples) { + + // When samples are provided, we create an instantiation model checker. + ModelCheckerType modelchecker(model); + + for (auto const& property : input.properties) { + storm::cli::printModelCheckingProperty(property); + + modelchecker.specifyFormula(storm::api::createTask(property.getRawFormula(), true)); + modelchecker.setInstantiationsAreGraphPreserving(samples.graphPreserving); + + storm::utility::parametric::Valuation valuation; + + std::vector::type> parameters; + std::vector::type>::const_iterator> iterators; + std::vector::type>::const_iterator> iteratorEnds; + + storm::utility::Stopwatch watch(true); + for (auto const& product : samples.cartesianProducts) { + parameters.clear(); + iterators.clear(); + iteratorEnds.clear(); + + for (auto const& entry : product) { + parameters.push_back(entry.first); + iterators.push_back(entry.second.cbegin()); + iteratorEnds.push_back(entry.second.cend()); + } + + bool done = false; + while (!done) { + // Read off valuation. + for (uint64_t i = 0; i < parameters.size(); ++i) { + valuation[parameters[i]] = *iterators[i]; + } + + storm::utility::Stopwatch valuationWatch(true); + std::unique_ptr result = modelchecker.check(Environment(), valuation); + valuationWatch.stop(); + + if (result) { + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model.getInitialStates())); + } + printInitialStatesResult(result, property, &valuationWatch, &valuation); + + for (uint64_t i = 0; i < parameters.size(); ++i) { + ++iterators[i]; + if (iterators[i] == iteratorEnds[i]) { + // Reset iterator and proceed to move next iterator. + iterators[i] = product.at(parameters[i]).cbegin(); + + // If the last iterator was removed, we are done. + if (i == parameters.size() - 1) { + done = true; + } + } else { + // If an iterator was moved but not reset, we have another valuation to check. + break; + } + } + + } + } + + watch.stop(); + STORM_PRINT_AND_LOG("Overall time for sampling all instances: " << watch << std::endl << std::endl); + } + } + + template + void verifyPropertiesAtSamplePoints(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { + if (model->isOfType(storm::models::ModelType::Dtmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else if (model->isOfType(storm::models::ModelType::Ctmc)) { + verifyPropertiesAtSamplePoints, ValueType, SolveValueType>(*model->template as>(), input, samples); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Sampling is currently only supported for DTMCs, CTMCs and MDPs."); + } + } + template - void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input) { - verifyProperties(input.properties, - [&model] (std::shared_ptr const& formula) { - std::unique_ptr result = storm::api::verifyWithSparseEngine(model, storm::api::createTask(formula, true)); - if (result) { - result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); - } - return result; - }, - [&model] (std::unique_ptr const& result) { - auto parametricSettings = storm::settings::getModule(); - if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { - auto dtmc = model->template as>(); - boost::optional rationalFunction = result->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; - storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector(*dtmc), parametricSettings.exportResultPath()); - } - }); + void verifyPropertiesWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, SampleInformation const& samples) { + + if (samples.empty()) { + verifyProperties(input.properties, + [&model] (std::shared_ptr const& formula) { + std::unique_ptr result = storm::api::verifyWithSparseEngine(model, storm::api::createTask(formula, true)); + if (result) { + result->filter(storm::modelchecker::ExplicitQualitativeCheckResult(model->getInitialStates())); + } + return result; + }, + [&model] (std::unique_ptr const& result) { + auto parametricSettings = storm::settings::getModule(); + if (parametricSettings.exportResultToFile() && model->isOfType(storm::models::ModelType::Dtmc)) { + auto dtmc = model->template as>(); + boost::optional rationalFunction = result->asExplicitQuantitativeCheckResult()[*model->getInitialStates().begin()]; + storm::api::exportParametricResultToFile(rationalFunction, storm::analysis::ConstraintCollector(*dtmc), parametricSettings.exportResultPath()); + } + }); + } else { + STORM_LOG_TRACE("Sampling the model at given points."); + + if (samples.exact) { + verifyPropertiesAtSamplePoints(model, input, samples); + } else { + verifyPropertiesAtSamplePoints(model, input, samples); + } + } } template @@ -226,18 +420,18 @@ namespace storm { } template - void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions) { + void verifyWithSparseEngine(std::shared_ptr> const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { if (regions.empty()) { - storm::pars::verifyPropertiesWithSparseEngine(model, input); + storm::pars::verifyPropertiesWithSparseEngine(model, input, samples); } else { storm::pars::verifyRegionsWithSparseEngine(model, input, regions); } } template - void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions) { + void verifyParametricModel(std::shared_ptr const& model, SymbolicInput const& input, std::vector> const& regions, SampleInformation const& samples) { STORM_LOG_ASSERT(model->isSparseModel(), "Unexpected model type."); - storm::pars::verifyWithSparseEngine(model->as>(), input, regions); + storm::pars::verifyWithSparseEngine(model->as>(), input, regions, samples); } template @@ -271,9 +465,13 @@ namespace storm { } std::vector> regions = parseRegions(model); - - - + std::string samplesAsString = parSettings.getSamples(); + SampleInformation samples; + if (!samplesAsString.empty()) { + samples = parseSamples(model, samplesAsString, parSettings.isSamplesAreGraphPreservingSet()); + samples.exact = parSettings.isSampleExactSet(); + } + if (model) { storm::cli::exportModel(model, input); } @@ -285,7 +483,7 @@ namespace storm { } if (model) { - verifyParametricModel(model, input, regions); + verifyParametricModel(model, input, regions, samples); } } diff --git a/src/storm-pars/CMakeLists.txt b/src/storm-pars/CMakeLists.txt index 4e2ec1e0f..b91292be4 100644 --- a/src/storm-pars/CMakeLists.txt +++ b/src/storm-pars/CMakeLists.txt @@ -36,5 +36,5 @@ add_custom_target(copy_storm_pars_headers DEPENDS ${STORM_PARS_OUTPUT_HEADERS} $ add_dependencies(storm-pars copy_storm_pars_headers) # installation -install(TARGETS storm-pars RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm-pars EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp new file mode 100644 index 000000000..4af65eb19 --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.cpp @@ -0,0 +1,27 @@ +#include "storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h" + +#include "storm/modelchecker/csl/SparseCtmcCslModelChecker.h" + +#include "storm/exceptions/InvalidStateException.h" + +namespace storm { + namespace modelchecker { + + template + SparseCtmcInstantiationModelChecker::SparseCtmcInstantiationModelChecker(SparseModelType const& parametricModel) : SparseInstantiationModelChecker(parametricModel), modelInstantiator(parametricModel) { + //Intentionally left empty + } + + template + std::unique_ptr SparseCtmcInstantiationModelChecker::check(Environment const& env, storm::utility::parametric::Valuation const& valuation) { + STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); + auto const& instantiatedModel = modelInstantiator.instantiate(valuation); + storm::modelchecker::SparseCtmcCslModelChecker> modelChecker(instantiatedModel); + + return modelChecker.check(env, *this->currentCheckTask); + } + + template class SparseCtmcInstantiationModelChecker, double>; + template class SparseCtmcInstantiationModelChecker, storm::RationalNumber>; + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h new file mode 100644 index 000000000..4e4b7643f --- /dev/null +++ b/src/storm-pars/modelchecker/instantiation/SparseCtmcInstantiationModelChecker.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include "storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.h" +#include "storm-pars/utility/ModelInstantiator.h" +#include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/StandardRewardModel.h" +#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h" + +namespace storm { + namespace modelchecker { + + /*! + * Class to efficiently check a formula on a parametric model with different parameter instantiations. + */ + template + class SparseCtmcInstantiationModelChecker : public SparseInstantiationModelChecker { + public: + SparseCtmcInstantiationModelChecker(SparseModelType const& parametricModel); + + virtual std::unique_ptr check(Environment const& env, storm::utility::parametric::Valuation const& valuation) override; + + storm::utility::ModelInstantiator> modelInstantiator; + }; + } +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp index d13f3bf44..5de3d8fd3 100644 --- a/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp +++ b/src/storm-pars/modelchecker/instantiation/SparseDtmcInstantiationModelChecker.cpp @@ -20,11 +20,11 @@ namespace storm { std::unique_ptr SparseDtmcInstantiationModelChecker::check(Environment const& env, storm::utility::parametric::Valuation const& valuation) { STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); auto const& instantiatedModel = modelInstantiator.instantiate(valuation); - STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); + STORM_LOG_THROW(instantiatedModel.getTransitionMatrix().isProbabilistic(), storm::exceptions::InvalidArgumentException, "Instantiation point is invalid as the transition matrix becomes non-stochastic."); storm::modelchecker::SparseDtmcPrctlModelChecker> modelChecker(instantiatedModel); // Check if there are some optimizations implemented for the specified property - if(this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { + if (this->currentCheckTask->getFormula().isInFragment(storm::logic::reachability())) { return checkReachabilityProbabilityFormula(env, modelChecker); } else if (this->currentCheckTask->getFormula().isInFragment(storm::logic::propositional().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setOperatorAtTopLevelRequired(true).setNestedOperatorsAllowed(false))) { return checkReachabilityRewardFormula(env, modelChecker); @@ -144,4 +144,4 @@ namespace storm { template class SparseDtmcInstantiationModelChecker, storm::RationalNumber>; } -} \ No newline at end of file +} diff --git a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp index d81d5b9a6..7d5143a50 100644 --- a/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp +++ b/src/storm-pars/modelchecker/instantiation/SparseInstantiationModelChecker.cpp @@ -2,6 +2,7 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/models/sparse/Dtmc.h" +#include "storm/models/sparse/Ctmc.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -12,10 +13,9 @@ namespace storm { template SparseInstantiationModelChecker::SparseInstantiationModelChecker(SparseModelType const& parametricModel) : parametricModel(parametricModel), instantiationsAreGraphPreserving(false) { - //Intentionally left empty + // Intentionally left empty } - template void SparseInstantiationModelChecker::specifyFormula(storm::modelchecker::CheckTask const& checkTask) { currentFormula = checkTask.getFormula().asSharedPointer(); @@ -33,9 +33,11 @@ namespace storm { } template class SparseInstantiationModelChecker, double>; + template class SparseInstantiationModelChecker, double>; template class SparseInstantiationModelChecker, double>; template class SparseInstantiationModelChecker, storm::RationalNumber>; + template class SparseInstantiationModelChecker, storm::RationalNumber>; template class SparseInstantiationModelChecker, storm::RationalNumber>; } diff --git a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp index a2a6c0094..3dc4866d3 100644 --- a/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp +++ b/src/storm-pars/modelchecker/instantiation/SparseMdpInstantiationModelChecker.cpp @@ -23,7 +23,7 @@ namespace storm { std::unique_ptr SparseMdpInstantiationModelChecker::check(Environment const& env, storm::utility::parametric::Valuation const& valuation) { STORM_LOG_THROW(this->currentCheckTask, storm::exceptions::InvalidStateException, "Checking has been invoked but no property has been specified before."); auto const& instantiatedModel = modelInstantiator.instantiate(valuation); - STORM_LOG_ASSERT(instantiatedModel.getTransitionMatrix().isProbabilistic(), "Instantiated matrix is not probabilistic!"); + STORM_LOG_THROW(instantiatedModel.getTransitionMatrix().isProbabilistic(), storm::exceptions::InvalidArgumentException, "Instantiation point is invalid as the transition matrix becomes non-stochastic."); storm::modelchecker::SparseMdpPrctlModelChecker> modelChecker(instantiatedModel); // Check if there are some optimizations implemented for the specified property diff --git a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp index b5c2ab11e..a199b3781 100644 --- a/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp @@ -10,7 +10,8 @@ #include "storm/modelchecker/prctl/helper/BaierUpperRewardBoundsComputer.h" #include "storm/models/sparse/Dtmc.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/solver/StandardMinMaxLinearEquationSolver.h" +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/utility/vector.h" #include "storm/utility/graph.h" #include "storm/utility/NumberTraits.h" @@ -149,9 +150,9 @@ namespace storm { upperResultBound = storm::utility::one(); // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations). - auto req = solverFactory->getRequirements(env, true); + auto req = solverFactory->getRequirements(env, true, boost::none, true); req.clearBounds(); - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "Unchecked solver requirement."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solverFactory->setRequirementsChecked(true); } @@ -188,13 +189,13 @@ namespace storm { lowerResultBound = storm::utility::zero(); // The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations). - auto req = solverFactory->getRequirements(env, true); + auto req = solverFactory->getRequirements(env, true, boost::none, true); req.clearLowerBounds(); - if (req.requiresUpperBounds()) { + if (req.upperBounds()) { solvingRequiresUpperRewardBounds = true; req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "Unchecked solver requirement."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solverFactory->setRequirementsChecked(true); @@ -249,49 +250,50 @@ namespace storm { parameterLifter->specifyRegion(region, dirForParameters); - auto solver = solverFactory->create(env, parameterLifter->getMatrix()); - solver->setHasUniqueSolution(); - if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); - if (upperResultBound) { - solver->setUpperBound(upperResultBound.get()); - } else if (solvingRequiresUpperRewardBounds) { - // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17). - std::vector oneStepProbs; - oneStepProbs.reserve(parameterLifter->getMatrix().getRowCount()); - for (uint64_t row = 0; row < parameterLifter->getMatrix().getRowCount(); ++row) { - oneStepProbs.push_back(storm::utility::one() - parameterLifter->getMatrix().getRowSum(row)); - } - if (dirForParameters == storm::OptimizationDirection::Minimize) { - storm::modelchecker::helper::DsMpiMdpUpperRewardBoundsComputer dsmpi(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); - solver->setUpperBounds(dsmpi.computeUpperBounds()); - } else { - storm::modelchecker::helper::BaierUpperRewardBoundsComputer baier(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); - solver->setUpperBound(baier.computeUpperBound()); - } - } - if (!stepBound) solver->setTrackScheduler(true); - if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setInitialScheduler(std::move(minSchedChoices.get())); - if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setInitialScheduler(std::move(maxSchedChoices.get())); - if (this->currentCheckTask->isBoundSet() && solver->hasInitialScheduler()) { - // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize). - std::unique_ptr> termCond; - storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); - if (storm::solver::minimize(dirForParameters)) { - // Terminate if the value for ALL relevant states is already below the threshold - termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), false); - } else { - // Terminate if the value for ALL relevant states is already above the threshold - termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); - } - solver->setTerminationCondition(std::move(termCond)); - } - - // Invoke the solver if (stepBound) { assert(*stepBound > 0); x = std::vector(maybeStates.getNumberOfSetBits(), storm::utility::zero()); - solver->repeatedMultiply(env, dirForParameters, x, ¶meterLifter->getVector(), *stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, parameterLifter->getMatrix()); + multiplier->repeatedMultiplyAndReduce(env, dirForParameters, x, ¶meterLifter->getVector(), *stepBound); } else { + auto solver = solverFactory->create(env, parameterLifter->getMatrix()); + solver->setHasUniqueSolution(); + if (lowerResultBound) solver->setLowerBound(lowerResultBound.get()); + if (upperResultBound) { + solver->setUpperBound(upperResultBound.get()); + } else if (solvingRequiresUpperRewardBounds) { + // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17). + std::vector oneStepProbs; + oneStepProbs.reserve(parameterLifter->getMatrix().getRowCount()); + for (uint64_t row = 0; row < parameterLifter->getMatrix().getRowCount(); ++row) { + oneStepProbs.push_back(storm::utility::one() - parameterLifter->getMatrix().getRowSum(row)); + } + if (dirForParameters == storm::OptimizationDirection::Minimize) { + storm::modelchecker::helper::DsMpiMdpUpperRewardBoundsComputer dsmpi(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); + solver->setUpperBounds(dsmpi.computeUpperBounds()); + } else { + storm::modelchecker::helper::BaierUpperRewardBoundsComputer baier(parameterLifter->getMatrix(), parameterLifter->getVector(), oneStepProbs); + solver->setUpperBound(baier.computeUpperBound()); + } + } + solver->setTrackScheduler(true); + if (storm::solver::minimize(dirForParameters) && minSchedChoices) solver->setInitialScheduler(std::move(minSchedChoices.get())); + if (storm::solver::maximize(dirForParameters) && maxSchedChoices) solver->setInitialScheduler(std::move(maxSchedChoices.get())); + if (this->currentCheckTask->isBoundSet() && solver->hasInitialScheduler()) { + // If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize). + std::unique_ptr> termCond; + storm::storage::BitVector relevantStatesInSubsystem = this->currentCheckTask->isOnlyInitialStatesRelevantSet() ? this->parametricModel->getInitialStates() % maybeStates : storm::storage::BitVector(maybeStates.getNumberOfSetBits(), true); + if (storm::solver::minimize(dirForParameters)) { + // Terminate if the value for ALL relevant states is already below the threshold + termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), false); + } else { + // Terminate if the value for ALL relevant states is already above the threshold + termCond = std::make_unique> (relevantStatesInSubsystem, true, this->currentCheckTask->getBoundThreshold(), true); + } + solver->setTerminationCondition(std::move(termCond)); + } + + // Invoke the solver x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero()); solver->solveEquations(env, dirForParameters, x, parameterLifter->getVector()); if(storm::solver::minimize(dirForParameters)) { diff --git a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp index 0aa70d974..c58426f79 100644 --- a/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp +++ b/src/storm-pars/modelchecker/region/SparseMdpParameterLiftingModelChecker.cpp @@ -275,8 +275,8 @@ namespace storm { } // Invoke the solver - if(stepBound) { - assert(*stepBound > 0); + if (stepBound) { + STORM_LOG_ASSERT(*stepBound > 0, "Expected positive step bound."); solver->repeatedMultiply(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound); } else { solver->solveGame(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector()); @@ -293,7 +293,7 @@ namespace storm { // Get the result for the complete model (including maybestates) std::vector result = resultsForNonMaybeStates; auto maybeStateResIt = x.begin(); - for(auto const& maybeState : maybeStates) { + for (auto const& maybeState : maybeStates) { result[maybeState] = *maybeStateResIt; ++maybeStateResIt; } diff --git a/src/storm-pars/settings/ParsSettings.cpp b/src/storm-pars/settings/ParsSettings.cpp index e36793b04..d819f8e24 100644 --- a/src/storm-pars/settings/ParsSettings.cpp +++ b/src/storm-pars/settings/ParsSettings.cpp @@ -1,4 +1,3 @@ -#include #include "storm-pars/settings/ParsSettings.h" #include "storm-pars/settings/modules/ParametricSettings.h" @@ -9,19 +8,20 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/BuildSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/DebugSettings.h" #include "storm/settings/modules/SylvanSettings.h" #include "storm/settings/modules/EigenEquationSolverSettings.h" #include "storm/settings/modules/GmmxxEquationSolverSettings.h" #include "storm/settings/modules/NativeEquationSolverSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/EliminationSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GameSolverSettings.h" #include "storm/settings/modules/BisimulationSettings.h" -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" #include "storm/settings/modules/ResourceSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" +#include "storm/settings/modules/MultiplierSettings.h" namespace storm { @@ -36,23 +36,21 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); - - + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); } } -} \ No newline at end of file +} diff --git a/src/storm-pars/settings/modules/ParametricSettings.cpp b/src/storm-pars/settings/modules/ParametricSettings.cpp index 28975aa5c..7ecbd6166 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.cpp +++ b/src/storm-pars/settings/modules/ParametricSettings.cpp @@ -18,13 +18,20 @@ namespace storm { const std::string ParametricSettings::transformContinuousOptionName = "transformcontinuous"; const std::string ParametricSettings::transformContinuousShortOptionName = "tc"; const std::string ParametricSettings::onlyWellformednessConstraintsOptionName = "onlyconstraints"; - + const std::string ParametricSettings::samplesOptionName = "samples"; + const std::string ParametricSettings::samplesGraphPreservingOptionName = "samples-graph-preserving"; + const std::string ParametricSettings::sampleExactOptionName = "sample-exact"; + ParametricSettings::ParametricSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, exportResultOptionName, false, "A path to a file where the parametric result should be saved.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("path", "the location.").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, derivativesOptionName, false, "Sets whether to generate the derivatives of the resulting rational function.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, transformContinuousOptionName, false, "Sets whether to transform a continuous time input model to a discrete time model.").setShortName(transformContinuousShortOptionName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, onlyWellformednessConstraintsOptionName, false, "Sets whether you only want to obtain the wellformedness constraints").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, samplesOptionName, false, "The points at which to sample the model.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("samples", "The samples are semicolon-separated entries of the form 'Var1=Val1:Val2:...:Valk,Var2=... that span the sample spaces.").setDefaultValueString("").build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, samplesGraphPreservingOptionName, false, "Sets whether it can be assumed that the samples are graph-preserving.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, sampleExactOptionName, false, "Sets whether to sample using exact arithmetic.").build()); } bool ParametricSettings::exportResultToFile() const { @@ -46,7 +53,19 @@ namespace storm { bool ParametricSettings::onlyObtainConstraints() const { return this->getOption(onlyWellformednessConstraintsOptionName).getHasOptionBeenSet(); } - + + std::string ParametricSettings::getSamples() const { + return this->getOption(samplesOptionName).getArgumentByName("samples").getValueAsString(); + } + + bool ParametricSettings::isSamplesAreGraphPreservingSet() const { + return this->getOption(samplesGraphPreservingOptionName).getHasOptionBeenSet(); + } + + bool ParametricSettings::isSampleExactSet() const { + return this->getOption(sampleExactOptionName).getHasOptionBeenSet(); + } + } // namespace modules } // namespace settings } // namespace storm diff --git a/src/storm-pars/settings/modules/ParametricSettings.h b/src/storm-pars/settings/modules/ParametricSettings.h index e610f033d..1f10a4b35 100644 --- a/src/storm-pars/settings/modules/ParametricSettings.h +++ b/src/storm-pars/settings/modules/ParametricSettings.h @@ -47,6 +47,23 @@ namespace storm { */ bool onlyObtainConstraints() const; + /*! + * Retrieves the samples as a comma-separated list of samples for each (relevant) variable, where the + * samples are colon-separated values. For example, 'N=1:2:3,K=2:4' means that N takes the values 1 to + * 3 and K either 2 or 4. + */ + std::string getSamples() const; + + /*! + * Retrieves whether the samples are graph preserving. + */ + bool isSamplesAreGraphPreservingSet() const; + + /*! + * Retrieves whether samples are to be computed exactly. + */ + bool isSampleExactSet() const; + const static std::string moduleName; private: @@ -55,6 +72,9 @@ namespace storm { const static std::string transformContinuousOptionName; const static std::string transformContinuousShortOptionName; const static std::string onlyWellformednessConstraintsOptionName; + const static std::string samplesOptionName; + const static std::string samplesGraphPreservingOptionName; + const static std::string sampleExactOptionName; }; } // namespace modules diff --git a/src/storm-parsers/CMakeLists.txt b/src/storm-parsers/CMakeLists.txt new file mode 100644 index 000000000..24d9532b5 --- /dev/null +++ b/src/storm-parsers/CMakeLists.txt @@ -0,0 +1,42 @@ +file(GLOB_RECURSE ALL_FILES ${PROJECT_SOURCE_DIR}/src/storm-parsers/*.h ${PROJECT_SOURCE_DIR}/src/storm-parsers/*.cpp) + +register_source_groups_from_filestructure("${ALL_FILES}" storm-parsers) + + + +file(GLOB_RECURSE STORM_PARSER_SOURCES ${PROJECT_SOURCE_DIR}/src/storm-parsers/*/*.cpp) +file(GLOB_RECURSE STORM_PARSER_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-parsers/*/*.h) + + +# Disable Debug compiler flags for PrismParser to lessen memory consumption during compilation +SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/storm-parsers/parser/PrismParser.cpp PROPERTIES COMPILE_FLAGS -g0) +# Create storm-parsers. +add_library(storm-parsers SHARED ${STORM_PARSER_SOURCES} ${STORM_PARSER_HEADERS}) + +# Remove define symbol for shared libstorm. +set_target_properties(storm-parsers PROPERTIES DEFINE_SYMBOL "") +#add_dependencies(storm resources) +list(APPEND STORM_TARGETS storm-parsers) +set(STORM_TARGETS ${STORM_TARGETS} PARENT_SCOPE) + +target_link_libraries(storm-parsers PUBLIC storm) + +# Install storm headers to include directory. +foreach(HEADER ${STORM_PARSER_HEADERS}) + string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/src/?" "" RELATIVE_HEADER_PATH ${HEADER}) + string(REGEX MATCH "(.*)[/\\]" RELATIVE_DIRECTORY ${RELATIVE_HEADER_PATH}) + string(REGEX REPLACE "${RELATIVE_DIRECTORY}/?" "" HEADER_FILENAME ${RELATIVE_HEADER_PATH}) + add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME} + DEPENDS ${HEADER} + ) + list(APPEND STORM_PARSER_OUTPUT_HEADERS "${CMAKE_BINARY_DIR}/include/${RELATIVE_DIRECTORY}${HEADER_FILENAME}") +endforeach() +add_custom_target(copy_storm_parser_headers DEPENDS ${STORM_PARSER_OUTPUT_HEADERS} ${STORM_PARSER_HEADERS}) +add_dependencies(storm-parsers copy_storm_parser_headers) + +# installation +install(TARGETS storm-parsers EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) + diff --git a/src/storm-parsers/api/model_descriptions.cpp b/src/storm-parsers/api/model_descriptions.cpp new file mode 100644 index 000000000..983156279 --- /dev/null +++ b/src/storm-parsers/api/model_descriptions.cpp @@ -0,0 +1,69 @@ +#include "model_descriptions.h" + +#include "storm-parsers/parser/PrismParser.h" +#include "storm-parsers/parser/JaniParser.h" + +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + +#include "storm/exceptions/NotSupportedException.h" +#include "storm/utility/macros.h" + + +namespace storm { + namespace api { + + storm::prism::Program parseProgram(std::string const& filename, bool prismCompatibility, bool simplify) { + storm::prism::Program program = storm::parser::PrismParser::parse(filename, prismCompatibility); + if (simplify) { + program = program.simplify().simplify(); + } + program.checkValidity(); + return program; + } + + std::pair> parseJaniModel(std::string const& filename) { + storm::jani::ModelFeatures features; + // Add derived-operators and state-exit-rewards as these can be handled by all model builders + features.add(storm::jani::ModelFeature::DerivedOperators); + features.add(storm::jani::ModelFeature::StateExitRewards); + auto parsedResult = parseJaniModel(filename, features); + std::map propertyMap; + for (auto const& property : parsedResult.second) { + propertyMap.emplace(property.getName(), property); + } + return std::make_pair(std::move(parsedResult.first), std::move(propertyMap)); + } + + std::pair> parseJaniModel(std::string const& filename, storm::jani::ModelFeatures const& allowedFeatures, boost::optional> const& propertyFilter) { + + bool parseProperties = !propertyFilter.is_initialized() || !propertyFilter.get().empty(); + std::pair> modelAndFormulae = storm::parser::JaniParser::parse(filename, parseProperties); + + // eliminate unselected properties. + if (propertyFilter.is_initialized()) { + std::vector newProperties; + // Make sure to preserve the provided order + for (auto const& propName : propertyFilter.get()) { + bool found = false; + for (auto const& property : modelAndFormulae.second) { + if (property.getName() == propName) { + newProperties.push_back(std::move(property)); + found = true; + break; + } + } + STORM_LOG_ERROR_COND(found, "No JANI property with name '" << propName << "' is known."); + } + modelAndFormulae.second = std::move(newProperties); + } + + modelAndFormulae.first.checkValid(); + auto nonEliminatedFeatures = modelAndFormulae.first.restrictToFeatures(allowedFeatures, modelAndFormulae.second); + STORM_LOG_THROW(nonEliminatedFeatures.empty(), storm::exceptions::NotSupportedException, "The used model feature(s) " << nonEliminatedFeatures.toString() << " is/are not in the list of allowed features."); + return modelAndFormulae; + } + + + } +} diff --git a/src/storm/api/model_descriptions.h b/src/storm-parsers/api/model_descriptions.h similarity index 52% rename from src/storm/api/model_descriptions.h rename to src/storm-parsers/api/model_descriptions.h index 533c5e8d1..8e45304c3 100644 --- a/src/storm/api/model_descriptions.h +++ b/src/storm-parsers/api/model_descriptions.h @@ -2,6 +2,8 @@ #include #include +#include +#include namespace storm { namespace prism { @@ -9,14 +11,15 @@ namespace storm { } namespace jani { class Model; + class ModelFeatures; class Property; } namespace api { - storm::prism::Program parseProgram(std::string const& filename, bool prismCompatibility = false); + storm::prism::Program parseProgram(std::string const& filename, bool prismCompatibility = false, bool simplify = true); std::pair> parseJaniModel(std::string const& filename); - + std::pair> parseJaniModel(std::string const& filename, storm::jani::ModelFeatures const& allowedFeatures, boost::optional> const& propertyFilter = boost::none); } } diff --git a/src/storm-parsers/api/properties.cpp b/src/storm-parsers/api/properties.cpp new file mode 100644 index 000000000..5c75a2eb5 --- /dev/null +++ b/src/storm-parsers/api/properties.cpp @@ -0,0 +1,75 @@ +#include "storm-parsers/api/properties.h" + +#include "storm-parsers/parser/FormulaParser.h" +#include "storm/api/properties.h" + +#include "storm/storage/SymbolicModelDescription.h" +#include "storm/logic/RewardAccumulationEliminationVisitor.h" + +#include "storm/storage/prism/Program.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + +#include "storm/logic/Formula.h" + +#include "storm/utility/cli.h" + + +namespace storm { + namespace api { + + boost::optional> parsePropertyFilter(std::string const& propertyFilter) { + if (propertyFilter == "all") { + return boost::none; + } + std::vector propertyNames = storm::utility::cli::parseCommaSeparatedStrings(propertyFilter); + std::set propertyNameSet(propertyNames.begin(), propertyNames.end()); + return propertyNameSet; + } + + std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter) { + // If the given property is a file, we parse it as a file, otherwise we assume it's a property. + std::vector properties; + if (std::ifstream(inputString).good()) { + STORM_LOG_INFO("Loading properties from file: " << inputString << std::endl); + properties = formulaParser.parseFromFile(inputString); + } else { + properties = formulaParser.parseFromString(inputString); + } + + return filterProperties(properties, propertyFilter); + } + + std::vector parseProperties(std::string const& inputString, boost::optional > const& propertyFilter) { + auto exprManager = std::make_shared(); + storm::parser::FormulaParser formulaParser(exprManager); + return parseProperties(formulaParser, inputString, propertyFilter); + } + + std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional > const& propertyFilter) { + storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); + auto formulas = parseProperties(formulaParser, inputString, propertyFilter); + // Eliminate reward accumulations if possible + storm::logic::RewardAccumulationEliminationVisitor v(model); + v.eliminateRewardAccumulations(formulas); + return substituteConstantsInProperties(formulas, model.getConstantsSubstitution()); + } + + std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional > const& propertyFilter) { + storm::parser::FormulaParser formulaParser(program); + auto formulas = parseProperties(formulaParser, inputString, propertyFilter); + return substituteConstantsInProperties(formulas, program.getConstantsFormulasSubstitution()); + } + + std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional > const& propertyFilter) { + std::vector result; + if (modelDescription.isPrismProgram()) { + result = storm::api::parsePropertiesForPrismProgram(inputString, modelDescription.asPrismProgram(), propertyFilter); + } else { + STORM_LOG_ASSERT(modelDescription.isJaniModel(), "Unknown model description type."); + result = storm::api::parsePropertiesForJaniModel(inputString, modelDescription.asJaniModel(), propertyFilter); + } + return result; + } + } +} diff --git a/src/storm-parsers/api/properties.h b/src/storm-parsers/api/properties.h new file mode 100644 index 000000000..81d37d965 --- /dev/null +++ b/src/storm-parsers/api/properties.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace storm { + namespace parser { + class FormulaParser; + } + namespace jani { + class Property; + class Model; + } + namespace expressions { + class Variable; + class Expression; + } + namespace prism { + class Program; + } + namespace storage { + class SymbolicModelDescription; + } + namespace logic { + class Formula; + } + + namespace api { + boost::optional> parsePropertyFilter(std::string const& propertyFilter); + + // Parsing properties. + std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter = boost::none); + std::vector parseProperties(std::string const& inputString, boost::optional> const& propertyFilter = boost::none); + std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter = boost::none); + std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter = boost::none); + std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional> const& propertyFilter = boost::none); + + } +} diff --git a/src/storm-parsers/api/storm-parsers.h b/src/storm-parsers/api/storm-parsers.h new file mode 100644 index 000000000..b88188976 --- /dev/null +++ b/src/storm-parsers/api/storm-parsers.h @@ -0,0 +1,4 @@ +#pragma once + +#include "storm-parsers/api/model_descriptions.h" +#include "storm-parsers/api/properties.h" \ No newline at end of file diff --git a/src/storm/parser/AtomicPropositionLabelingParser.cpp b/src/storm-parsers/parser/AtomicPropositionLabelingParser.cpp similarity index 98% rename from src/storm/parser/AtomicPropositionLabelingParser.cpp rename to src/storm-parsers/parser/AtomicPropositionLabelingParser.cpp index 4d55b4fe8..a8afc93d7 100644 --- a/src/storm/parser/AtomicPropositionLabelingParser.cpp +++ b/src/storm-parsers/parser/AtomicPropositionLabelingParser.cpp @@ -5,14 +5,14 @@ * Author: Gereon Kremer */ -#include "storm/parser/AtomicPropositionLabelingParser.h" +#include "storm-parsers/parser/AtomicPropositionLabelingParser.h" #include #include #include #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/storm/parser/AtomicPropositionLabelingParser.h b/src/storm-parsers/parser/AtomicPropositionLabelingParser.h similarity index 100% rename from src/storm/parser/AtomicPropositionLabelingParser.h rename to src/storm-parsers/parser/AtomicPropositionLabelingParser.h diff --git a/src/storm/parser/AutoParser.cpp b/src/storm-parsers/parser/AutoParser.cpp similarity index 95% rename from src/storm/parser/AutoParser.cpp rename to src/storm-parsers/parser/AutoParser.cpp index 896c4215e..9e96af5e6 100644 --- a/src/storm/parser/AutoParser.cpp +++ b/src/storm-parsers/parser/AutoParser.cpp @@ -1,12 +1,12 @@ -#include "storm/parser/AutoParser.h" +#include "storm-parsers/parser/AutoParser.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" -#include "storm/parser/DeterministicModelParser.h" -#include "storm/parser/NondeterministicModelParser.h" -#include "storm/parser/MarkovAutomatonParser.h" +#include "storm-parsers/parser/DeterministicModelParser.h" +#include "storm-parsers/parser/NondeterministicModelParser.h" +#include "storm-parsers/parser/MarkovAutomatonParser.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm/parser/AutoParser.h b/src/storm-parsers/parser/AutoParser.h similarity index 100% rename from src/storm/parser/AutoParser.h rename to src/storm-parsers/parser/AutoParser.h diff --git a/src/storm/parser/DeterministicModelParser.cpp b/src/storm-parsers/parser/DeterministicModelParser.cpp similarity index 95% rename from src/storm/parser/DeterministicModelParser.cpp rename to src/storm-parsers/parser/DeterministicModelParser.cpp index cfe5a16df..6b81c0630 100644 --- a/src/storm/parser/DeterministicModelParser.cpp +++ b/src/storm-parsers/parser/DeterministicModelParser.cpp @@ -1,13 +1,13 @@ -#include "storm/parser/DeterministicModelParser.h" +#include "storm-parsers/parser/DeterministicModelParser.h" #include #include #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/DeterministicSparseTransitionParser.h" -#include "storm/parser/SparseItemLabelingParser.h" -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/DeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/adapters/RationalFunctionAdapter.h" diff --git a/src/storm/parser/DeterministicModelParser.h b/src/storm-parsers/parser/DeterministicModelParser.h similarity index 100% rename from src/storm/parser/DeterministicModelParser.h rename to src/storm-parsers/parser/DeterministicModelParser.h diff --git a/src/storm/parser/DeterministicSparseTransitionParser.cpp b/src/storm-parsers/parser/DeterministicSparseTransitionParser.cpp similarity index 99% rename from src/storm/parser/DeterministicSparseTransitionParser.cpp rename to src/storm-parsers/parser/DeterministicSparseTransitionParser.cpp index 540371f74..229cc3c2e 100644 --- a/src/storm/parser/DeterministicSparseTransitionParser.cpp +++ b/src/storm-parsers/parser/DeterministicSparseTransitionParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/DeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/DeterministicSparseTransitionParser.h" #include #include @@ -9,7 +9,7 @@ #include "storm/utility/constants.h" #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" diff --git a/src/storm/parser/DeterministicSparseTransitionParser.h b/src/storm-parsers/parser/DeterministicSparseTransitionParser.h similarity index 100% rename from src/storm/parser/DeterministicSparseTransitionParser.h rename to src/storm-parsers/parser/DeterministicSparseTransitionParser.h diff --git a/src/storm/parser/DirectEncodingParser.cpp b/src/storm-parsers/parser/DirectEncodingParser.cpp similarity index 61% rename from src/storm/parser/DirectEncodingParser.cpp rename to src/storm-parsers/parser/DirectEncodingParser.cpp index c2c1a5998..160ada212 100644 --- a/src/storm/parser/DirectEncodingParser.cpp +++ b/src/storm-parsers/parser/DirectEncodingParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/DirectEncodingParser.h" +#include "storm-parsers/parser/DirectEncodingParser.h" #include #include @@ -25,32 +25,6 @@ namespace storm { namespace parser { - template - void ValueParser::addParameter(std::string const& parameter) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); - } - - template<> - void ValueParser::addParameter(std::string const& parameter) { - //STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); - storm::expressions::Variable var = manager->declareRationalVariable(parameter); - identifierMapping.emplace(var.getName(), var); - parser.setIdentifierMapping(identifierMapping); - STORM_LOG_TRACE("Added parameter: " << var.getName()); - } - - template<> - double ValueParser::parseValue(std::string const& value) const { - return boost::lexical_cast(value); - } - - template<> - storm::RationalFunction ValueParser::parseValue(std::string const& value) const { - storm::RationalFunction rationalFunction = evaluator.asRational(parser.parseFromString(value)); - STORM_LOG_TRACE("Parsed expression: " << rationalFunction); - return rationalFunction; - } - template std::shared_ptr> DirectEncodingParser::parseModel(std::string const& filename) { @@ -66,26 +40,26 @@ namespace storm { bool sawParameters = false; size_t nrStates = 0; storm::models::ModelType type; - std::vector rewardModelNames; - - std::shared_ptr> modelComponents; + std::shared_ptr> modelComponents; // Parse header - while(std::getline(file, line)) { - if(line.empty() || boost::starts_with(line, "//")) { + while (std::getline(file, line)) { + if (line.empty() || boost::starts_with(line, "//")) { continue; } if (boost::starts_with(line, "@type: ")) { + // Parse type STORM_LOG_THROW(!sawType, storm::exceptions::WrongFormatException, "Type declared twice"); type = storm::models::getModelType(line.substr(7)); STORM_LOG_TRACE("Model type: " << type); - STORM_LOG_THROW(type != storm::models::ModelType::MarkovAutomaton, storm::exceptions::NotSupportedException, "Markov Automata in DRN format are not supported (unclear indication of Markovian Choices in DRN format)"); STORM_LOG_THROW(type != storm::models::ModelType::S2pg, storm::exceptions::NotSupportedException, "Stochastic Two Player Games in DRN format are not supported."); sawType = true; - } - if(line == "@parameters") { + + } else if (line == "@parameters") { + // Parse parameters + STORM_LOG_THROW(!sawParameters, storm::exceptions::WrongFormatException, "Parameters declared twice"); std::getline(file, line); if (line != "") { std::vector parameters; @@ -96,26 +70,28 @@ namespace storm { } } sawParameters = true; - } - if(line == "@reward_models") { + + } else if (line == "@reward_models") { + // Parse reward models STORM_LOG_THROW(rewardModelNames.size() == 0, storm::exceptions::WrongFormatException, "Reward model names declared twice"); std::getline(file, line); boost::split(rewardModelNames, line, boost::is_any_of("\t ")); - } - if(line == "@nr_states") { + } else if (line == "@nr_states") { + // Parse no. of states STORM_LOG_THROW(nrStates == 0, storm::exceptions::WrongFormatException, "Number states declared twice"); std::getline(file, line); - nrStates = boost::lexical_cast(line); - - } - if(line == "@model") { + nrStates = NumberParser::parse(line); + } else if (line == "@model") { + // Parse rest of the model STORM_LOG_THROW(sawType, storm::exceptions::WrongFormatException, "Type has to be declared before model."); STORM_LOG_THROW(sawParameters, storm::exceptions::WrongFormatException, "Parameters have to be declared before model."); - STORM_LOG_THROW(nrStates != 0, storm::exceptions::WrongFormatException, "Nr States has to be declared before model."); + STORM_LOG_THROW(nrStates != 0, storm::exceptions::WrongFormatException, "No. of states has to be declared before model."); // Construct model components modelComponents = parseStates(file, type, nrStates, valueParser, rewardModelNames); break; + } else { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse line '" << line << "'."); } } // Done parsing @@ -130,23 +106,29 @@ namespace storm { // Initialize auto modelComponents = std::make_shared>(); bool nonDeterministic = (type == storm::models::ModelType::Mdp || type == storm::models::ModelType::MarkovAutomaton || type == storm::models::ModelType::Pomdp); + bool continousTime = (type == storm::models::ModelType::Ctmc || type == storm::models::ModelType::MarkovAutomaton); storm::storage::SparseMatrixBuilder builder = storm::storage::SparseMatrixBuilder(0, 0, 0, false, nonDeterministic, 0); modelComponents->stateLabeling = storm::models::sparse::StateLabeling(stateSize); modelComponents->observabilityClasses = std::vector(); modelComponents->observabilityClasses->resize(stateSize); std::vector> stateRewards; - + if (continousTime) { + modelComponents->exitRates = std::vector(stateSize); + if (type == storm::models::ModelType::MarkovAutomaton) { + modelComponents->markovianStates = storm::storage::BitVector(stateSize); + } + } // We parse rates for continuous time models. if (type == storm::models::ModelType::Ctmc) { modelComponents->rateTransitions = true; } - + // Iterate over all lines std::string line; size_t row = 0; size_t state = 0; bool firstState = true; - bool firstAction = true; + bool firstActionForState = true; while (std::getline(file, line)) { STORM_LOG_TRACE("Parsing: " << line); if (boost::starts_with(line, "state ")) { @@ -155,48 +137,83 @@ namespace storm { firstState = false; } else { ++state; + ++row; } - line = line.substr(6); - size_t parsedId; - size_t posId = line.find(" "); - if (posId != std::string::npos) { - parsedId = boost::lexical_cast(line.substr(0, posId)); + firstActionForState = true; + STORM_LOG_TRACE("New state " << state); - // Parse rewards and labels - line = line.substr(posId+1); - // Check for rewards - if (boost::starts_with(line, "[")) { - // Rewards found - size_t posEndReward = line.find(']'); - STORM_LOG_THROW(posEndReward != std::string::npos, storm::exceptions::WrongFormatException, "] missing."); - std::string rewardsStr = line.substr(1, posEndReward-1); - STORM_LOG_TRACE("State rewards: " << rewardsStr); - std::vector rewards; - boost::split(rewards, rewardsStr, boost::is_any_of(",")); - if (stateRewards.size() < rewards.size()) { - stateRewards.resize(rewards.size(), std::vector(stateSize, storm::utility::zero())); - } - auto stateRewardsIt = stateRewards.begin(); - for (auto const& rew : rewards) { - (*stateRewardsIt)[state] = valueParser.parseValue(rew); - ++stateRewardsIt; - } - line = line.substr(posEndReward+1); + // Parse state id + line = line.substr(6); // Remove "state " + std::string curString = line; + size_t posEnd = line.find(" "); + if (posEnd != std::string::npos) { + curString = line.substr(0, posEnd); + line = line.substr(posEnd+1); + } else { + line = ""; + } + size_t parsedId = NumberParser::parse(curString); + STORM_LOG_ASSERT(state == parsedId, "State ids do not correspond."); + if (nonDeterministic) { + STORM_LOG_TRACE("new Row Group starts at " << row << "."); + builder.newRowGroup(row); + } + + if (type == storm::models::ModelType::Ctmc || type == storm::models::ModelType::MarkovAutomaton) { + // Parse exit rate for CTMC or MA + STORM_LOG_THROW(boost::starts_with(line, "!"), storm::exceptions::WrongFormatException, "Exit rate missing."); + line = line.substr(1); //Remove "!" + curString = line; + posEnd = line.find(" "); + if (posEnd != std::string::npos) { + curString = line.substr(0, posEnd); + line = line.substr(posEnd+1); + } else { + line = ""; + } + ValueType exitRate = valueParser.parseValue(curString); + if (type == storm::models::ModelType::MarkovAutomaton && !storm::utility::isZero(exitRate)) { + modelComponents->markovianStates.get().set(state); } + STORM_LOG_TRACE("Exit rate " << exitRate); + modelComponents->exitRates.get()[state] = exitRate; + } - if (type == storm::models::ModelType::Pomdp) { - if (boost::starts_with(line, "{")) { - size_t posEndObservation = line.find("}"); - std::string observation = line.substr(1, posEndObservation-1); - STORM_LOG_TRACE("State observation " << observation); - modelComponents->observabilityClasses.get()[state] = std::stoi(observation); - line = line.substr(posEndObservation+1); - } else { - STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Expected an observation for state " << state << "."); - } + if (boost::starts_with(line, "[")) { + // Parse rewards + size_t posEndReward = line.find(']'); + STORM_LOG_THROW(posEndReward != std::string::npos, storm::exceptions::WrongFormatException, "] missing."); + std::string rewardsStr = line.substr(1, posEndReward-1); + STORM_LOG_TRACE("State rewards: " << rewardsStr); + std::vector rewards; + boost::split(rewards, rewardsStr, boost::is_any_of(",")); + if (stateRewards.size() < rewards.size()) { + stateRewards.resize(rewards.size(), std::vector(stateSize, storm::utility::zero())); + } + auto stateRewardsIt = stateRewards.begin(); + for (auto const& rew : rewards) { + (*stateRewardsIt)[state] = valueParser.parseValue(rew); + ++stateRewardsIt; } - // Check for labels + line = line.substr(posEndReward+1); + } + + + if (type == storm::models::ModelType::Pomdp) { + if (boost::starts_with(line, "{")) { + size_t posEndObservation = line.find("}"); + std::string observation = line.substr(1, posEndObservation-1); + STORM_LOG_TRACE("State observation " << observation); + modelComponents->observabilityClasses.get()[state] = std::stoi(observation); + line = line.substr(posEndObservation+1); + } else { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Expected an observation for state " << state << "."); + } + } + + // Parse labels + if (!line.empty()) { std::vector labels; boost::split(labels, line, boost::is_any_of(" ")); for (std::string label : labels) { @@ -204,27 +221,19 @@ namespace storm { modelComponents->stateLabeling.addLabel(label); } modelComponents->stateLabeling.addLabelToState(label, state); - STORM_LOG_TRACE("New label: " << label); + STORM_LOG_TRACE("New label: '" << label << "'"); } - } else { - // Only state id given - parsedId = boost::lexical_cast(line); - } - STORM_LOG_TRACE("New state " << state); - STORM_LOG_ASSERT(state == parsedId, "State ids do not correspond."); - if (nonDeterministic) { - STORM_LOG_TRACE("new Row Group starts at " << row << "."); - builder.newRowGroup(row); } + } else if (boost::starts_with(line, "\taction ")) { // New action - if (firstAction) { - firstAction = false; + if (firstActionForState) { + firstActionForState = false; } else { ++row; } - line = line.substr(8); STORM_LOG_TRACE("New action: " << row); + line = line.substr(8); //Remove "\taction " // Check for rewards if (boost::starts_with(line, "[")) { // Rewards found @@ -241,8 +250,8 @@ namespace storm { } else { // New transition size_t posColon = line.find(":"); - STORM_LOG_ASSERT(posColon != std::string::npos, "':' not found."); - size_t target = boost::lexical_cast(line.substr(2, posColon-3)); + STORM_LOG_THROW(posColon != std::string::npos, storm::exceptions::WrongFormatException, "':' not found."); + size_t target = NumberParser::parse(line.substr(2, posColon-3)); std::string valueStr = line.substr(posColon+2); ValueType value = valueParser.parseValue(valueStr); STORM_LOG_TRACE("Transition " << row << " -> " << target << ": " << value); @@ -268,9 +277,7 @@ namespace storm { // Template instantiations. template class DirectEncodingParser; - -#ifdef STORM_HAVE_CARL template class DirectEncodingParser; -#endif + } // namespace parser } // namespace storm diff --git a/src/storm/parser/DirectEncodingParser.h b/src/storm-parsers/parser/DirectEncodingParser.h similarity index 55% rename from src/storm/parser/DirectEncodingParser.h rename to src/storm-parsers/parser/DirectEncodingParser.h index db1bac12e..f025b8dfc 100644 --- a/src/storm/parser/DirectEncodingParser.h +++ b/src/storm-parsers/parser/DirectEncodingParser.h @@ -1,53 +1,14 @@ #ifndef STORM_PARSER_DIRECTENCODINGPARSER_H_ #define STORM_PARSER_DIRECTENCODINGPARSER_H_ +#include "storm-parsers/parser/ValueParser.h" #include "storm/models/sparse/Model.h" #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" -#include "storm/storage/expressions/ExpressionEvaluator.h" #include "storm/storage/sparse/ModelComponents.h" namespace storm { namespace parser { - /*! - * Parser for values according to their ValueType. - */ - template - class ValueParser { - public: - - ValueParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { - } - - /*! - * Parse ValueType from string. - * - * @param value String containing the value. - * - * @return ValueType - */ - ValueType parseValue(std::string const& value) const; - - /*! - * Add declaration of parameter. - * - * @param parameter New parameter. - */ - void addParameter(std::string const& parameter); - - private: - - std::shared_ptr manager; - - storm::parser::ExpressionParser parser; - - storm::expressions::ExpressionEvaluator evaluator; - - std::unordered_map identifierMapping; - }; - /*! * Parser for models in the DRN format with explicit encoding. */ diff --git a/src/storm/parser/ExpressionCreator.cpp b/src/storm-parsers/parser/ExpressionCreator.cpp similarity index 96% rename from src/storm/parser/ExpressionCreator.cpp rename to src/storm-parsers/parser/ExpressionCreator.cpp index 6266206ef..682342e29 100644 --- a/src/storm/parser/ExpressionCreator.cpp +++ b/src/storm-parsers/parser/ExpressionCreator.cpp @@ -16,6 +16,12 @@ namespace storm { // Intenetionally left empty. } + ExpressionCreator::~ExpressionCreator() { + if (deleteIdentifierMapping) { + delete this->identifiers; + } + } + storm::expressions::Expression ExpressionCreator::createIteExpression(storm::expressions::Expression const& e1, storm::expressions::Expression const& e2, storm::expressions::Expression const& e3, bool& pass) const { if (this->createExpressions) { try { @@ -120,11 +126,12 @@ namespace storm { return manager.boolean(false); } - storm::expressions::Expression ExpressionCreator::createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const { + storm::expressions::Expression ExpressionCreator::createPowerModuloExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const { if (this->createExpressions) { try { switch (operatorType) { case storm::expressions::OperatorType::Power: return e1 ^ e2; break; + case storm::expressions::OperatorType::Modulo: return e1 % e2; break; default: STORM_LOG_ASSERT(false, "Invalid operation."); break; } } catch (storm::exceptions::InvalidTypeException const& e) { @@ -240,7 +247,7 @@ namespace storm { void ExpressionCreator::setIdentifierMapping(std::unordered_map const& identifierMapping) { unsetIdentifierMapping(); - createExpressions =true; + createExpressions = true; identifiers = new qi::symbols(); for (auto const& identifierExpressionPair : identifierMapping) { identifiers->add(identifierExpressionPair.first, identifierExpressionPair.second); @@ -256,9 +263,6 @@ namespace storm { } this->identifiers = nullptr; } - - - } } diff --git a/src/storm/parser/ExpressionCreator.h b/src/storm-parsers/parser/ExpressionCreator.h similarity index 92% rename from src/storm/parser/ExpressionCreator.h rename to src/storm-parsers/parser/ExpressionCreator.h index bf454c552..4c137325b 100644 --- a/src/storm/parser/ExpressionCreator.h +++ b/src/storm-parsers/parser/ExpressionCreator.h @@ -1,7 +1,7 @@ #pragma once #include // Very ugly, but currently we would like to have the symbol table here. -#include "storm/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" #include #include "storm/adapters/RationalNumberAdapter.h" @@ -19,11 +19,7 @@ namespace storm { public: ExpressionCreator(storm::expressions::ExpressionManager const& manager); - virtual ~ExpressionCreator() { - if (deleteIdentifierMapping) { - delete this->identifiers; - } - } + ~ExpressionCreator(); /*! * Sets an identifier mapping that is used to determine valid variables in the expression. The mapped-to @@ -67,7 +63,7 @@ namespace storm { storm::expressions::Expression createEqualsExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createPlusExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createMultExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; - storm::expressions::Expression createPowerExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; + storm::expressions::Expression createPowerModuloExpression(storm::expressions::Expression const& e1, storm::expressions::OperatorType const& operatorType, storm::expressions::Expression const& e2, bool& pass) const; storm::expressions::Expression createUnaryExpression(boost::optional const& operatorType, storm::expressions::Expression const& e1, bool& pass) const; storm::expressions::Expression createRationalLiteralExpression(storm::RationalNumber const& value, bool& pass) const; storm::expressions::Expression createIntegerLiteralExpression(int value, bool& pass) const; diff --git a/src/storm/parser/ExpressionParser.cpp b/src/storm-parsers/parser/ExpressionParser.cpp similarity index 68% rename from src/storm/parser/ExpressionParser.cpp rename to src/storm-parsers/parser/ExpressionParser.cpp index f78e47d13..deaaa93bc 100644 --- a/src/storm/parser/ExpressionParser.cpp +++ b/src/storm-parsers/parser/ExpressionParser.cpp @@ -1,10 +1,10 @@ -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/utility/constants.h" -#include "storm/parser/ExpressionCreator.h" +#include "storm-parsers/parser/ExpressionCreator.h" #include "storm/storage/expressions/Expression.h" @@ -36,9 +36,9 @@ namespace boost { namespace storm { namespace parser { - ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerOperator_(), invalidIdentifiers_(invalidIdentifiers_) { + ExpressionParser::ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_, bool enableErrorHandling, bool allowBacktracking) : ExpressionParser::base_type(expression), orOperator_(), andOperator_(), equalityOperator_(), relationalOperator_(), plusOperator_(), multiplicationOperator_(), infixPowerModuloOperator_(), unaryOperator_(), floorCeilOperator_(), minMaxOperator_(), prefixPowerModuloOperator_(), invalidIdentifiers_(invalidIdentifiers_) { - expressionCreator = new ExpressionCreator(manager); + expressionCreator = std::make_unique(manager); identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_') | qi::char_('.')) >> *(qi::alnum | qi::char_('_')))]]][qi::_pass = phoenix::bind(&ExpressionParser::isValidIdentifier, phoenix::ref(*this), qi::_1)]; identifier.name("identifier"); @@ -58,11 +58,13 @@ namespace storm { minMaxExpression.name("min/max expression"); if (allowBacktracking) { - prefixPowerExpression = ((prefixPowerOperator_ >> qi::lit("(")) >> expression >> qi::lit(",") >> expression >> qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; + prefixPowerModuloExpression = ((prefixPowerModuloOperator_ >> qi::lit("(")) >> expression >> qi::lit(",") >> expression >> qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)] + | (qi::lit("func") >> qi::lit("(") >> prefixPowerModuloOperator_ >> qi::lit(",") >> expression >> qi::lit(",") >> expression >> qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; } else { - prefixPowerExpression = ((prefixPowerOperator_ >> qi::lit("(")) > expression > qi::lit(",") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; + prefixPowerModuloExpression = ((prefixPowerModuloOperator_ >> qi::lit("(")) > expression > qi::lit(",") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)] + | ((qi::lit("func") >> qi::lit("(")) > prefixPowerModuloOperator_ > qi::lit(",") > expression > qi::lit(",") > expression > qi::lit(")"))[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_2, qi::_1, qi::_3, qi::_pass)]; } - prefixPowerExpression.name("pow expression"); + prefixPowerModuloExpression.name("(prefix) power/modulo expression"); identifierExpression = identifier[qi::_val = phoenix::bind(&ExpressionCreator::getIdentifierExpression, phoenix::ref(*expressionCreator), qi::_1, qi::_pass)]; identifierExpression.name("identifier expression"); @@ -73,27 +75,31 @@ namespace storm { | qi::int_[qi::_val = phoenix::bind(&ExpressionCreator::createIntegerLiteralExpression, phoenix::ref(*expressionCreator), qi::_1, qi::_pass)]; literalExpression.name("literal expression"); - atomicExpression = floorCeilExpression | prefixPowerExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | identifierExpression | literalExpression; + atomicExpression = floorCeilExpression | prefixPowerModuloExpression | minMaxExpression | (qi::lit("(") >> expression >> qi::lit(")")) | identifierExpression | literalExpression; atomicExpression.name("atomic expression"); unaryExpression = (-unaryOperator_ >> atomicExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createUnaryExpression, phoenix::ref(*expressionCreator), qi::_1, qi::_2, qi::_pass)]; unaryExpression.name("unary expression"); if (allowBacktracking) { - infixPowerExpression = unaryExpression[qi::_val = qi::_1] >> -(infixPowerOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + infixPowerModuloExpression = unaryExpression[qi::_val = qi::_1] >> -(infixPowerModuloOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } else { - infixPowerExpression = unaryExpression[qi::_val = qi::_1] > -(infixPowerOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + infixPowerModuloExpression = unaryExpression[qi::_val = qi::_1] > -(infixPowerModuloOperator_ >> expression)[qi::_val = phoenix::bind(&ExpressionCreator::createPowerModuloExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } - infixPowerExpression.name("power expression"); + infixPowerModuloExpression.name("(infix) power/modulo expression"); if (allowBacktracking) { - multiplicationExpression = infixPowerExpression[qi::_val = qi::_1] >> *(multiplicationOperator_ >> infixPowerExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + multiplicationExpression = infixPowerModuloExpression[qi::_val = qi::_1] >> *(multiplicationOperator_ >> infixPowerModuloExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } else { - multiplicationExpression = infixPowerExpression[qi::_val = qi::_1] > *(multiplicationOperator_ > infixPowerExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + multiplicationExpression = infixPowerModuloExpression[qi::_val = qi::_1] > *(multiplicationOperator_ > infixPowerModuloExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createMultExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; } multiplicationExpression.name("multiplication expression"); - plusExpression = multiplicationExpression[qi::_val = qi::_1] > *(plusOperator_ >> multiplicationExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createPlusExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + if (allowBacktracking) { + plusExpression = multiplicationExpression[qi::_val = qi::_1] >> *(plusOperator_ >> multiplicationExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createPlusExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } else { + plusExpression = multiplicationExpression[qi::_val = qi::_1] > *(plusOperator_ >> multiplicationExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createPlusExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } plusExpression.name("plus expression"); if (allowBacktracking) { @@ -103,7 +109,11 @@ namespace storm { } relativeExpression.name("relative expression"); - equalityExpression = relativeExpression[qi::_val = qi::_1] >> *(equalityOperator_ >> relativeExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createEqualsExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + if (allowBacktracking) { + equalityExpression = relativeExpression[qi::_val = qi::_1] >> *(equalityOperator_ >> relativeExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createEqualsExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } else { + equalityExpression = relativeExpression[qi::_val = qi::_1] >> *(equalityOperator_ >> relativeExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createEqualsExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } equalityExpression.name("equality expression"); if (allowBacktracking) { @@ -120,7 +130,11 @@ namespace storm { } orExpression.name("or expression"); - iteExpression = orExpression[qi::_val = qi::_1] > -(qi::lit("?") > iteExpression > qi::lit(":") > iteExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createIteExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + if (allowBacktracking) { + iteExpression = orExpression[qi::_val = qi::_1] >> -(qi::lit("?") >> iteExpression >> qi::lit(":") >> iteExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createIteExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } else { + iteExpression = orExpression[qi::_val = qi::_1] > -(qi::lit("?") > iteExpression > qi::lit(":") > iteExpression)[qi::_val = phoenix::bind(&ExpressionCreator::createIteExpression, phoenix::ref(*expressionCreator), qi::_val, qi::_1, qi::_2, qi::_pass)]; + } iteExpression.name("if-then-else expression"); expression %= iteExpression; @@ -136,12 +150,12 @@ namespace storm { debug(relativeExpression); debug(plusExpression); debug(multiplicationExpression); - debug(infixPowerExpression); + debug(infixPowerModuloExpression); debug(unaryExpression); debug(atomicExpression); debug(literalExpression); debug(identifierExpression); - */ + */ if (enableErrorHandling) { // Enable error reporting. @@ -162,6 +176,10 @@ namespace storm { } } + ExpressionParser::~ExpressionParser() { + // Needed, because auto-generated destructor requires ExpressionCreator to be a complete type in the header. + } + void ExpressionParser::setIdentifierMapping(qi::symbols const* identifiers_) { expressionCreator->setIdentifierMapping(identifiers_); } @@ -196,7 +214,7 @@ namespace storm { try { // Start parsing. - bool succeeded = qi::phrase_parse(iter, last, *this, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + bool succeeded = qi::phrase_parse(iter, last, *this, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse expression '" << expressionString << "'."); STORM_LOG_DEBUG("Parsed expression successfully."); } catch (qi::expectation_failure const& e) { diff --git a/src/storm/parser/ExpressionParser.h b/src/storm-parsers/parser/ExpressionParser.h similarity index 91% rename from src/storm/parser/ExpressionParser.h rename to src/storm-parsers/parser/ExpressionParser.h index da3282b1b..4bd3cfaab 100644 --- a/src/storm/parser/ExpressionParser.h +++ b/src/storm-parsers/parser/ExpressionParser.h @@ -1,9 +1,10 @@ #pragma once #include +#include -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/storage/expressions/OperatorType.h" #include "storm/adapters/RationalNumberAdapter.h" @@ -18,6 +19,8 @@ namespace storm { template struct RationalPolicies : boost::spirit::qi::strict_real_policies { static const bool expect_dot = true; + static const bool allow_leading_dot = true; + static const bool allow_trailing_dot = false; template static bool parse_nan(It&, It const&, Attr&) { return false; } @@ -44,6 +47,7 @@ namespace storm { * also parses boolean conjuncts that are erroneously consumed by the expression parser. */ ExpressionParser(storm::expressions::ExpressionManager const& manager, qi::symbols const& invalidIdentifiers_ = qi::symbols(), bool enableErrorHandling = true, bool allowBacktracking = false); + ~ExpressionParser(); ExpressionParser(ExpressionParser const& other) = default; ExpressionParser& operator=(ExpressionParser const& other) = default; @@ -149,15 +153,16 @@ namespace storm { // A parser used for recognizing the operators at the "multiplication" precedence level. multiplicationOperatorStruct multiplicationOperator_; - struct infixPowerOperatorStruct : qi::symbols { - infixPowerOperatorStruct() { + struct infixPowerModuloOperatorStruct : qi::symbols { + infixPowerModuloOperatorStruct() { add - ("^", storm::expressions::OperatorType::Power); + ("^", storm::expressions::OperatorType::Power) + ("%", storm::expressions::OperatorType::Modulo); } }; // A parser used for recognizing the operators at the "power" precedence level. - infixPowerOperatorStruct infixPowerOperator_; + infixPowerModuloOperatorStruct infixPowerModuloOperator_; struct unaryOperatorStruct : qi::symbols { unaryOperatorStruct() { @@ -192,18 +197,19 @@ namespace storm { // A parser used for recognizing the operators at the "min/max" precedence level. minMaxOperatorStruct minMaxOperator_; - struct prefixPowerOperatorStruct : qi::symbols { - prefixPowerOperatorStruct() { + struct prefixPowerModuloOperatorStruct : qi::symbols { + prefixPowerModuloOperatorStruct() { add - ("pow", storm::expressions::OperatorType::Power); + ("pow", storm::expressions::OperatorType::Power) + ("mod", storm::expressions::OperatorType::Modulo); } }; // A parser used for recognizing the operators at the "power" precedence level. - prefixPowerOperatorStruct prefixPowerOperator_; + prefixPowerModuloOperatorStruct prefixPowerModuloOperator_; - ExpressionCreator* expressionCreator; + std::unique_ptr expressionCreator; // The symbol table of invalid identifiers. @@ -218,8 +224,8 @@ namespace storm { qi::rule, Skipper> equalityExpression; qi::rule, Skipper> plusExpression; qi::rule, Skipper> multiplicationExpression; - qi::rule, Skipper> prefixPowerExpression; - qi::rule, Skipper> infixPowerExpression; + qi::rule, Skipper> prefixPowerModuloExpression; + qi::rule, Skipper> infixPowerModuloExpression; qi::rule unaryExpression; qi::rule atomicExpression; qi::rule literalExpression; diff --git a/src/storm/parser/FormulaParser.cpp b/src/storm-parsers/parser/FormulaParser.cpp similarity index 87% rename from src/storm/parser/FormulaParser.cpp rename to src/storm-parsers/parser/FormulaParser.cpp index e592f141c..78cf2ad3c 100644 --- a/src/storm/parser/FormulaParser.cpp +++ b/src/storm-parsers/parser/FormulaParser.cpp @@ -1,11 +1,10 @@ -#include "storm/parser/FormulaParser.h" +#include "storm-parsers/parser/FormulaParser.h" #include -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/storage/prism/Program.h" -#include "storm/storage/jani/Model.h" #include "storm/logic/Formulas.h" @@ -33,20 +32,11 @@ namespace storm { } FormulaParser::FormulaParser(storm::prism::Program const& program) : manager(program.getManager().getSharedPointer()), grammar(new FormulaParserGrammar(program.getManager().getSharedPointer())) { - this->addFormulasAsIdentifiers(program); } FormulaParser::FormulaParser(storm::prism::Program& program) : manager(program.getManager().getSharedPointer()), grammar(new FormulaParserGrammar(program.getManager().getSharedPointer())) { - this->addFormulasAsIdentifiers(program); } - void FormulaParser::addFormulasAsIdentifiers(storm::prism::Program const& program) { - // Make the formulas of the program available to the parser. - for (auto const& formula : program.getFormulas()) { - this->addIdentifierExpression(formula.getName(), formula.getExpression()); - } - } - FormulaParser::FormulaParser(FormulaParser const& other) : FormulaParser(other.manager) { other.identifiers_.for_each([=] (std::string const& name, storm::expressions::Expression const& expression) { this->addIdentifierExpression(name, expression); }); } @@ -97,7 +87,7 @@ namespace storm { // Create grammar. try { // Start parsing. - bool succeeded = qi::phrase_parse(iter, last, *grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + bool succeeded = qi::phrase_parse(iter, last, *grammar, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse formula."); STORM_LOG_DEBUG("Parsed formula successfully."); } catch (qi::expectation_failure const& e) { diff --git a/src/storm/parser/FormulaParser.h b/src/storm-parsers/parser/FormulaParser.h similarity index 96% rename from src/storm/parser/FormulaParser.h rename to src/storm-parsers/parser/FormulaParser.h index d9c06fa92..49c78a720 100644 --- a/src/storm/parser/FormulaParser.h +++ b/src/storm-parsers/parser/FormulaParser.h @@ -3,8 +3,8 @@ #include -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/jani/Property.h" #include "storm/storage/expressions/Expression.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/FormulaParserGrammar.cpp b/src/storm-parsers/parser/FormulaParserGrammar.cpp similarity index 94% rename from src/storm/parser/FormulaParserGrammar.cpp rename to src/storm-parsers/parser/FormulaParserGrammar.cpp index 9e8191ad2..ceca76e8e 100644 --- a/src/storm/parser/FormulaParserGrammar.cpp +++ b/src/storm-parsers/parser/FormulaParserGrammar.cpp @@ -133,7 +133,7 @@ namespace storm { formulaName = qi::lit("\"") >> identifier >> qi::lit("\"") >> qi::lit(":"); formulaName.name("formula name"); - constantDefinition = (qi::lit("const") > qi::eps[qi::_a = true] > -(qi::lit("int") | qi::lit("double")[qi::_a = false]) >> identifier)[phoenix::bind(&FormulaParserGrammar::addConstant, phoenix::ref(*this), qi::_1, qi::_a)]; + constantDefinition = (qi::lit("const") > -(qi::lit("int")[qi::_a = ConstantDataType::Integer] | qi::lit("bool")[qi::_a = ConstantDataType::Bool] | qi::lit("double")[qi::_a = ConstantDataType::Rational]) >> identifier >> -(qi::lit("=") > expressionParser))[phoenix::bind(&FormulaParserGrammar::addConstant, phoenix::ref(*this), qi::_1, qi::_a, qi::_2)]; constantDefinition.name("constant definition"); #pragma clang diagnostic push @@ -147,7 +147,7 @@ namespace storm { start = (qi::eps >> filterProperty[phoenix::push_back(qi::_val, qi::_1)] | qi::eps(phoenix::bind(&FormulaParserGrammar::areConstantDefinitionsAllowed, phoenix::ref(*this))) >> constantDefinition | qi::eps) - % +(qi::char_("\n;")) >> qi::skip(boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi; + % +(qi::char_("\n;")) >> qi::skip(storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi; start.name("start"); // Enable the following lines to print debug output for most the rules. @@ -208,15 +208,25 @@ namespace storm { this->identifiers_.add(identifier, expression); } - void FormulaParserGrammar::addConstant(std::string const& name, bool integer) { + void FormulaParserGrammar::addConstant(std::string const& name, ConstantDataType type, boost::optional const& expression) { STORM_LOG_ASSERT(manager, "Mutable expression manager required to define new constants."); storm::expressions::Variable newVariable; - if (integer) { + STORM_LOG_THROW(!manager->hasVariable(name), storm::exceptions::WrongFormatException, "Invalid constant definition '" << name << "' in property: variable already exists."); + + if (type == ConstantDataType::Bool) { + newVariable = manager->declareBooleanVariable(name); + } else if (type == ConstantDataType::Integer) { newVariable = manager->declareIntegerVariable(name); } else { newVariable = manager->declareRationalVariable(name); } - addIdentifierExpression(name, newVariable); + + if (expression) { + addIdentifierExpression(name, expression.get()); + } else { + undefinedConstants.insert(newVariable); + addIdentifierExpression(name, newVariable); + } } bool FormulaParserGrammar::areConstantDefinitionsAllowed() const { @@ -408,24 +418,31 @@ namespace storm { return std::shared_ptr(new storm::logic::MultiObjectiveFormula(subformulas)); } } - + + std::set FormulaParserGrammar::getUndefinedConstants(std::shared_ptr const& formula) const { + std::set result; + std::set usedVariables = formula->getUsedVariables(); + std::set_intersection(usedVariables.begin(), usedVariables.end(), undefinedConstants.begin(), undefinedConstants.end(), std::inserter(result, result.begin())); + return result; + } + storm::jani::Property FormulaParserGrammar::createProperty(boost::optional const& propertyName, storm::modelchecker::FilterType const& filterType, std::shared_ptr const& formula, std::shared_ptr const& states) { storm::jani::FilterExpression filterExpression(formula, filterType, states); ++propertyCount; if (propertyName) { - return storm::jani::Property(propertyName.get(), filterExpression); + return storm::jani::Property(propertyName.get(), filterExpression, this->getUndefinedConstants(formula)); } else { - return storm::jani::Property(std::to_string(propertyCount -1 ), filterExpression); + return storm::jani::Property(std::to_string(propertyCount - 1), filterExpression, this->getUndefinedConstants(formula)); } } storm::jani::Property FormulaParserGrammar::createPropertyWithDefaultFilterTypeAndStates(boost::optional const& propertyName, std::shared_ptr const& formula) { ++propertyCount; if (propertyName) { - return storm::jani::Property(propertyName.get(), formula); + return storm::jani::Property(propertyName.get(), formula, this->getUndefinedConstants(formula)); } else { - return storm::jani::Property(std::to_string(propertyCount), formula); + return storm::jani::Property(std::to_string(propertyCount), formula, this->getUndefinedConstants(formula)); } } diff --git a/src/storm/parser/FormulaParserGrammar.h b/src/storm-parsers/parser/FormulaParserGrammar.h similarity index 96% rename from src/storm/parser/FormulaParserGrammar.h rename to src/storm-parsers/parser/FormulaParserGrammar.h index dd9a3a06f..75012aaf4 100644 --- a/src/storm/parser/FormulaParserGrammar.h +++ b/src/storm-parsers/parser/FormulaParserGrammar.h @@ -3,11 +3,11 @@ #include #include -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/storage/jani/Property.h" #include "storm/logic/Formulas.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/modelchecker/results/FilterType.h" @@ -145,7 +145,11 @@ namespace storm { qi::rule(), Skipper> start; - qi::rule, Skipper> constantDefinition; + enum class ConstantDataType { + Bool, Integer, Rational + }; + + qi::rule, Skipper> constantDefinition; qi::rule identifier; qi::rule formulaName; @@ -197,7 +201,7 @@ namespace storm { boost::spirit::qi::real_parser> strict_double; bool areConstantDefinitionsAllowed() const; - void addConstant(std::string const& name, bool integer); + void addConstant(std::string const& name, ConstantDataType type, boost::optional const& expression); void addProperty(std::vector& properties, boost::optional const& name, std::shared_ptr const& formula); std::shared_ptr createTimeBoundReference(storm::logic::TimeBoundType const& type, boost::optional const& rewardModelName) const; @@ -226,6 +230,7 @@ namespace storm { std::shared_ptr createUnaryBooleanStateFormula(std::shared_ptr const& subformula, boost::optional const& operatorType); std::shared_ptr createMultiFormula(std::vector> const& subformulas); + std::set getUndefinedConstants(std::shared_ptr const& formula) const; storm::jani::Property createProperty(boost::optional const& propertyName, storm::modelchecker::FilterType const& filterType, std::shared_ptr const& formula, std::shared_ptr const& states); storm::jani::Property createPropertyWithDefaultFilterTypeAndStates(boost::optional const& propertyName, std::shared_ptr const& formula); @@ -233,6 +238,8 @@ namespace storm { phoenix::function handler; uint64_t propertyCount; + + std::set undefinedConstants; }; } diff --git a/src/storm/parser/ImcaMarkovAutomatonParser.cpp b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.cpp similarity index 98% rename from src/storm/parser/ImcaMarkovAutomatonParser.cpp rename to src/storm-parsers/parser/ImcaMarkovAutomatonParser.cpp index 01cb93671..0cbf917f1 100644 --- a/src/storm/parser/ImcaMarkovAutomatonParser.cpp +++ b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/ImcaMarkovAutomatonParser.h" +#include "storm-parsers/parser/ImcaMarkovAutomatonParser.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/BuildSettings.h" @@ -248,7 +248,7 @@ namespace storm { try { // Start parsing. ImcaParserGrammar grammar; - bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), components); + bool succeeded = qi::phrase_parse(iter, last, grammar, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), components); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Could not parse imca file."); STORM_LOG_DEBUG("Parsed imca file successfully."); } catch (qi::expectation_failure const& e) { diff --git a/src/storm/parser/ImcaMarkovAutomatonParser.h b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.h similarity index 98% rename from src/storm/parser/ImcaMarkovAutomatonParser.h rename to src/storm-parsers/parser/ImcaMarkovAutomatonParser.h index f2820242e..b5c7beded 100644 --- a/src/storm/parser/ImcaMarkovAutomatonParser.h +++ b/src/storm-parsers/parser/ImcaMarkovAutomatonParser.h @@ -7,7 +7,7 @@ #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/generator/StateBehavior.h" -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" namespace storm { namespace parser { diff --git a/src/storm/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp similarity index 50% rename from src/storm/parser/JaniParser.cpp rename to src/storm-parsers/parser/JaniParser.cpp index 3de6bb2cc..eba57d0dd 100644 --- a/src/storm/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -9,13 +9,15 @@ #include "storm/storage/jani/Property.h" #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" +#include "storm/storage/jani/ModelType.h" #include "storm/storage/jani/CompositionInformationVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/logic/RewardAccumulationEliminationVisitor.h" + #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/InvalidJaniException.h" - #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/NotImplementedException.h" -#include "storm/storage/jani/ModelType.h" #include "storm/modelchecker/results/FilterType.h" @@ -23,6 +25,7 @@ #include #include #include +#include "storm/storage/jani/ArrayVariable.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" @@ -59,11 +62,16 @@ namespace storm { return static_cast(num); } + int64_t getSignedInt(json const& structure, std::string const& errorInfo) { + STORM_LOG_THROW(structure.is_number(), storm::exceptions::InvalidJaniException, "Expected a number in " << errorInfo << ", got '" << structure.dump() << "'"); + int num = structure.front(); + return static_cast(num); + } - std::pair> JaniParser::parse(std::string const& path) { + std::pair> JaniParser::parse(std::string const& path, bool parseProperties) { JaniParser parser; parser.readFile(path); - return parser.parseModel(); + return parser.parseModel(parseProperties); } JaniParser::JaniParser(std::string const& jsonstring) { @@ -77,7 +85,7 @@ namespace storm { storm::utility::closeFile(file); } - std::pair> JaniParser::parseModel(bool parseProperties) { + std::pair> JaniParser::parseModel(bool parseProperties) { //jani-version STORM_LOG_THROW(parsedStructure.count("jani-version") == 1, storm::exceptions::InvalidJaniException, "Jani-version must be given exactly once."); uint64_t version = getUnsignedInt(parsedStructure.at("jani-version"), "jani version"); @@ -90,86 +98,144 @@ namespace storm { storm::jani::ModelType type = storm::jani::getModelType(modeltypestring); STORM_LOG_THROW(type != storm::jani::ModelType::UNDEFINED, storm::exceptions::InvalidJaniException, "model type " + modeltypestring + " not recognized"); storm::jani::Model model(name, type, version, expressionManager); + size_t featuresCount = parsedStructure.count("features"); + STORM_LOG_THROW(featuresCount < 2, storm::exceptions::InvalidJaniException, "features-declarations can be given at most once."); + if (featuresCount == 1) { + auto allKnownModelFeatures = storm::jani::getAllKnownModelFeatures(); + for (auto const& feature : parsedStructure.at("features")) { + std::string featureStr = getString(feature, "Model feature"); + bool found = false; + for (auto const& knownFeature : allKnownModelFeatures.asSet()) { + if (featureStr == storm::jani::toString(knownFeature)) { + model.getModelFeatures().add(knownFeature); + found = true; + break; + } + } + STORM_LOG_THROW(found, storm::exceptions::NotSupportedException, "Storm does not support the model feature " << featureStr); + } + } size_t actionCount = parsedStructure.count("actions"); STORM_LOG_THROW(actionCount < 2, storm::exceptions::InvalidJaniException, "Action-declarations can be given at most once."); if (actionCount > 0) { parseActions(parsedStructure.at("actions"), model); } + + Scope scope(name); + + // Parse constants + ConstantsMap constants; + scope.constants = &constants; size_t constantsCount = parsedStructure.count("constants"); - std::unordered_map> constants; STORM_LOG_THROW(constantsCount < 2, storm::exceptions::InvalidJaniException, "Constant-declarations can be given at most once."); if (constantsCount == 1) { for (auto const &constStructure : parsedStructure.at("constants")) { - std::shared_ptr constant = parseConstant(constStructure, constants, "global"); - constants.emplace(constant->getName(), constant); + std::shared_ptr constant = parseConstant(constStructure, scope.refine("constants[" + std::to_string(constants.size()) + "]")); model.addConstant(*constant); } + // Insert references after adding all constants to make sure that they remain valid + for (auto const& constant : model.getConstants()) { + constants.emplace(constant.getName(), &constant); + } } + + // Parse variables size_t variablesCount = parsedStructure.count("variables"); STORM_LOG_THROW(variablesCount < 2, storm::exceptions::InvalidJaniException, "Variable-declarations can be given at most once for global variables."); - std::unordered_map> globalVars; + VariablesMap globalVars; + scope.globalVars = &globalVars; if (variablesCount == 1) { + bool requireInitialValues = parsedStructure.count("restrict-initial") == 0; for (auto const& varStructure : parsedStructure.at("variables")) { - std::shared_ptr variable = parseVariable(varStructure, "global", globalVars, constants); - globalVars.emplace(variable->getName(), variable); - model.addVariable(*variable); + std::shared_ptr variable = parseVariable(varStructure, requireInitialValues, scope.refine("variables[" + std::to_string(globalVars.size()))); + globalVars.emplace(variable->getName(), &model.addVariable(*variable)); } } + + uint64_t funDeclCount = parsedStructure.count("functions"); + STORM_LOG_THROW(funDeclCount < 2, storm::exceptions::InvalidJaniException, "Model '" << name << "' has more than one list of functions"); + FunctionsMap globalFuns; + scope.globalFunctions = &globalFuns; + if (funDeclCount > 0) { + // We require two passes through the function definitions array to allow referring to functions before they were defined. + std::vector dummyFunctionDefinitions; + for (auto const& funStructure : parsedStructure.at("functions")) { + // Skip parsing of function body + dummyFunctionDefinitions.push_back(parseFunctionDefinition(funStructure, scope.refine("functions[" + std::to_string(globalFuns.size()) + "] of model " + name), + true)); + } + // Store references to the dummy function definitions. This needs to happen in a separate loop since otherwise, references to FunDefs can be invalidated after calling dummyFunctionDefinitions.push_back + for (auto const& funDef : dummyFunctionDefinitions) { + bool unused = globalFuns.emplace(funDef.getName(), &funDef).second; + STORM_LOG_THROW(unused, storm::exceptions::InvalidJaniException, "Multiple definitions of functions with the name " << funDef.getName() << " in " << scope.description); + } + for (auto const& funStructure : parsedStructure.at("functions")) { + // Actually parse the function body + storm::jani::FunctionDefinition funDef = parseFunctionDefinition(funStructure, scope.refine("functions[" + std::to_string(globalFuns.size()) + "] of model " + name), + false); + assert(globalFuns.count(funDef.getName()) == 1); + globalFuns[funDef.getName()] = &model.addFunctionDefinition(funDef); + } + } + + // Parse Automata STORM_LOG_THROW(parsedStructure.count("automata") == 1, storm::exceptions::InvalidJaniException, "Exactly one list of automata must be given"); STORM_LOG_THROW(parsedStructure.at("automata").is_array(), storm::exceptions::InvalidJaniException, "Automata must be an array"); // Automatons can only be parsed after constants and variables. for (auto const& automataEntry : parsedStructure.at("automata")) { - model.addAutomaton(parseAutomaton(automataEntry, model, globalVars, constants)); + model.addAutomaton(parseAutomaton(automataEntry, model, scope.refine("automata[" + std::to_string(model.getNumberOfAutomata()) + "]"))); } STORM_LOG_THROW(parsedStructure.count("restrict-initial") < 2, storm::exceptions::InvalidJaniException, "Model has multiple initial value restrictions"); storm::expressions::Expression initialValueRestriction = expressionManager->boolean(true); - if(parsedStructure.count("restrict-initial") > 0) { + if (parsedStructure.count("restrict-initial") > 0) { STORM_LOG_THROW(parsedStructure.at("restrict-initial").count("exp") == 1, storm::exceptions::InvalidJaniException, "Model needs an expression inside the initial restricion"); - initialValueRestriction = parseExpression(parsedStructure.at("restrict-initial").at("exp"), "Initial value restriction for automaton " + name, globalVars, constants); + initialValueRestriction = parseExpression(parsedStructure.at("restrict-initial").at("exp"), scope.refine("Initial value restriction")); } model.setInitialStatesRestriction(initialValueRestriction); STORM_LOG_THROW(parsedStructure.count("system") == 1, storm::exceptions::InvalidJaniException, "Exactly one system description must be given"); std::shared_ptr composition = parseComposition(parsedStructure.at("system")); model.setSystemComposition(composition); + model.finalize(); + + // Parse properties + storm::logic::RewardAccumulationEliminationVisitor rewAccEliminator(model); STORM_LOG_THROW(parsedStructure.count("properties") <= 1, storm::exceptions::InvalidJaniException, "At most one list of properties can be given"); - std::map properties; + std::vector properties; if (parseProperties && parsedStructure.count("properties") == 1) { STORM_LOG_THROW(parsedStructure.at("properties").is_array(), storm::exceptions::InvalidJaniException, "Properties should be an array"); for(auto const& propertyEntry : parsedStructure.at("properties")) { try { - auto prop = this->parseProperty(propertyEntry, globalVars, constants); - properties.emplace(prop.getName(), prop); + auto prop = this->parseProperty(propertyEntry, scope.refine("property[" + std::to_string(properties.size()) + "]")); + // Eliminate reward accumulations as much as possible + rewAccEliminator.eliminateRewardAccumulations(prop); + properties.push_back(prop); } catch (storm::exceptions::NotSupportedException const& ex) { - STORM_LOG_WARN("Cannot handle property " << ex.what()); + STORM_LOG_WARN("Cannot handle property: " << ex.what()); } catch (storm::exceptions::NotImplementedException const& ex) { - STORM_LOG_WARN("Cannot handle property " << ex.what()); + STORM_LOG_WARN("Cannot handle property: " << ex.what()); } } } - model.finalize(); return {model, properties}; } - std::vector> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context) { - STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting operand for operator " << opstring << " in " << context); - return { parseFormula(propertyStructure.at("exp"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; + std::vector> JaniParser::parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope) { + STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting operand for operator " << opstring << " in " << scope.description); + return { parseFormula(propertyStructure.at("exp"), formulaContext, scope.refine("Operand of operator " + opstring)) }; } - std::vector> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context) { - STORM_LOG_THROW(propertyStructure.count("left") == 1, storm::exceptions::InvalidJaniException, "Expecting left operand for operator " << opstring << " in " << context); - STORM_LOG_THROW(propertyStructure.count("right") == 1, storm::exceptions::InvalidJaniException, "Expecting right operand for operator " << opstring << " in " << context); - return { parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "Operand of operator " + opstring), parseFormula(propertyStructure.at("right"), formulaContext, globalVars, constants, "Operand of operator " + opstring) }; + std::vector> JaniParser::parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope) { + STORM_LOG_THROW(propertyStructure.count("left") == 1, storm::exceptions::InvalidJaniException, "Expecting left operand for operator " << opstring << " in " << scope.description); + STORM_LOG_THROW(propertyStructure.count("right") == 1, storm::exceptions::InvalidJaniException, "Expecting right operand for operator " << opstring << " in " << scope.description); + return { parseFormula(propertyStructure.at("left"), formulaContext, scope.refine("Operand of operator " + opstring)), parseFormula(propertyStructure.at("right"), formulaContext, scope.refine("Operand of operator " + opstring)) }; } - storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure) { + storm::jani::PropertyInterval JaniParser::parsePropertyInterval(json const& piStructure, Scope const& scope) { storm::jani::PropertyInterval pi; if (piStructure.count("lower") > 0) { - pi.lowerBound = parseExpression(piStructure.at("lower"), "Lower bound for property interval", {}, {}); - // TODO substitute constants. - std::cout << "have lower bound" << std::endl; - STORM_LOG_THROW(!pi.lowerBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as lower bounds"); + pi.lowerBound = parseExpression(piStructure.at("lower"), scope.refine("Lower bound for property interval")); } if (piStructure.count("lower-exclusive") > 0) { STORM_LOG_THROW(pi.lowerBound.isInitialized(), storm::exceptions::InvalidJaniException, "Lower-exclusive can only be set if a lower bound is present"); @@ -177,10 +243,7 @@ namespace storm { } if (piStructure.count("upper") > 0) { - std::cout << "have upper bound" << std::endl; - pi.upperBound = parseExpression(piStructure.at("upper"), "Upper bound for property interval", {}, {}); - // TODO substitute constants. - STORM_LOG_THROW(!pi.upperBound.containsVariables(), storm::exceptions::NotSupportedException, "Only constant expressions are supported as upper bounds"); + pi.upperBound = parseExpression(piStructure.at("upper"), scope.refine("Upper bound for property interval")); } if (piStructure.count("upper-exclusive") > 0) { @@ -189,12 +252,28 @@ namespace storm { } STORM_LOG_THROW(pi.lowerBound.isInitialized() || pi.upperBound.isInitialized(), storm::exceptions::InvalidJaniException, "Bounded operator must have a bounded interval, but no bounds found in '" << piStructure << "'"); return pi; - - } + storm::logic::RewardAccumulation JaniParser::parseRewardAccumulation(json const& accStructure, std::string const& context) { + bool accTime = false; + bool accSteps = false; + bool accExit = false; + STORM_LOG_THROW(accStructure.is_array(), storm::exceptions::InvalidJaniException, "Accumulate should be an array"); + for (auto const& accEntry : accStructure) { + if (accEntry == "steps") { + accSteps = true; + } else if (accEntry == "time") { + accTime = true; + } else if (accEntry == "exit") { + accExit = true; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time' or 'exit', got " << accEntry.dump() << " in " << context); + } + } + return storm::logic::RewardAccumulation(accSteps, accTime, accExit); + } - std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext,std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context, boost::optional bound) { + std::shared_ptr JaniParser::parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, Scope const& scope, boost::optional bound) { if (propertyStructure.is_boolean()) { return std::make_shared(propertyStructure.get()); } @@ -203,7 +282,7 @@ namespace storm { return std::make_shared(propertyStructure.get()); } } - storm::expressions::Expression expr = parseExpression(propertyStructure, "expression in property", globalVars, constants, {}, true); + storm::expressions::Expression expr = parseExpression(propertyStructure, scope.refine("expression in property"), true); if(expr.isInitialized()) { assert(bound == boost::none); return std::make_shared(expr); @@ -211,7 +290,7 @@ namespace storm { std::string opString = getString(propertyStructure.at("op"), "Operation description"); if(opString == "Pmin" || opString == "Pmax") { - std::vector> args = parseUnaryFormulaArgument(propertyStructure, storm::logic::FormulaContext::Probability, opString, globalVars, constants, ""); + std::vector> args = parseUnaryFormulaArgument(propertyStructure, storm::logic::FormulaContext::Probability, opString, scope); assert(args.size() == 1); storm::logic::OperatorInformation opInfo; opInfo.optimalityType = opString == "Pmin" ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; @@ -222,172 +301,132 @@ namespace storm { assert(bound == boost::none); STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Forall and Exists are currently not supported"); } else if (opString == "Emin" || opString == "Emax") { - bool time=false; - STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); - storm::expressions::Expression rewExpr = parseExpression(propertyStructure.at("exp"), "Reward expression in " + context, globalVars, constants); - if (rewExpr.isVariable()) { - time = false; - } else { - time = true; - } - std::shared_ptr reach; - if (propertyStructure.count("reach") > 0) { - reach = std::make_shared(parseFormula(propertyStructure.at("reach"), time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward, globalVars, constants, "Reach-expression of operator " + opString)); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Total reward is currently not supported"); - } + STORM_LOG_THROW(propertyStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << scope.description); + storm::expressions::Expression rewExpr = parseExpression(propertyStructure.at("exp"), scope.refine("Reward expression")); + STORM_LOG_THROW(rewExpr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Reward expression '" << rewExpr << "' does not have numerical type in " << scope.description); + std::string rewardName = rewExpr.toString(); + storm::logic::OperatorInformation opInfo; opInfo.optimalityType = opString == "Emin" ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize; opInfo.bound = bound; - bool accTime = false; - bool accSteps = false; + storm::logic::RewardAccumulation rewardAccumulation(false, false, false); if (propertyStructure.count("accumulate") > 0) { - STORM_LOG_THROW(propertyStructure.at("accumulate").is_array(), storm::exceptions::InvalidJaniException, "Accumulate should be an array"); - for(auto const& accEntry : propertyStructure.at("accumulate")) { - if (accEntry == "steps") { - accSteps = true; - } else if (accEntry == "time") { - accTime = true; - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "One may only accumulate either 'steps' or 'time', got " << accEntry.dump() << " in " << context); - } - } + rewardAccumulation = parseRewardAccumulation(propertyStructure.at("accumulate"), scope.description); } - STORM_LOG_THROW(!(accTime && accSteps), storm::exceptions::NotSupportedException, "Storm does not allow to accumulate over both time and steps"); - + bool time = false; if (propertyStructure.count("step-instant") > 0) { - storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), "Step instant in " + context, globalVars, constants); - STORM_LOG_THROW(!stepInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant step-instants"); + STORM_LOG_THROW(propertyStructure.count("time-instant") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a time-instant in " + scope.description); + STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a step-instant and a reward-instant in " + scope.description); - int64_t stepInstant = stepInstantExpr.evaluateAsInt(); - STORM_LOG_THROW(stepInstant >= 0, storm::exceptions::InvalidJaniException, "Only non-negative step-instants are allowed"); - if(!accTime && !accSteps) { - if (rewExpr.isVariable()) { - std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(stepInstantExpr, storm::logic::TimeBoundType::Steps), rewardName, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); - } + storm::expressions::Expression stepInstantExpr = parseExpression(propertyStructure.at("step-instant"), scope.refine("Step instant")); + if(rewardAccumulation.isEmpty()) { + return std::make_shared(std::make_shared(stepInstantExpr, storm::logic::TimeBoundType::Steps), rewardName, opInfo); } else { - if (rewExpr.isVariable()) { - std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(storm::logic::TimeBound(false, stepInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps)), rewardName, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); - } + return std::make_shared(std::make_shared(storm::logic::TimeBound(false, stepInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps), rewardAccumulation), rewardName, opInfo); } } else if (propertyStructure.count("time-instant") > 0) { - storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), "time instant in " + context, globalVars, constants); - STORM_LOG_THROW(!timeInstantExpr.containsVariables(), storm::exceptions::NotSupportedException, "Storm only allows constant time-instants"); - - double timeInstant = timeInstantExpr.evaluateAsDouble(); - STORM_LOG_THROW(timeInstant >= 0, storm::exceptions::InvalidJaniException, "Only non-negative time-instants are allowed"); - if(!accTime && !accSteps) { - if (rewExpr.isVariable()) { - std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(timeInstantExpr, storm::logic::TimeBoundType::Time), rewardName, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); - } + STORM_LOG_THROW(propertyStructure.count("reward-instants") == 0, storm::exceptions::NotSupportedException, "Storm does not support to have a time-instant and a reward-instant in " + scope.description); + storm::expressions::Expression timeInstantExpr = parseExpression(propertyStructure.at("time-instant"), scope.refine("time instant")); + if(rewardAccumulation.isEmpty()) { + return std::make_shared(std::make_shared(timeInstantExpr, storm::logic::TimeBoundType::Time), rewardName, opInfo); } else { - if (rewExpr.isVariable()) { - std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(std::make_shared(storm::logic::TimeBound(false, timeInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)), rewardName, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Only simple reward expressions are currently supported"); - } + return std::make_shared(std::make_shared(storm::logic::TimeBound(false, timeInstantExpr), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time), rewardAccumulation), rewardName, opInfo); } } else if (propertyStructure.count("reward-instants") > 0) { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Instant Reward for reward constraints not supported currently."); - } - - //STORM_LOG_THROW(!accTime && !accSteps, storm::exceptions::NotSupportedException, "Storm only allows accumulation if a step- or time-bound is given."); - - if (rewExpr.isVariable()) { - std::string rewardName = rewExpr.getVariables().begin()->getName(); - return std::make_shared(reach, rewardName, opInfo); - } else if (!rewExpr.containsVariables()) { - if(rewExpr.hasIntegerType()) { - if (rewExpr.evaluateAsInt() == 1) { - - return std::make_shared(reach, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expected steps/time only works with constant one."); + std::vector bounds; + std::vector boundReferences; + for (auto const& rewInst : propertyStructure.at("reward-instants")) { + storm::expressions::Expression rewInstRewardModelExpression = parseExpression(rewInst.at("exp"), scope.refine("Reward expression at reward instant")); + STORM_LOG_THROW(rewInstRewardModelExpression.hasNumericalType(), storm::exceptions::InvalidJaniException, "Reward expression '" << rewInstRewardModelExpression << "' does not have numerical type in " << scope.description); + std::string rewInstRewardModelName = rewInstRewardModelExpression.toString(); + if (!rewInstRewardModelExpression.isVariable()) { + nonTrivialRewardModelExpressions.emplace(rewInstRewardModelName, rewInstRewardModelExpression); } - } else if (rewExpr.hasRationalType()){ - if (rewExpr.evaluateAsDouble() == 1.0) { - - return std::make_shared(reach, opInfo); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expected steps/time only works with constant one."); - } - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Only numerical reward expressions are allowed"); + storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rewInst.at("accumulate"), scope.description); + boundReferences.emplace_back(rewInstRewardModelName, boundRewardAccumulation); + storm::expressions::Expression rewInstantExpr = parseExpression(rewInst.at("instant"), scope.refine("reward instant")); + bounds.emplace_back(false, rewInstantExpr); } - + return std::make_shared(std::make_shared(bounds, boundReferences, rewardAccumulation), rewardName, opInfo); } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex reward expressions are supported at the moment"); + time = !rewExpr.containsVariables() && storm::utility::isOne(rewExpr.evaluateAsRational()); + std::shared_ptr subformula; + if (propertyStructure.count("reach") > 0) { + auto formulaContext = time ? storm::logic::FormulaContext::Time : storm::logic::FormulaContext::Reward; + subformula = std::make_shared(parseFormula(propertyStructure.at("reach"), formulaContext, scope.refine("Reach-expression of operator " + opString)), formulaContext, rewardAccumulation); + } else { + subformula = std::make_shared(rewardAccumulation); + } + if (time) { + assert(subformula->isTotalRewardFormula() || subformula->isTimePathFormula()); + return std::make_shared(subformula, opInfo); + } else { + return std::make_shared(subformula, rewardName, opInfo); + } + } + if (!time && !rewExpr.isVariable()) { + nonTrivialRewardModelExpressions.emplace(rewardName, rewExpr); } - - } else if (opString == "Smin" || opString == "Smax") { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Smin and Smax are currently not supported"); } else if (opString == "U" || opString == "F") { assert(bound == boost::none); std::vector> args; if (opString == "U") { - args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, globalVars, constants, ""); + args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, scope); } else { assert(opString == "F"); - args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, ""); + args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, scope); args.push_back(args[0]); args[0] = storm::logic::BooleanLiteralFormula::getTrueFormula(); } + + std::vector> lowerBounds, upperBounds; + std::vector tbReferences; if (propertyStructure.count("step-bounds") > 0) { - storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds")); - STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports step-bounded until with an upper bound"); - if(pi.hasLowerBound()) { - STORM_LOG_THROW(pi.lowerBound.evaluateAsInt() == 0, storm::exceptions::NotSupportedException, "Storm only supports step-bounded until without a (non-trivial) lower-bound"); + storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("step-bounds"), scope.refine("step-bounded until").clearVariables()); + boost::optional lowerBound, upperBound; + if (pi.hasLowerBound()) { + lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); + } else { + lowerBounds.push_back(boost::none); } - int64_t upperBound = pi.upperBound.evaluateAsInt(); - if(pi.upperBoundStrict) { - upperBound--; + if (pi.hasUpperBound()) { + upperBounds.push_back(storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound)); + } else { + upperBounds.push_back(boost::none); } - STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "Step-bounds cannot be negative"); - return std::make_shared(args[0], args[1], storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound), storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Steps)); - } else if (propertyStructure.count("time-bounds") > 0) { - storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds")); - STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports time-bounded until with an upper bound."); - double lowerBound = 0.0; - if(pi.hasLowerBound()) { - lowerBound = pi.lowerBound.evaluateAsDouble(); + tbReferences.emplace_back(storm::logic::TimeBoundType::Steps); + } + if (propertyStructure.count("time-bounds") > 0) { + storm::jani::PropertyInterval pi = parsePropertyInterval(propertyStructure.at("time-bounds"), scope.refine("time-bounded until").clearVariables()); + boost::optional lowerBound, upperBound; + if (pi.hasLowerBound()) { + lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); + } else { + lowerBounds.push_back(boost::none); } - double upperBound = pi.upperBound.evaluateAsDouble(); - STORM_LOG_THROW(lowerBound >= 0, storm::exceptions::InvalidJaniException, "(Lower) time-bounds cannot be negative"); - STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "(Upper) time-bounds cannot be negative"); - return std::make_shared(args[0], args[1], storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound), storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound), storm::logic::TimeBoundReference(storm::logic::TimeBoundType::Time)); - - } else if (propertyStructure.count("reward-bounds") > 0 ) { - std::vector> lowerBounds; - std::vector> upperBounds; - std::vector tbReferences; + if (pi.hasUpperBound()) { + upperBounds.push_back(storm::logic::TimeBound(pi.upperBoundStrict, pi.upperBound)); + } else { + upperBounds.push_back(boost::none); + } + tbReferences.emplace_back(storm::logic::TimeBoundType::Time); + } + if (propertyStructure.count("reward-bounds") > 0 ) { for (auto const& rbStructure : propertyStructure.at("reward-bounds")) { - storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds")); - STORM_LOG_THROW(pi.hasUpperBound(), storm::exceptions::NotSupportedException, "Storm only supports time-bounded until with an upper bound."); - STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << context); - storm::expressions::Expression rewExpr = parseExpression(rbStructure.at("exp"), "Reward expression in " + context, globalVars, constants); - STORM_LOG_THROW(rewExpr.isVariable(), storm::exceptions::NotSupportedException, "Storm currently does not support complex reward expressions."); - std::string rewardName = rewExpr.getVariables().begin()->getName(); - STORM_LOG_WARN("Reward-type (steps, time) is deduced from model type."); - double lowerBound = 0.0; - if(pi.hasLowerBound()) { - lowerBound = pi.lowerBound.evaluateAsDouble(); + storm::jani::PropertyInterval pi = parsePropertyInterval(rbStructure.at("bounds"), scope.refine("reward-bounded until").clearVariables()); + STORM_LOG_THROW(rbStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Expecting reward-expression for operator " << opString << " in " << scope.description); + storm::expressions::Expression rewInstRewardModelExpression = parseExpression(rbStructure.at("exp"), scope.refine("Reward expression at reward-bounds")); + STORM_LOG_THROW(rewInstRewardModelExpression.hasNumericalType(), storm::exceptions::InvalidJaniException, "Reward expression '" << rewInstRewardModelExpression << "' does not have numerical type in " << scope.description); + std::string rewInstRewardModelName = rewInstRewardModelExpression.toString(); + if (!rewInstRewardModelExpression.isVariable()) { + nonTrivialRewardModelExpressions.emplace(rewInstRewardModelName, rewInstRewardModelExpression); } - double upperBound = pi.upperBound.evaluateAsDouble(); - STORM_LOG_THROW(lowerBound >= 0, storm::exceptions::InvalidJaniException, "(Lower) time-bounds cannot be negative"); - STORM_LOG_THROW(upperBound >= 0, storm::exceptions::InvalidJaniException, "(Upper) time-bounds cannot be negative"); + storm::logic::RewardAccumulation boundRewardAccumulation = parseRewardAccumulation(rbStructure.at("accumulate"), scope.description); + tbReferences.emplace_back(rewInstRewardModelName, boundRewardAccumulation); if (pi.hasLowerBound()) { lowerBounds.push_back(storm::logic::TimeBound(pi.lowerBoundStrict, pi.lowerBound)); } else { @@ -398,20 +437,18 @@ namespace storm { } else { upperBounds.push_back(boost::none); } - tbReferences.push_back(storm::logic::TimeBoundReference(rewardName)); } - auto res = std::make_shared(args[0], args[1], lowerBounds, upperBounds, tbReferences); - return res; - } - if (args[0]->isTrueFormula()) { + if (!tbReferences.empty()) { + return std::make_shared(args[0], args[1], lowerBounds, upperBounds, tbReferences); + } else if (args[0]->isTrueFormula()) { return std::make_shared(args[1], formulaContext); } else { return std::make_shared(args[0], args[1]); } } else if (opString == "G") { assert(bound == boost::none); - std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, "Subformula of globally operator " + context); + std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, scope.refine("Subformula of globally operator ")); if (propertyStructure.count("step-bounds") > 0) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Globally and step-bounds are not supported currently"); } else if (propertyStructure.count("time-bounds") > 0) { @@ -429,17 +466,23 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Release is not supported"); } else if (opString == "∧" || opString == "∨") { assert(bound == boost::none); - std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, globalVars, constants, ""); + std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, scope); assert(args.size() == 2); storm::logic::BinaryBooleanStateFormula::OperatorType oper = opString == "∧" ? storm::logic::BinaryBooleanStateFormula::OperatorType::And : storm::logic::BinaryBooleanStateFormula::OperatorType::Or; return std::make_shared(oper, args[0], args[1]); + } else if (opString == "⇒") { + assert(bound == boost::none); + std::vector> args = parseBinaryFormulaArguments(propertyStructure, formulaContext, opString, scope); + assert(args.size() == 2); + std::shared_ptr tmp = std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); + return std::make_shared(storm::logic::BinaryBooleanStateFormula::OperatorType::Or, tmp, args[1]); } else if (opString == "¬") { assert(bound == boost::none); - std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, globalVars, constants, ""); + std::vector> args = parseUnaryFormulaArgument(propertyStructure, formulaContext, opString, scope); assert(args.size() == 1); return std::make_shared(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); - } else if (opString == "≥" || opString == "≤" || opString == "<" || opString == ">") { + } else if (opString == "≥" || opString == "≤" || opString == "<" || opString == ">" || opString == "=" || opString == "≠") { assert(bound == boost::none); storm::logic::ComparisonType ct; if(opString == "≥") { @@ -451,19 +494,38 @@ namespace storm { } else if (opString == ">") { ct = storm::logic::ComparisonType::Greater; } - if (propertyStructure.at("left").count("op") > 0 && (propertyStructure.at("left").at("op") == "Pmin" || propertyStructure.at("left").at("op") == "Pmax" || propertyStructure.at("left").at("op") == "Emin" || propertyStructure.at("left").at("op") == "Emax" || propertyStructure.at("left").at("op") == "Smin" || propertyStructure.at("left").at("op") == "Smax")) { - auto expr = parseExpression(propertyStructure.at("right"), "Threshold for operator " + propertyStructure.at("left").at("op").get(),{},{}); - STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported"); - return parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); - - } else if(propertyStructure.at("right").count("op") > 0 && (propertyStructure.at("right").at("op") == "Pmin" || propertyStructure.at("right").at("op") == "Pmax" || propertyStructure.at("right").at("op") == "Emin" || propertyStructure.at("right").at("op") == "Emax" || propertyStructure.at("right").at("op") == "Smin" || propertyStructure.at("right").at("op") == "Smax")) { - auto expr = parseExpression(propertyStructure.at("left"), "Threshold for operator " + propertyStructure.at("right").at("op").get(),{},{}); - STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported"); - // TODO evaluate this expression directly as rational number - return parseFormula(propertyStructure.at("right"),formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons are allowed."); + + std::vector const leftRight = {"left", "right"}; + for (uint64_t i = 0; i < 2; ++i) { + if (propertyStructure.at(leftRight[i]).count("op") > 0) { + std::string propertyOperatorString = getString(propertyStructure.at(leftRight[i]).at("op"), "property-operator"); + std::set const propertyOperatorStrings = {"Pmin", "Pmax","Emin", "Emax", "Smin", "Smax"}; + if (propertyOperatorStrings.count(propertyOperatorString) > 0) { + auto boundExpr = parseExpression(propertyStructure.at(leftRight[1-i]), scope.refine("Threshold for operator " + propertyStructure.at(leftRight[i]).at("op").get())); + if ((opString == "=" || opString == "≠")) { + STORM_LOG_THROW(!boundExpr.containsVariables(), storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); + auto boundValue = boundExpr.evaluateAsRational(); + if (storm::utility::isZero(boundValue)) { + if (opString == "=") { + ct = storm::logic::ComparisonType::LessEqual; + } else { + ct = storm::logic::ComparisonType::Greater; + } + } else if (storm::utility::isOne(boundValue) && (propertyOperatorString == "Pmin" || propertyOperatorString == "Pmax")) { + if (opString == "=") { + ct = storm::logic::ComparisonType::GreaterEqual; + } else { + ct = storm::logic::ComparisonType::Less; + } + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); + } + } + return parseFormula(propertyStructure.at(leftRight[i]), formulaContext, scope, storm::logic::Bound(ct, boundExpr)); + } + } } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons for properties are supported."); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opString); } @@ -472,10 +534,11 @@ namespace storm { } } - storm::jani::Property JaniParser::parseProperty(json const& propertyStructure, std::unordered_map> const& globalVars, std::unordered_map> const& constants) { + storm::jani::Property JaniParser::parseProperty(json const& propertyStructure, Scope const& scope) { STORM_LOG_THROW(propertyStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Property must have a name"); // TODO check unique name std::string name = getString(propertyStructure.at("name"), "property-name"); + STORM_LOG_TRACE("Parsing property named: " << name); std::string comment = ""; if (propertyStructure.count("comment") > 0) { comment = getString(propertyStructure.at("comment"), "comment for property named '" + name + "'."); @@ -514,52 +577,67 @@ namespace storm { } STORM_LOG_THROW(expressionStructure.count("states") == 1, storm::exceptions::InvalidJaniException, "Filter must have a states description"); - STORM_LOG_THROW(expressionStructure.at("states").count("op") > 0, storm::exceptions::NotImplementedException, "We only support properties where the filter has initial states"); - std::string statesDescr = getString(expressionStructure.at("states").at("op"), "Filtered states in property named " + name); - STORM_LOG_THROW(statesDescr == "initial", storm::exceptions::NotImplementedException, "Only initial states are allowed as set of states we are interested in."); + std::shared_ptr statesFormula; + if (expressionStructure.at("states").count("op") > 0) { + std::string statesDescr = getString(expressionStructure.at("states").at("op"), "Filtered states in property named " + name); + if (statesDescr == "initial") { + statesFormula = std::make_shared("init"); + } + } + if (!statesFormula) { + try { + // Try to parse the states as formula. + statesFormula = parseFormula(expressionStructure.at("states"), storm::logic::FormulaContext::Undefined, scope.refine("Values of property " + name)); + } catch (storm::exceptions::NotSupportedException const& ex) { + throw ex; + } catch (storm::exceptions::NotImplementedException const& ex) { + throw ex; + } + } + STORM_LOG_THROW(statesFormula, storm::exceptions::NotImplementedException, "Could not derive states formula."); STORM_LOG_THROW(expressionStructure.count("values") == 1, storm::exceptions::InvalidJaniException, "Values as input for a filter must be given"); - auto formula = parseFormula(expressionStructure.at("values"), storm::logic::FormulaContext::Undefined, globalVars, constants, "Values of property " + name); - return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft), comment); + auto formula = parseFormula(expressionStructure.at("values"), storm::logic::FormulaContext::Undefined, scope.refine("Values of property " + name)); + return storm::jani::Property(name, storm::jani::FilterExpression(formula, ft, statesFormula), {}, comment); } - std::shared_ptr JaniParser::parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription) { - STORM_LOG_THROW(constantStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); - std::string name = getString(constantStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); + std::shared_ptr JaniParser::parseConstant(json const& constantStructure, Scope const& scope) { + STORM_LOG_THROW(constantStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scope.description + ") must have a name"); + std::string name = getString(constantStructure.at("name"), "variable-name in " + scope.description + "-scope"); // TODO check existance of name. // TODO store prefix in variable. std::string exprManagerName = name; - STORM_LOG_THROW(constantStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Constant '" + name + "' (scope: " + scopeDescription + ") must have a (single) type-declaration."); + STORM_LOG_THROW(constantStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Constant '" + name + "' (scope: " + scope.description + ") must have a (single) type-declaration."); size_t valueCount = constantStructure.count("value"); storm::expressions::Expression initExpr; - STORM_LOG_THROW(valueCount < 2, storm::exceptions::InvalidJaniException, "Value for constant '" + name + "' (scope: " + scopeDescription + ") must be given at most once."); + STORM_LOG_THROW(valueCount < 2, storm::exceptions::InvalidJaniException, "Value for constant '" + name + "' (scope: " + scope.description + ") must be given at most once."); if (valueCount == 1) { // Read initial value before; that makes creation later on a bit easier, and has as an additional benefit that we do not need to check whether the variable occurs also on the assignment. - initExpr = parseExpression(constantStructure.at("value"), "Value of constant " + name + " (scope: " + scopeDescription + ")", {}, constants); + initExpr = parseExpression(constantStructure.at("value"), scope.refine("Value of constant " + name)); assert(initExpr.isInitialized()); } if (constantStructure.at("type").is_object()) { -// STORM_LOG_THROW(variableStructure.at("type").count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << name << "(scope: " << scopeDescription << ") kind must be given"); -// std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scopeDescription + ") "); +// STORM_LOG_THROW(variableStructure.at("type").count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << name << "(scope: " << scope.description << ") kind must be given"); +// std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scope.description + ") "); // if(kind == "bounded") { // // First do the bounds, that makes the code a bit more streamlined -// STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") lower-bound must be given"); -// storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable "+ name + " (scope: " + scopeDescription + ")"); +// STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scope.description << ") lower-bound must be given"); +// storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable "+ name + " (scope: " + scope.description + ")"); // assert(lowerboundExpr.isInitialized()); -// STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") upper-bound must be given"); -// storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scopeDescription + ")"); +// STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scope.description << ") upper-bound must be given"); +// storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scope.description + ")"); // assert(upperboundExpr.isInitialized()); -// STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") base must be given"); -// std::string basictype = getString(variableStructure.at("type").at("base"), "base for bounded type as in variable " + name + "(scope: " + scopeDescription + ") "); +// STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scope.description << ") base must be given"); +// std::string basictype = getString(variableStructure.at("type").at("base"), "base for bounded type as in variable " + name + "(scope: " + scope.description + ") "); // if(basictype == "int") { -// STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); -// STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); +// STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scope.description << ") must be integer-typed"); +// STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scope.description << ") must be integer-typed"); // return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), lowerboundExpr, upperboundExpr); // } else { -// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scopeDescription << ") "); +// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scope.description << ") "); // } // } else { -// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scopeDescription << ") "); +// STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scope.description << ") "); // } } else if(constantStructure.at("type").is_string()) { @@ -584,119 +662,233 @@ namespace storm { } } else { // TODO clocks. - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description " << constantStructure.at("type").dump() << " for constant '" << name << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description " << constantStructure.at("type").dump() << " for constant '" << name << "' (scope: " << scope.description << ")"); } } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << constantStructure.at("type").dump() << " for Variable '" << name << "' (scope: " << scopeDescription << ")"); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << constantStructure.at("type").dump() << " for Variable '" << name << "' (scope: " << scope.description << ")"); + } + + void JaniParser::parseType(ParsedType& result, json const& typeStructure, std::string variableName, Scope const& scope) { + if (typeStructure.is_string()) { + if (typeStructure == "real") { + result.basicType = ParsedType::BasicType::Real; + result.expressionType = expressionManager->getRationalType(); + } else if (typeStructure == "bool") { + result.basicType = ParsedType::BasicType::Bool; + result.expressionType = expressionManager->getBooleanType(); + } else if (typeStructure == "int") { + result.basicType = ParsedType::BasicType::Int; + result.expressionType = expressionManager->getIntegerType(); + } else if(typeStructure == "clock") { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type 'clock' for variable '" << variableName << "' (scope: " << scope.description << ")"); + } else if(typeStructure == "continuous") { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type 'continuous' for variable ''" << variableName << "' (scope: " << scope.description << ")"); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type " << typeStructure.dump() << " for variable '" << variableName << "' (scope: " << scope.description << ")"); + } + } else if (typeStructure.is_object()) { + STORM_LOG_THROW(typeStructure.count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << variableName << "(scope: " << scope.description << ") kind must be given"); + std::string kind = getString(typeStructure.at("kind"), "kind for complex type as in variable " + variableName + "(scope: " + scope.description + ") "); + if (kind == "bounded") { + STORM_LOG_THROW(typeStructure.count("lower-bound") + typeStructure.count("upper-bound") > 0, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scope.description << ") lower-bound or upper-bound must be given"); + storm::expressions::Expression lowerboundExpr; + if (typeStructure.count("lower-bound") > 0) { + lowerboundExpr = parseExpression(typeStructure.at("lower-bound"), scope.refine("Lower bound for variable " + variableName)); + } + storm::expressions::Expression upperboundExpr; + if (typeStructure.count("upper-bound") > 0) { + upperboundExpr = parseExpression(typeStructure.at("upper-bound"), scope.refine("Upper bound for variable "+ variableName)); + } + STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << variableName << "(scope: " << scope.description << ") base must be given"); + std::string basictype = getString(typeStructure.at("base"), "base for bounded type as in variable " + variableName + "(scope: " + scope.description + ") "); + if (basictype == "int") { + STORM_LOG_THROW(!lowerboundExpr.isInitialized() || lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << variableName << "(scope: " << scope.description << ") must be integer-typed"); + STORM_LOG_THROW(!upperboundExpr.isInitialized() || upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << variableName << "(scope: " << scope.description << ") must be integer-typed"); + if (lowerboundExpr.isInitialized() && upperboundExpr.isInitialized() && !lowerboundExpr.containsVariables() && !upperboundExpr.containsVariables()) { + STORM_LOG_THROW(lowerboundExpr.evaluateAsInt() <= upperboundExpr.evaluateAsInt(), storm::exceptions::InvalidJaniException, "Lower bound must not be larger than upper bound for bounded integer variable " << variableName << "(scope: " << scope.description << ")"); + } + result.basicType = ParsedType::BasicType::Int; + result.expressionType = expressionManager->getIntegerType(); + result.bounds = std::make_pair(lowerboundExpr, upperboundExpr); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << variableName << "(scope: " << scope.description << ") "); + } + } else if (kind == "array") { + STORM_LOG_THROW(typeStructure.count("base") == 1, storm::exceptions::InvalidJaniException, "For array type as in variable " << variableName << "(scope: " << scope.description << ") base must be given"); + result.arrayBase = std::make_unique(); + parseType(*result.arrayBase, typeStructure.at("base"), variableName, scope); + result.expressionType = expressionManager->getArrayType(result.arrayBase->expressionType); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << variableName << "(scope: " << scope.description << ") "); + } + } + } + + storm::jani::FunctionDefinition JaniParser::parseFunctionDefinition(json const& functionDefinitionStructure, Scope const& scope, bool firstPass, std::string const& parameterNamePrefix) { + STORM_LOG_THROW(functionDefinitionStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Function definition (scope: " + scope.description + ") must have a name"); + std::string functionName = getString(functionDefinitionStructure.at("name"), "function-name in " + scope.description); + STORM_LOG_THROW(functionDefinitionStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Function definition '" + functionName + "' (scope: " + scope.description + ") must have a (single) type-declaration."); + ParsedType type; + parseType(type, functionDefinitionStructure.at("type"), functionName, scope); + + std::unordered_map parameterNameToVariableMap; + std::vector parameters; + if (!firstPass && functionDefinitionStructure.count("parameters") > 0) { + STORM_LOG_THROW(functionDefinitionStructure.count("parameters") == 1, storm::exceptions::InvalidJaniException, "Function definition '" + functionName + "' (scope: " + scope.description + ") must have exactly one list of parameters."); + for (auto const& parameterStructure : functionDefinitionStructure.at("parameters")) { + STORM_LOG_THROW(parameterStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Parameter declaration of parameter " + std::to_string(parameters.size()) + " of Function definition '" + functionName + "' (scope: " + scope.description + ") must have a name"); + std::string parameterName = getString(parameterStructure.at("name"), "parameter-name of parameter " + std::to_string(parameters.size()) + " of Function definition '" + functionName + "' (scope: " + scope.description + ")"); + ParsedType parameterType; + STORM_LOG_THROW(parameterStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Parameter declaration of parameter " + std::to_string(parameters.size()) + " of Function definition '" + functionName + "' (scope: " + scope.description + ") must have exactly one type."); + parseType(parameterType, parameterStructure.at("type"), parameterName, scope.refine("parameter declaration of parameter " + std::to_string(parameters.size()) + " of function definition " + functionName)); + STORM_LOG_WARN_COND(!parameterType.bounds.is_initialized(), "Bounds on parameter" + parameterName + " of function definition " + functionName + " will be ignored."); + + std::string exprParameterName = parameterNamePrefix + functionName + VARIABLE_AUTOMATON_DELIMITER + parameterName; + parameters.push_back(expressionManager->declareVariable(exprParameterName, parameterType.expressionType)); + parameterNameToVariableMap.emplace(parameterName, parameters.back()); + } + } + + STORM_LOG_THROW(functionDefinitionStructure.count("body") == 1, storm::exceptions::InvalidJaniException, "Function definition '" + functionName + "' (scope: " + scope.description + ") must have a (single) body."); + storm::expressions::Expression functionBody; + if (!firstPass) { + functionBody = parseExpression(functionDefinitionStructure.at("body"), scope.refine("body of function definition " + functionName), false, parameterNameToVariableMap); + STORM_LOG_WARN_COND(functionBody.getType() == type.expressionType, "Type of body of function " + functionName + "' (scope: " + scope.description + ") has type " << functionBody.getType() << " although the function type is given as " << type.expressionType); + } + return storm::jani::FunctionDefinition(functionName, type.expressionType, parameters, functionBody); } - std::shared_ptr JaniParser::parseVariable(json const& variableStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool prefWithScope) { - STORM_LOG_THROW(variableStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scopeDescription + ") must have a name"); - std::string pref = prefWithScope ? scopeDescription + VARIABLE_AUTOMATON_DELIMITER : ""; - std::string name = getString(variableStructure.at("name"), "variable-name in " + scopeDescription + "-scope"); + + std::shared_ptr JaniParser::parseVariable(json const& variableStructure, bool requireInitialValues, Scope const& scope, std::string const& namePrefix) { + STORM_LOG_THROW(variableStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Variable (scope: " + scope.description + ") must have a name"); + std::string name = getString(variableStructure.at("name"), "variable-name in " + scope.description + "-scope"); // TODO check existance of name. // TODO store prefix in variable. - std::string exprManagerName = pref + name; + std::string exprManagerName = namePrefix + name; bool transientVar = defaultVariableTransient; // Default value for variables. size_t tvarcount = variableStructure.count("transient"); - STORM_LOG_THROW(tvarcount <= 1, storm::exceptions::InvalidJaniException, "Multiple definitions of transient not allowed in variable '" + name + "' (scope: " + scopeDescription + ") "); + STORM_LOG_THROW(tvarcount <= 1, storm::exceptions::InvalidJaniException, "Multiple definitions of transient not allowed in variable '" + name + "' (scope: " + scope.description + ") "); if(tvarcount == 1) { - transientVar = getBoolean(variableStructure.at("transient"), "transient-attribute in variable '" + name + "' (scope: " + scopeDescription + ") "); + transientVar = getBoolean(variableStructure.at("transient"), "transient-attribute in variable '" + name + "' (scope: " + scope.description + ") "); } + STORM_LOG_THROW(variableStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Variable '" + name + "' (scope: " + scope.description + ") must have a (single) type-declaration."); + ParsedType type; + parseType(type, variableStructure.at("type"), name, scope); + size_t initvalcount = variableStructure.count("initial-value"); if(transientVar) { - STORM_LOG_THROW(initvalcount == 1, storm::exceptions::InvalidJaniException, "Initial value must be given once for transient variable '" + name + "' (scope: " + scopeDescription + ") "+ name + "' (scope: " + scopeDescription + ") "); + STORM_LOG_THROW(initvalcount == 1, storm::exceptions::InvalidJaniException, "Initial value must be given once for transient variable '" + name + "' (scope: " + scope.description + ") "+ name + "' (scope: " + scope.description + ") "); } else { - STORM_LOG_THROW(initvalcount <= 1, storm::exceptions::InvalidJaniException, "Initial value can be given at most one for variable " + name + "' (scope: " + scopeDescription + ")"); + STORM_LOG_THROW(initvalcount <= 1, storm::exceptions::InvalidJaniException, "Initial value can be given at most one for variable " + name + "' (scope: " + scope.description + ")"); } - STORM_LOG_THROW(variableStructure.count("type") == 1, storm::exceptions::InvalidJaniException, "Variable '" + name + "' (scope: " + scopeDescription + ") must have a (single) type-declaration."); boost::optional initVal; - if(variableStructure.at("type").is_string()) { - if(variableStructure.at("type") == "real") { - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { + if (initvalcount == 1 && !variableStructure.at("initial-value").is_null()) { + initVal = parseExpression(variableStructure.at("initial-value"), scope.refine("Initial value for variable " + name)); + } else { + assert(!transientVar); + } + + bool setInitValFromDefault = !initVal.is_initialized() && requireInitialValues; + if (type.basicType) { + switch (type.basicType.get()) { + case ParsedType::BasicType::Real: + if (setInitValFromDefault) { initVal = expressionManager->rational(defaultRationalInitialValue); + } + if (initVal) { + STORM_LOG_THROW(initVal.get().hasRationalType() || initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for rational variable " + name + "(scope " + scope.description + ") should be a rational"); + return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName), initVal.get(), transientVar); } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); - STORM_LOG_THROW(initVal.get().hasRationalType() || initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for rational variable " + name + "(scope " + scopeDescription + ") should be a rational"); + return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName)); } - return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName), initVal.get(), transientVar); - - } - assert(!transientVar); - return std::make_shared(name, expressionManager->declareRationalVariable(exprManagerName)); - } else if(variableStructure.at("type") == "bool") { - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { - initVal = expressionManager->boolean(defaultBooleanInitialValue); + case ParsedType::BasicType::Int: + if (setInitValFromDefault) { + if (type.bounds) { + storm::expressions::Expression takeDefaultCondition; + if (type.bounds->first.isInitialized()) { + takeDefaultCondition = type.bounds->first < defaultIntegerInitialValue; + if (type.bounds->second.isInitialized()) { + takeDefaultCondition = takeDefaultCondition && type.bounds->second >= defaultIntegerInitialValue; + } + } else { + STORM_LOG_ASSERT(type.bounds->second.isInitialized(), "Expected to have either a lower or an upper bound"); + takeDefaultCondition = type.bounds->second >= defaultIntegerInitialValue; + } + initVal = storm::expressions::ite(takeDefaultCondition, expressionManager->integer(defaultIntegerInitialValue), type.bounds->first); + } else { + initVal = expressionManager->integer(defaultIntegerInitialValue); + } + } + if (initVal) { + STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scope.description + ") should be an integer"); + if (type.bounds) { + return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, type.bounds->first, type.bounds->second); + } else { + return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), initVal.get(), transientVar); + } } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); - STORM_LOG_THROW(initVal.get().hasBooleanType(), storm::exceptions::InvalidJaniException, "Initial value for boolean variable " + name + "(scope " + scopeDescription + ") should be a Boolean"); + if (type.bounds) { + return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), initVal.get(), transientVar); + } else { + return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), boost::none, false, type.bounds->first, type.bounds->second); + } } - if(transientVar) { - labels.insert(name); + break; + case ParsedType::BasicType::Bool: + if (setInitValFromDefault) { + initVal = expressionManager->boolean(defaultBooleanInitialValue); } - return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName), initVal.get(), transientVar); - } - assert(!transientVar); - return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName)); - } else if(variableStructure.at("type") == "int") { - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { - initVal = expressionManager->integer(defaultIntegerInitialValue); + if (initVal) { + STORM_LOG_THROW(initVal.get().hasBooleanType(), storm::exceptions::InvalidJaniException, "Initial value for boolean variable " + name + "(scope " + scope.description + ") should be a Boolean"); + if (transientVar) { + labels.insert(name); + } + return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName), initVal.get(), transientVar); } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); - STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scopeDescription + ") should be an integer"); + return std::make_shared(name, expressionManager->declareBooleanVariable(exprManagerName)); } - return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName), initVal.get(), transientVar); - } - assert(!transientVar); // Checked earlier. - return std::make_shared(name, expressionManager->declareIntegerVariable(exprManagerName)); - } else if(variableStructure.at("type") == "clock") { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type 'clock' for variable '" << name << "' (scope: " << scopeDescription << ")"); - } else if(variableStructure.at("type") == "continuous") { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported type 'continuous' for variable ''" << name << "' (scope: " << scopeDescription << ")"); + } + } else if (type.arrayBase) { + STORM_LOG_THROW(type.arrayBase->basicType, storm::exceptions::InvalidJaniException, "Array base type for variable " + name + "(scope " + scope.description + ") should be a BasicType or a BoundedType."); + storm::jani::ArrayVariable::ElementType elementType; + storm::expressions::Type exprVariableType = type.expressionType; + switch (type.arrayBase->basicType.get()) { + case ParsedType::BasicType::Real: + elementType = storm::jani::ArrayVariable::ElementType::Real; + break; + case ParsedType::BasicType::Bool: + elementType = storm::jani::ArrayVariable::ElementType::Bool; + break; + case ParsedType::BasicType::Int: + elementType = storm::jani::ArrayVariable::ElementType::Int; + break; + default: + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported type"); + } + if (setInitValFromDefault) { + initVal = storm::expressions::ValueArrayExpression(*expressionManager, exprVariableType, {}).toExpression(); + } + std::shared_ptr result; + if (initVal) { + STORM_LOG_THROW(initVal->getType().isArrayType(), storm::exceptions::InvalidJaniException, "Initial value for array variable " + name + "(scope " + scope.description + ") should be an Array"); + result = std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType, initVal.get(), transientVar); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); + result = std::make_shared(name, expressionManager->declareArrayVariable(exprManagerName, exprVariableType.getElementType()), elementType); } - } else if(variableStructure.at("type").is_object()) { - STORM_LOG_THROW(variableStructure.at("type").count("kind") == 1, storm::exceptions::InvalidJaniException, "For complex type as in variable " << name << "(scope: " << scopeDescription << ") kind must be given"); - std::string kind = getString(variableStructure.at("type").at("kind"), "kind for complex type as in variable " + name + "(scope: " + scopeDescription + ") "); - if(kind == "bounded") { - // First do the bounds, that makes the code a bit more streamlined - STORM_LOG_THROW(variableStructure.at("type").count("lower-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") lower-bound must be given"); - storm::expressions::Expression lowerboundExpr = parseExpression(variableStructure.at("type").at("lower-bound"), "Lower bound for variable " + name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); - assert(lowerboundExpr.isInitialized()); - STORM_LOG_THROW(variableStructure.at("type").count("upper-bound") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") upper-bound must be given"); - storm::expressions::Expression upperboundExpr = parseExpression(variableStructure.at("type").at("upper-bound"), "Upper bound for variable "+ name + " (scope: " + scopeDescription + ")", globalVars, constants, localVars); - assert(upperboundExpr.isInitialized()); - STORM_LOG_THROW(variableStructure.at("type").count("base") == 1, storm::exceptions::InvalidJaniException, "For bounded type as in variable " << name << "(scope: " << scopeDescription << ") base must be given"); - if(initvalcount == 1) { - if(variableStructure.at("initial-value").is_null()) { - initVal = storm::expressions::ite(lowerboundExpr < 0 && upperboundExpr > 0, expressionManager->integer(0), lowerboundExpr); - // TODO as soon as we support half-open intervals, we have to change this. - } else { - initVal = parseExpression(variableStructure.at("initial-value"), "Initial value for variable " + name + " (scope: " + scopeDescription + ") ", globalVars, constants, localVars); - } + if (type.arrayBase->bounds) { + auto const& bounds = type.arrayBase->bounds.get(); + if (bounds.first.isInitialized()) { + result->setLowerElementTypeBound(bounds.first); } - std::string basictype = getString(variableStructure.at("type").at("base"), "base for bounded type as in variable " + name + "(scope: " + scopeDescription + ") "); - if(basictype == "int") { - if(initVal) { - STORM_LOG_THROW(initVal.get().hasIntegerType(), storm::exceptions::InvalidJaniException, "Initial value for integer variable " + name + "(scope " + scopeDescription + ") should be an integer"); - } - STORM_LOG_THROW(lowerboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Lower bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); - STORM_LOG_THROW(upperboundExpr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Upper bound for bounded integer variable " << name << "(scope: " << scopeDescription << ") must be integer-typed"); - return storm::jani::makeBoundedIntegerVariable(name, expressionManager->declareIntegerVariable(exprManagerName), initVal, transientVar, lowerboundExpr, upperboundExpr); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported base " << basictype << " for bounded variable " << name << "(scope: " << scopeDescription << ") "); + if (bounds.second.isInitialized()) { + result->setUpperElementTypeBound(bounds.second); } - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unsupported kind " << kind << " for complex type of variable " << name << "(scope: " << scopeDescription << ") "); } + return result; } - - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scopeDescription << ")"); + + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown type description, " << variableStructure.at("type").dump() << " for variable '" << name << "' (scope: " << scope.description << ")"); } /** @@ -706,21 +898,21 @@ namespace storm { STORM_LOG_THROW(expected == actual, storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects " << expected << " arguments, but got " << actual << " in " << errorInfo << "."); } - std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator) { - storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), "Argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars,returnNoneInitializedOnUnknownOperator); + std::vector JaniParser::parseUnaryExpressionArguments(json const& expressionDecl, std::string const& opstring, Scope const& scope, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression left = parseExpression(expressionDecl.at("exp"), scope.refine("Argument of operator " + opstring), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left}; } - std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator) { - storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), "Left argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); - storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), "Right argument of operator " + opstring + " in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + std::vector JaniParser::parseBinaryExpressionArguments(json const& expressionDecl, std::string const& opstring, Scope const& scope, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + storm::expressions::Expression left = parseExpression(expressionDecl.at("left"), scope.refine("Left argument of operator " + opstring), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + storm::expressions::Expression right = parseExpression(expressionDecl.at("right"), scope.refine("Right argument of operator " + opstring), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); return {left, right}; } /** * Helper for parse expression. */ void ensureBooleanType(storm::expressions::Expression const& expr, std::string const& opstring, unsigned argNr, std::string const& errorInfo) { - STORM_LOG_THROW(expr.hasBooleanType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be Boolean in " << errorInfo << "."); + STORM_LOG_THROW(expr.hasBooleanType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument[" << argNr << "]: '" << expr << "' to be Boolean in " << errorInfo << "."); } /** @@ -730,267 +922,376 @@ namespace storm { STORM_LOG_THROW(expr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be numerical in " << errorInfo << "."); } - storm::jani::Variable const& getLValue(std::string const& ident, storm::jani::VariableSet const& globalVars, storm::jani::VariableSet const& localVars, std::string const& scopeDescription) { - if(localVars.hasVariable(ident)) { - return localVars.getVariable(ident); - } else if(globalVars.hasVariable(ident)) { - return globalVars.getVariable(ident); + /** + * Helper for parse expression. + */ + void ensureIntegerType(storm::expressions::Expression const& expr, std::string const& opstring, unsigned argNr, std::string const& errorInfo) { + STORM_LOG_THROW(expr.hasIntegerType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be numerical in " << errorInfo << "."); + } + + /** + * Helper for parse expression. + */ + void ensureArrayType(storm::expressions::Expression const& expr, std::string const& opstring, unsigned argNr, std::string const& errorInfo) { + STORM_LOG_THROW(expr.getType().isArrayType(), storm::exceptions::InvalidJaniException, "Operator " << opstring << " expects argument " + std::to_string(argNr) + " to be of type 'array' in " << errorInfo << "."); + } + + storm::jani::LValue JaniParser::parseLValue(json const& lValueStructure, Scope const& scope) { + if (lValueStructure.is_string()) { + std::string ident = getString(lValueStructure, scope.description); + if (scope.localVars != nullptr) { + auto localVar = scope.localVars->find(ident); + if (localVar != scope.localVars->end()) { + return storm::jani::LValue(*localVar->second); + } + } + STORM_LOG_THROW(scope.globalVars != nullptr, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scope.description); + auto globalVar = scope.globalVars->find(ident); + STORM_LOG_THROW(globalVar != scope.globalVars->end(), storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scope.description); + return storm::jani::LValue(*globalVar->second); + } else if (lValueStructure.count("op") == 1) { + std::string opstring = getString(lValueStructure.at("op"), scope.description); + STORM_LOG_THROW(opstring == "aa", storm::exceptions::InvalidJaniException, "Unknown operation '" << opstring << "' occurs in " << scope.description); + STORM_LOG_THROW(lValueStructure.count("exp"), storm::exceptions::InvalidJaniException, "Missing 'exp' in array access at " << scope.description); + storm::jani::LValue exp = parseLValue(lValueStructure.at("exp"), scope.refine("LValue description of array expression")); + STORM_LOG_THROW(lValueStructure.count("index"), storm::exceptions::InvalidJaniException, "Missing 'index' in array access at " << scope.description); + storm::expressions::Expression index = parseExpression(lValueStructure.at("index"), scope.refine("Index expression of array access")); + return storm::jani::LValue(exp, index); } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown LValue '" << lValueStructure.dump() << "' occurs in " << scope.description); + // Silly warning suppression. + return storm::jani::LValue(*scope.globalVars->end()->second); } } - storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars) { - if(localVars.count(ident) == 1) { - return localVars.at(ident)->getExpressionVariable(); - } else if(globalVars.count(ident) == 1) { - return globalVars.at(ident)->getExpressionVariable(); - } else if(constants.count(ident) == 1) { - return constants.at(ident)->getExpressionVariable(); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scopeDescription); + storm::expressions::Variable JaniParser::getVariableOrConstantExpression(std::string const& ident, Scope const& scope, std::unordered_map const& auxiliaryVariables) { + { + auto it = auxiliaryVariables.find(ident); + if (it != auxiliaryVariables.end()) { + return it->second; + } } + if (scope.localVars != nullptr) { + auto it = scope.localVars->find(ident); + if (it != scope.localVars->end()) { + return it->second->getExpressionVariable(); + } + } + if (scope.globalVars != nullptr) { + auto it = scope.globalVars->find(ident); + if (it != scope.globalVars->end()) { + return it->second->getExpressionVariable(); + } + } + if (scope.constants != nullptr) { + auto it = scope.constants->find(ident); + if (it != scope.constants->end()) { + return it->second->getExpressionVariable(); + } + } + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown identifier '" << ident << "' occurs in " << scope.description); + // Silly warning suppression. + return storm::expressions::Variable(); } - storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars, bool returnNoneInitializedOnUnknownOperator) { - if(expressionStructure.is_boolean()) { - if(expressionStructure.get()) { + storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, Scope const& scope, bool returnNoneInitializedOnUnknownOperator, std::unordered_map const& auxiliaryVariables) { + if (expressionStructure.is_boolean()) { + if (expressionStructure.get()) { return expressionManager->boolean(true); } else { return expressionManager->boolean(false); } - } else if(expressionStructure.is_number_integer()) { + } else if (expressionStructure.is_number_integer()) { return expressionManager->integer(expressionStructure.get()); - } else if(expressionStructure.is_number_float()) { - // For now, just take the double. - // TODO make this a rational number - return expressionManager->rational(expressionStructure.get()); - } else if(expressionStructure.is_string()) { + } else if (expressionStructure.is_number_float()) { + return expressionManager->rational(storm::utility::convertNumber(expressionStructure.dump())); + } else if (expressionStructure.is_string()) { std::string ident = expressionStructure.get(); - return storm::expressions::Expression(getVariableOrConstantExpression(ident, scopeDescription, globalVars, constants, localVars)); - } else if(expressionStructure.is_object()) { - if(expressionStructure.count("distribution") == 1) { - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Distributions are not supported by storm expressions, cannot import " << expressionStructure.dump() << " in " << scopeDescription << "."); + return storm::expressions::Expression(getVariableOrConstantExpression(ident, scope, auxiliaryVariables)); + } else if (expressionStructure.is_object()) { + if (expressionStructure.count("distribution") == 1) { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Distributions are not supported by storm expressions, cannot import " << expressionStructure.dump() << " in " << scope.description << "."); } - if(expressionStructure.count("op") == 1) { - std::string opstring = getString(expressionStructure.at("op"), scopeDescription); + if (expressionStructure.count("op") == 1) { + std::string opstring = getString(expressionStructure.at("op"), scope.description); std::vector arguments = {}; if(opstring == "ite") { STORM_LOG_THROW(expressionStructure.count("if") == 1, storm::exceptions::InvalidJaniException, "If operator required"); STORM_LOG_THROW(expressionStructure.count("else") == 1, storm::exceptions::InvalidJaniException, "Else operator required"); - STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "If operator required"); - arguments.push_back(parseExpression(expressionStructure.at("if"), "if-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); - arguments.push_back(parseExpression(expressionStructure.at("then"), "then-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); - arguments.push_back(parseExpression(expressionStructure.at("else"), "else-formula in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator)); - ensureNumberOfArguments(3, arguments.size(), opstring, scopeDescription); + STORM_LOG_THROW(expressionStructure.count("then") == 1, storm::exceptions::InvalidJaniException, "Then operator required"); + arguments.push_back(parseExpression(expressionStructure.at("if"), scope.refine("if-formula"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + arguments.push_back(parseExpression(expressionStructure.at("then"), scope.refine("then-formula"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + arguments.push_back(parseExpression(expressionStructure.at("else"), scope.refine("else-formula"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables)); + ensureNumberOfArguments(3, arguments.size(), opstring, scope.description); assert(arguments.size() == 3); - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); return storm::expressions::ite(arguments[0], arguments[1], arguments[2]); } else if (opstring == "∨") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return arguments[0] || arguments[1]; } else if (opstring == "∧") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return arguments[0] && arguments[1]; } else if (opstring == "⇒") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return (!arguments[0]) || arguments[1]; } else if (opstring == "¬") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); if(!arguments[0].isInitialized()) { return storm::expressions::Expression(); } - ensureBooleanType(arguments[0], opstring, 0, scopeDescription); + ensureBooleanType(arguments[0], opstring, 0, scope.description); return !arguments[0]; } else if (opstring == "=") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); + if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { + return storm::expressions::Expression(); + } if(arguments[0].hasBooleanType()) { - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return storm::expressions::iff(arguments[0], arguments[1]); } else { - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] == arguments[1]; } } else if (opstring == "≠") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); + if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { + return storm::expressions::Expression(); + } if(arguments[0].hasBooleanType()) { - ensureBooleanType(arguments[1], opstring, 1, scopeDescription); + ensureBooleanType(arguments[1], opstring, 1, scope.description); return storm::expressions::xclusiveor(arguments[0], arguments[1]); } else { - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] != arguments[1]; } } else if (opstring == "<") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] < arguments[1]; } else if (opstring == "≤") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] <= arguments[1]; } else if (opstring == ">") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] > arguments[1]; } else if (opstring == "≥") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { return storm::expressions::Expression(); } - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] >= arguments[1]; } else if (opstring == "+") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] + arguments[1]; - } else if (opstring == "-") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + } else if (opstring == "-" && expressionStructure.count("left") > 0) { + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] - arguments[1]; } else if (opstring == "-") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription,globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return -arguments[0]; } else if (opstring == "*") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] * arguments[1]; } else if (opstring == "/") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return arguments[0] / arguments[1]; } else if (opstring == "%") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); - // TODO implement - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "modulo operation is not yet implemented"); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); + return arguments[0] % arguments[1]; } else if (opstring == "max") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return storm::expressions::maximum(arguments[0],arguments[1]); } else if (opstring == "min") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); return storm::expressions::minimum(arguments[0],arguments[1]); } else if (opstring == "floor") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::floor(arguments[0]); } else if (opstring == "ceil") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::ceil(arguments[0]); } else if (opstring == "abs") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::abs(arguments[0]); } else if (opstring == "sgn") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); return storm::expressions::sign(arguments[0]); } else if (opstring == "trc") { - arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseUnaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 1); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - return storm::expressions::abs(arguments[0]); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + return storm::expressions::truncate(arguments[0]); } else if (opstring == "pow") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); - // TODO implement - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "pow operation is not yet implemented"); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); + return arguments[0]^arguments[1]; } else if (opstring == "exp") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); // TODO implement STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "exp operation is not yet implemented"); } else if (opstring == "log") { - arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator); + arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scope, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); - ensureNumericalType(arguments[0], opstring, 0, scopeDescription); - ensureNumericalType(arguments[1], opstring, 1, scopeDescription); + ensureNumericalType(arguments[0], opstring, 0, scope.description); + ensureNumericalType(arguments[1], opstring, 1, scope.description); // TODO implement STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "log operation is not yet implemented"); - } else if (unsupportedOpstrings.count(opstring) > 0){ + } else if (opstring == "aa") { + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scope.description + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), scope.refine("'exp' of array access operator"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + STORM_LOG_THROW(expressionStructure.count("index") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one index (at " + scope.description + ")."); + storm::expressions::Expression index = parseExpression(expressionStructure.at("index"), scope.refine("index of array access operator"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + ensureArrayType(exp, opstring, 0, scope.description); + ensureIntegerType(index, opstring, 1, scope.description); + return std::make_shared(exp.getManager(), exp.getType().getElementType(), exp.getBaseExpressionPointer(), index.getBaseExpressionPointer())->toExpression(); + } else if (opstring == "av") { + STORM_LOG_THROW(expressionStructure.count("elements") == 1, storm::exceptions::InvalidJaniException, "Array value operator requires exactly one 'elements' (at " + scope.description + ")."); + std::vector> elements; + storm::expressions::Type commonType; + bool first = true; + for (auto const& element : expressionStructure.at("elements")) { + elements.push_back(parseExpression(element, scope.refine("element " + std::to_string(elements.size()) + " of array value expression"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables).getBaseExpressionPointer()); + if (first) { + commonType = elements.back()->getType(); + first = false; + } else if (!(commonType == elements.back()->getType())) { + if (commonType.isIntegerType() && elements.back()->getType().isRationalType()) { + commonType = elements.back()->getType(); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Incompatible element types " << commonType << " and " << elements.back()->getType() << " of array value expression at " << scope.description); + } + } + } + return std::make_shared(*expressionManager, expressionManager->getArrayType(commonType), elements)->toExpression(); + } else if (opstring == "ac") { + STORM_LOG_THROW(expressionStructure.count("length") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one length (at " + scope.description + ")."); + storm::expressions::Expression length = parseExpression(expressionStructure.at("length"), scope.refine("index of array constructor expression"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables); + ensureIntegerType(length, opstring, 1, scope.description); + STORM_LOG_THROW(expressionStructure.count("var") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one var (at " + scope.description + ")."); + std::string indexVarName = getString(expressionStructure.at("var"), "Field 'var' of Array access operator (at " + scope.description + ")."); + STORM_LOG_THROW(auxiliaryVariables.find(indexVarName) == auxiliaryVariables.end(), storm::exceptions::InvalidJaniException, "Index variable " << indexVarName << " is already defined as an auxiliary variable (at " + scope.description + ")."); + auto newAuxVars = auxiliaryVariables; + storm::expressions::Variable indexVar = expressionManager->declareFreshIntegerVariable(false, "ac_" + indexVarName); + newAuxVars.emplace(indexVarName, indexVar); + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array constructor operator requires exactly one exp (at " + scope.description + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), scope.refine("exp of array constructor"), returnNoneInitializedOnUnknownOperator, newAuxVars); + return std::make_shared(*expressionManager, expressionManager->getArrayType(exp.getType()), length.getBaseExpressionPointer(), indexVar, exp.getBaseExpressionPointer())->toExpression(); + } else if (opstring == "call") { + STORM_LOG_THROW(expressionStructure.count("function") == 1, storm::exceptions::InvalidJaniException, "Function call operator requires exactly one function (at " + scope.description + ")."); + std::string functionName = getString(expressionStructure.at("function"), "in function call operator (at " + scope.description + ")."); + storm::jani::FunctionDefinition const* functionDefinition; + if (scope.localFunctions != nullptr && scope.localFunctions->count(functionName) > 0) { + functionDefinition = scope.localFunctions->at(functionName); + } else if (scope.globalFunctions != nullptr && scope.globalFunctions->count(functionName) > 0){ + functionDefinition = scope.globalFunctions->at(functionName); + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Function call operator calls unknown function '" + functionName + "' (at " + scope.description + ")."); + } + STORM_LOG_THROW(expressionStructure.count("args") == 1, storm::exceptions::InvalidJaniException, "Function call operator requires exactly one args (at " + scope.description + ")."); + std::vector> args; + if (expressionStructure.count("args") > 0) { + STORM_LOG_THROW(expressionStructure.count("args") == 1, storm::exceptions::InvalidJaniException, "Function call operator requires exactly one args (at " + scope.description + ")."); + for (auto const& arg : expressionStructure.at("args")) { + args.push_back(parseExpression(arg, scope.refine("argument " + std::to_string(args.size()) + " of function call expression"), returnNoneInitializedOnUnknownOperator, auxiliaryVariables).getBaseExpressionPointer()); + } + } + return std::make_shared(*expressionManager, functionDefinition->getType(), functionName, args)->toExpression(); + } else if (unsupportedOpstrings.count(opstring) > 0) { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Opstring " + opstring + " is not supported by storm"); - } else { if(returnNoneInitializedOnUnknownOperator) { return storm::expressions::Expression(); } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opstring << " in " << scopeDescription << "."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opstring << " in " << scope.description << "."); } } - STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported operator declaration found for complex expressions as " << expressionStructure.dump() << " in " << scopeDescription << "."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported operator declaration found for complex expressions as " << expressionStructure.dump() << " in " << scope.description << "."); } - assert(false); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "No supported expression found at " << expressionStructure.dump() << " in " << scope.description << "."); // Silly warning suppression. return storm::expressions::Expression(); } - - void JaniParser::parseActions(json const& actionStructure, storm::jani::Model& parentModel) { std::set actionNames; for(auto const& actionEntry : actionStructure) { @@ -1002,24 +1303,50 @@ namespace storm { } } - storm::jani::Automaton JaniParser::parseAutomaton(json const &automatonStructure, storm::jani::Model const& parentModel, std::unordered_map> const& globalVars, std::unordered_map> const& constants ) { + storm::jani::Automaton JaniParser::parseAutomaton(json const &automatonStructure, storm::jani::Model const& parentModel, Scope const& globalScope) { STORM_LOG_THROW(automatonStructure.count("name") == 1, storm::exceptions::InvalidJaniException, "Each automaton must have a name"); std::string name = getString(automatonStructure.at("name"), " the name field for automaton"); + Scope scope = globalScope.refine(name); storm::jani::Automaton automaton(name, expressionManager->declareIntegerVariable("_loc_" + name)); uint64_t varDeclCount = automatonStructure.count("variables"); STORM_LOG_THROW(varDeclCount < 2, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' has more than one list of variables"); - std::unordered_map> localVars; - if(varDeclCount > 0) { + VariablesMap localVars; + scope.localVars = &localVars; + if (varDeclCount > 0) { + bool requireInitialValues = automatonStructure.count("restrict-initial") == 0; for(auto const& varStructure : automatonStructure.at("variables")) { - std::shared_ptr var = parseVariable(varStructure, name, globalVars, constants, localVars, true); + std::shared_ptr var = parseVariable(varStructure, requireInitialValues, scope.refine("variables[" + std::to_string(localVars.size()) + "] of automaton " + name), name + VARIABLE_AUTOMATON_DELIMITER); assert(localVars.count(var->getName()) == 0); - automaton.addVariable(*var); - localVars.emplace(var->getName(), var); + localVars.emplace(var->getName(), &automaton.addVariable(*var)); } } - + uint64_t funDeclCount = automatonStructure.count("functions"); + STORM_LOG_THROW(funDeclCount < 2, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' has more than one list of functions"); + FunctionsMap localFuns; + scope.localFunctions = &localFuns; + if (funDeclCount > 0) { + // We require two passes through the function definitions array to allow referring to functions before they were defined. + std::vector dummyFunctionDefinitions; + for (auto const& funStructure : automatonStructure.at("functions")) { + // Skip parsing of function body + dummyFunctionDefinitions.push_back(parseFunctionDefinition(funStructure, scope.refine("functions[" + std::to_string(localFuns.size()) + "] of automaton " + name), true)); + } + // Store references to the dummy function definitions. This needs to happen in a separate loop since otherwise, references to FunDefs can be invalidated after calling dummyFunctionDefinitions.push_back + for (auto const& funDef : dummyFunctionDefinitions) { + bool unused = localFuns.emplace(funDef.getName(), &funDef).second; + STORM_LOG_THROW(unused, storm::exceptions::InvalidJaniException, "Multiple definitions of functions with the name " << funDef.getName() << " in " << scope.description); + } + for (auto const& funStructure : automatonStructure.at("functions")) { + // Actually parse the function body + storm::jani::FunctionDefinition funDef = parseFunctionDefinition(funStructure, scope.refine("functions[" + std::to_string(localFuns.size()) + "] of automaton " + name), + false, name + VARIABLE_AUTOMATON_DELIMITER); + assert(localFuns.count(funDef.getName()) == 1); + localFuns[funDef.getName()] = &automaton.addFunctionDefinition(funDef); + } + } + STORM_LOG_THROW(automatonStructure.count("locations") > 0, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' does not have locations."); std::unordered_map locIds; for(auto const& locEntry : automatonStructure.at("locations")) { @@ -1033,10 +1360,10 @@ namespace storm { for(auto const& transientValueEntry : locEntry.at("transient-values")) { STORM_LOG_THROW(transientValueEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one ref that is assigned to"); STORM_LOG_THROW(transientValueEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Transient values in location " << locName << " need exactly one assigned value"); - storm::jani::Variable const& lhs = getLValue(transientValueEntry.at("ref"), parentModel.getGlobalVariables(), automaton.getVariables(), "LHS of assignment in location " + locName + " (automaton '" + name + "')"); - STORM_LOG_THROW(lhs.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')"); - storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), "Assignment of variable " + lhs.getName() + " in location " + locName + " (automaton: '" + name + "')", globalVars, constants, localVars); - transientAssignments.emplace_back(lhs, rhs); + storm::jani::LValue lValue = parseLValue(transientValueEntry.at("ref"), scope.refine("LHS of assignment in location " + locName)); + STORM_LOG_THROW(lValue.isTransient(), storm::exceptions::InvalidJaniException, "Assigned non-transient variable " << lValue << " in location " + locName + " (automaton: '" + name + "')"); + storm::expressions::Expression rhs = parseExpression(transientValueEntry.at("value"), scope.refine("Assignment of lValue in location " + locName)); + transientAssignments.emplace_back(lValue, rhs); } } uint64_t id = automaton.addLocation(storm::jani::Location(locName, transientAssignments)); @@ -1050,12 +1377,11 @@ namespace storm { storm::expressions::Expression initialValueRestriction = expressionManager->boolean(true); if(automatonStructure.count("restrict-initial") > 0) { STORM_LOG_THROW(automatonStructure.at("restrict-initial").count("exp") == 1, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' needs an expression inside the initial restricion"); - initialValueRestriction = parseExpression(automatonStructure.at("restrict-initial").at("exp"), "Initial value restriction for automaton " + name, globalVars, constants, localVars); + initialValueRestriction = parseExpression(automatonStructure.at("restrict-initial").at("exp"), scope.refine("Initial value restriction")); } automaton.setInitialStatesRestriction(initialValueRestriction); - STORM_LOG_THROW(automatonStructure.count("edges") > 0, storm::exceptions::InvalidJaniException, "Automaton '" << name << "' must have a list of edges"); for(auto const& edgeEntry : automatonStructure.at("edges")) { // source location @@ -1075,7 +1401,7 @@ namespace storm { storm::expressions::Expression rateExpr; if(edgeEntry.count("rate") > 0) { STORM_LOG_THROW(edgeEntry.at("rate").count("exp") == 1, storm::exceptions::InvalidJaniException, "Rate in edge from '" << sourceLoc << "' in automaton '" << name << "' must have a defing expression."); - rateExpr = parseExpression(edgeEntry.at("rate").at("exp"), "rate expression in edge from '" + sourceLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + rateExpr = parseExpression(edgeEntry.at("rate").at("exp"), scope.refine("rate expression in edge from '" + sourceLoc)); STORM_LOG_THROW(rateExpr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Rate '" << rateExpr << "' has not a numerical type"); } // guard @@ -1083,7 +1409,7 @@ namespace storm { storm::expressions::Expression guardExpr = expressionManager->boolean(true); if(edgeEntry.count("guard") == 1) { STORM_LOG_THROW(edgeEntry.at("guard").count("exp") == 1, storm::exceptions::InvalidJaniException, "Guard in edge from '" + sourceLoc + "' in automaton '" + name + "' must have one expression"); - guardExpr = parseExpression(edgeEntry.at("guard").at("exp"), "guard expression in edge from '" + sourceLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + guardExpr = parseExpression(edgeEntry.at("guard").at("exp"), scope.refine("guard expression in edge from '" + sourceLoc)); STORM_LOG_THROW(guardExpr.hasBooleanType(), storm::exceptions::InvalidJaniException, "Guard " << guardExpr << " does not have Boolean type."); } assert(guardExpr.isInitialized()); @@ -1105,7 +1431,7 @@ namespace storm { probExpr = expressionManager->rational(1.0); } else { STORM_LOG_THROW(destEntry.at("probability").count("exp") == 1, storm::exceptions::InvalidJaniException, "Destination in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have a probability expression."); - probExpr = parseExpression(destEntry.at("probability").at("exp"), "probability expression in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + probExpr = parseExpression(destEntry.at("probability").at("exp"), scope.refine("probability expression in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'")); } assert(probExpr.isInitialized()); STORM_LOG_THROW(probExpr.hasNumericalType(), storm::exceptions::InvalidJaniException, "Probability expression " << probExpr << " does not have a numerical type." ); @@ -1117,18 +1443,17 @@ namespace storm { for (auto const& assignmentEntry : destEntry.at("assignments")) { // ref STORM_LOG_THROW(assignmentEntry.count("ref") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one ref field"); - std::string refstring = getString(assignmentEntry.at("ref"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); - storm::jani::Variable const& lhs = getLValue(refstring, parentModel.getGlobalVariables(), automaton.getVariables(), "Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); + storm::jani::LValue lValue = parseLValue(assignmentEntry.at("ref"), scope.refine("Assignment variable in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'")); // value STORM_LOG_THROW(assignmentEntry.count("value") == 1, storm::exceptions::InvalidJaniException, "Assignment in edge from '" << sourceLoc << "' to '" << targetLoc << "' in automaton '" << name << "' must have one value field"); - storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), "assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'", globalVars, constants, localVars); + storm::expressions::Expression assignmentExpr = parseExpression(assignmentEntry.at("value"), scope.refine("assignment in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'")); // TODO check types // index - uint64_t assignmentIndex = 0; // default. + int64_t assignmentIndex = 0; // default. if(assignmentEntry.count("index") > 0) { - assignmentIndex = getUnsignedInt(assignmentEntry.at("index"), "assignment index in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); + assignmentIndex = getSignedInt(assignmentEntry.at("index"), "assignment index in edge from '" + sourceLoc + "' to '" + targetLoc + "' in automaton '" + name + "'"); } - assignments.emplace_back(lhs, assignmentExpr, assignmentIndex); + assignments.emplace_back(lValue, assignmentExpr, assignmentIndex); } } destinationLocationsAndProbabilities.emplace_back(locIds.at(targetLoc), probExpr); diff --git a/src/storm-parsers/parser/JaniParser.h b/src/storm-parsers/parser/JaniParser.h new file mode 100644 index 000000000..93e1a5790 --- /dev/null +++ b/src/storm-parsers/parser/JaniParser.h @@ -0,0 +1,143 @@ +#pragma once +#include "storm/storage/jani/Constant.h" +#include "storm/storage/jani/FunctionDefinition.h" +#include "storm/storage/jani/LValue.h" +#include "storm/logic/Formula.h" +#include "storm/logic/Bound.h" +#include "storm/logic/RewardAccumulation.h" +#include "storm/exceptions/FileIoException.h" +#include "storm/storage/expressions/ExpressionManager.h" + + +// JSON parser +#include "json.hpp" + +using json = nlohmann::json; + +namespace storm { + namespace jani { + class Model; + class Automaton; + class Variable; + class Composition; + class Property; + struct PropertyInterval; + } + + namespace logic { + enum class FormulaContext; + } + + + namespace parser { + /* + * The JANI format parser. + * Parses Models and Properties + */ + class JaniParser { + + public: + typedef std::vector PropertyVector; + typedef std::unordered_map VariablesMap; + typedef std::unordered_map ConstantsMap; + typedef std::unordered_map FunctionsMap; + + JaniParser() : expressionManager(new storm::expressions::ExpressionManager()) {} + JaniParser(std::string const& jsonstring); + static std::pair> parse(std::string const& path, bool parseProperties = true); + + protected: + void readFile(std::string const& path); + + struct Scope { + Scope(std::string description = "global", ConstantsMap const* constants = nullptr, VariablesMap const* globalVars = nullptr, FunctionsMap const* globalFunctions = nullptr, VariablesMap const* localVars = nullptr, FunctionsMap const* localFunctions = nullptr) : description(description) , constants(constants), globalVars(globalVars), globalFunctions(globalFunctions), localVars(localVars), localFunctions(localFunctions) {}; + + Scope(Scope const& other) = default; + std::string description; + ConstantsMap const* constants; + VariablesMap const* globalVars; + FunctionsMap const* globalFunctions; + VariablesMap const* localVars; + FunctionsMap const* localFunctions; + Scope refine(std::string const& prependedDescription = "") const { + Scope res(*this); + if (prependedDescription != "") { + res.description = "'" + prependedDescription + "' at " + res.description; + } + return res; + } + + Scope& clearVariables() { + this->globalVars = nullptr; + this->localVars = nullptr; + return *this; + } + }; + + std::pair> parseModel(bool parseProperties = true); + storm::jani::Property parseProperty(json const& propertyStructure, Scope const& scope); + storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, Scope const& scope); + struct ParsedType { + enum class BasicType {Bool, Int, Real}; + boost::optional basicType; + boost::optional> bounds; + std::unique_ptr arrayBase; + storm::expressions::Type expressionType; + }; + void parseType(ParsedType& result, json const& typeStructure, std::string variableName, Scope const& scope); + storm::jani::LValue parseLValue(json const& lValueStructure, Scope const& scope); + std::shared_ptr parseVariable(json const& variableStructure, bool requireInitialValues, Scope const& scope, std::string const& namePrefix = ""); + storm::expressions::Expression parseExpression(json const& expressionStructure, Scope const& scope, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + + private: + std::shared_ptr parseConstant(json const& constantStructure, Scope const& scope); + storm::jani::FunctionDefinition parseFunctionDefinition(json const& functionDefinitionStructure, Scope const& scope, bool firstPass, std::string const& parameterNamePrefix = ""); + + /** + * Helper for parsing the actions of a model. + */ + void parseActions(json const& actionStructure, storm::jani::Model& parentModel); + std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, Scope const& scope, boost::optional bound = boost::none); + std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, Scope const& scope, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, Scope const& scope, bool returnNoneOnUnknownOpString = false, std::unordered_map const& auxiliaryVariables = {}); + + + std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope); + std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, Scope const& scope); + storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure, Scope const& scope); + storm::logic::RewardAccumulation parseRewardAccumulation(json const& accStructure, std::string const& context); + + std::shared_ptr parseComposition(json const& compositionStructure); + storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, Scope const& scope, std::unordered_map const& auxiliaryVariables = {}); + + + + /** + * The overall structure currently under inspection. + */ + json parsedStructure; + /** + * The expression manager to be used. + */ + std::shared_ptr expressionManager; + + std::set labels = {}; + std::unordered_map nonTrivialRewardModelExpressions; + + bool allowRecursion = true; + + ////////// + // Default values -- assumptions from JANI. + ////////// + static const bool defaultVariableTransient; + + static const bool defaultBooleanInitialValue; + static const double defaultRationalInitialValue; + static const int64_t defaultIntegerInitialValue; + + static const std::set unsupportedOpstrings; + + }; + } +} + diff --git a/src/storm/parser/KeyValueParser.cpp b/src/storm-parsers/parser/KeyValueParser.cpp similarity index 100% rename from src/storm/parser/KeyValueParser.cpp rename to src/storm-parsers/parser/KeyValueParser.cpp diff --git a/src/storm/parser/KeyValueParser.h b/src/storm-parsers/parser/KeyValueParser.h similarity index 100% rename from src/storm/parser/KeyValueParser.h rename to src/storm-parsers/parser/KeyValueParser.h diff --git a/src/storm/parser/MappedFile.cpp b/src/storm-parsers/parser/MappedFile.cpp similarity index 98% rename from src/storm/parser/MappedFile.cpp rename to src/storm-parsers/parser/MappedFile.cpp index 5b9f02714..d28e8e927 100644 --- a/src/storm/parser/MappedFile.cpp +++ b/src/storm-parsers/parser/MappedFile.cpp @@ -5,7 +5,7 @@ * Author: Manuel Sascha Weiand */ -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include #include diff --git a/src/storm/parser/MappedFile.h b/src/storm-parsers/parser/MappedFile.h similarity index 100% rename from src/storm/parser/MappedFile.h rename to src/storm-parsers/parser/MappedFile.h diff --git a/src/storm/parser/MarkovAutomatonParser.cpp b/src/storm-parsers/parser/MarkovAutomatonParser.cpp similarity index 75% rename from src/storm/parser/MarkovAutomatonParser.cpp rename to src/storm-parsers/parser/MarkovAutomatonParser.cpp index 0921556fd..829c7256f 100644 --- a/src/storm/parser/MarkovAutomatonParser.cpp +++ b/src/storm-parsers/parser/MarkovAutomatonParser.cpp @@ -25,36 +25,36 @@ namespace storm { // Parse the state labeling. storm::models::sparse::StateLabeling resultLabeling(storm::parser::SparseItemLabelingParser::parseAtomicPropositionLabeling(transitionMatrix.getColumnCount(), labelingFilename)); - // Cunstruct the result components - storm::storage::sparse::ModelComponents> componets(std::move(transitionMatrix), std::move(resultLabeling)); - componets.rateTransitions = true; - componets.markovianStates = std::move(transitionResult.markovianStates); - componets.exitRates = std::move(transitionResult.exitRates); + // Construct the result components + storm::storage::sparse::ModelComponents> components(std::move(transitionMatrix), std::move(resultLabeling)); + components.rateTransitions = true; + components.markovianStates = std::move(transitionResult.markovianStates); + components.exitRates = std::move(transitionResult.exitRates); // If given, parse the state rewards file. boost::optional> stateRewards; if (!stateRewardFilename.empty()) { - stateRewards.reset(storm::parser::SparseStateRewardParser::parseSparseStateReward(componets.transitionMatrix.getColumnCount(), stateRewardFilename)); + stateRewards.reset(storm::parser::SparseStateRewardParser::parseSparseStateReward(components.transitionMatrix.getColumnCount(), stateRewardFilename)); } // Only parse transition rewards if a file is given. boost::optional> transitionRewards; if (!transitionRewardFilename.empty()) { - transitionRewards = std::move(storm::parser::NondeterministicSparseTransitionParser::parseNondeterministicTransitionRewards(transitionRewardFilename, componets.transitionMatrix)); + transitionRewards = std::move(storm::parser::NondeterministicSparseTransitionParser::parseNondeterministicTransitionRewards(transitionRewardFilename, components.transitionMatrix)); } if (stateRewards || transitionRewards) { - componets.rewardModels.insert(std::make_pair("", storm::models::sparse::StandardRewardModel(std::move(stateRewards), boost::none, std::move(transitionRewards)))); + components.rewardModels.insert(std::make_pair("", storm::models::sparse::StandardRewardModel(std::move(stateRewards), boost::none, std::move(transitionRewards)))); } // Only parse choice labeling if a file is given. boost::optional choiceLabeling; if (!choiceLabelingFilename.empty()) { - componets.choiceLabeling = storm::parser::SparseItemLabelingParser::parseChoiceLabeling(componets.transitionMatrix.getRowCount(), choiceLabelingFilename, componets.transitionMatrix.getRowGroupIndices()); + components.choiceLabeling = storm::parser::SparseItemLabelingParser::parseChoiceLabeling(components.transitionMatrix.getRowCount(), choiceLabelingFilename, components.transitionMatrix.getRowGroupIndices()); } // generate the Markov Automaton. - return storm::models::sparse::MarkovAutomaton> (std::move(componets)); + return storm::models::sparse::MarkovAutomaton> (std::move(components)); } template class MarkovAutomatonParser; diff --git a/src/storm/parser/MarkovAutomatonParser.h b/src/storm-parsers/parser/MarkovAutomatonParser.h similarity index 96% rename from src/storm/parser/MarkovAutomatonParser.h rename to src/storm-parsers/parser/MarkovAutomatonParser.h index 763ece141..1f2087674 100644 --- a/src/storm/parser/MarkovAutomatonParser.h +++ b/src/storm-parsers/parser/MarkovAutomatonParser.h @@ -2,7 +2,7 @@ #define STORM_PARSER_MARKOVAUTOMATONPARSER_H_ #include "storm/models/sparse/MarkovAutomaton.h" -#include "storm/parser/MarkovAutomatonSparseTransitionParser.h" +#include "storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h" namespace storm { namespace parser { diff --git a/src/storm/parser/MarkovAutomatonSparseTransitionParser.cpp b/src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.cpp similarity index 99% rename from src/storm/parser/MarkovAutomatonSparseTransitionParser.cpp rename to src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.cpp index 25b62a2e2..9acd151b0 100644 --- a/src/storm/parser/MarkovAutomatonSparseTransitionParser.cpp +++ b/src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.cpp @@ -4,7 +4,7 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/FileIoException.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/cstring.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/MarkovAutomatonSparseTransitionParser.h b/src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h similarity index 100% rename from src/storm/parser/MarkovAutomatonSparseTransitionParser.h rename to src/storm-parsers/parser/MarkovAutomatonSparseTransitionParser.h diff --git a/src/storm/parser/NondeterministicModelParser.cpp b/src/storm-parsers/parser/NondeterministicModelParser.cpp similarity index 93% rename from src/storm/parser/NondeterministicModelParser.cpp rename to src/storm-parsers/parser/NondeterministicModelParser.cpp index c107803eb..b26626fb0 100644 --- a/src/storm/parser/NondeterministicModelParser.cpp +++ b/src/storm-parsers/parser/NondeterministicModelParser.cpp @@ -1,13 +1,13 @@ -#include "storm/parser/NondeterministicModelParser.h" +#include "storm-parsers/parser/NondeterministicModelParser.h" #include #include #include "storm/models/sparse/StandardRewardModel.h" -#include "storm/parser/NondeterministicSparseTransitionParser.h" -#include "storm/parser/SparseItemLabelingParser.h" -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/NondeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/NondeterministicModelParser.h b/src/storm-parsers/parser/NondeterministicModelParser.h similarity index 100% rename from src/storm/parser/NondeterministicModelParser.h rename to src/storm-parsers/parser/NondeterministicModelParser.h diff --git a/src/storm/parser/NondeterministicSparseTransitionParser.cpp b/src/storm-parsers/parser/NondeterministicSparseTransitionParser.cpp similarity index 99% rename from src/storm/parser/NondeterministicSparseTransitionParser.cpp rename to src/storm-parsers/parser/NondeterministicSparseTransitionParser.cpp index cb941aec5..56b00070c 100644 --- a/src/storm/parser/NondeterministicSparseTransitionParser.cpp +++ b/src/storm-parsers/parser/NondeterministicSparseTransitionParser.cpp @@ -1,8 +1,8 @@ -#include "storm/parser/NondeterministicSparseTransitionParser.h" +#include "storm-parsers/parser/NondeterministicSparseTransitionParser.h" #include -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/exceptions/FileIoException.h" diff --git a/src/storm/parser/NondeterministicSparseTransitionParser.h b/src/storm-parsers/parser/NondeterministicSparseTransitionParser.h similarity index 100% rename from src/storm/parser/NondeterministicSparseTransitionParser.h rename to src/storm-parsers/parser/NondeterministicSparseTransitionParser.h diff --git a/src/storm/parser/PrismParser.cpp b/src/storm-parsers/parser/PrismParser.cpp similarity index 95% rename from src/storm/parser/PrismParser.cpp rename to src/storm-parsers/parser/PrismParser.cpp index ad275da7d..68d8d77fb 100644 --- a/src/storm/parser/PrismParser.cpp +++ b/src/storm-parsers/parser/PrismParser.cpp @@ -1,4 +1,4 @@ -#include "storm/parser/PrismParser.h" +#include "storm-parsers/parser/PrismParser.h" #include "storm/storage/prism/Compositions.h" @@ -11,7 +11,7 @@ #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/ExpressionParser.h" namespace storm { namespace parser { @@ -37,11 +37,13 @@ namespace storm { } storm::prism::Program PrismParser::parseFromString(std::string const& input, std::string const& filename, bool prismCompatibility) { - PositionIteratorType first(input.begin()); + bool hasByteOrderMark = input.size() >= 3 && input[0] == '\xEF' && input[1] == '\xBB' && input[2] == '\xBF'; + + PositionIteratorType first(hasByteOrderMark ? input.begin() + 3 : input.begin()); PositionIteratorType iter = first; PositionIteratorType last(input.end()); STORM_LOG_ASSERT(first != last, "Illegal input to PRISM parser."); - + // Create empty result; storm::prism::Program result; @@ -49,7 +51,8 @@ namespace storm { storm::parser::PrismParser grammar(filename, first, prismCompatibility); try { // Start first run. - bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + storm::spirit_encoding::space_type space; + bool succeeded = qi::phrase_parse(iter, last, grammar, space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing failed in first pass."); STORM_LOG_DEBUG("First pass of parsing PRISM input finished."); @@ -58,7 +61,7 @@ namespace storm { iter = first; last = PositionIteratorType(input.end()); grammar.moveToSecondRun(); - succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + succeeded = qi::phrase_parse(iter, last, grammar, space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing failed in second pass."); } catch (qi::expectation_failure const& e) { // If the parser expected content different than the one provided, display information about the location of the error. @@ -115,7 +118,7 @@ namespace storm { booleanVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("bool")) > -((qi::lit("init") > expression_[qi::_a = qi::_1]) | qi::attr(manager->boolean(false))) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createBooleanVariable, phoenix::ref(*this), qi::_1, qi::_a)]; booleanVariableDefinition.name("boolean variable definition"); - integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), false)]) > expression_ > qi::lit("..") > expression_ > qi::lit("]")[phoenix::bind(&PrismParser::allowDoubleLiterals, phoenix::ref(*this), true)] > -(qi::lit("init") > expression_[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; + integerVariableDefinition = ((identifier >> qi::lit(":") >> qi::lit("[")) > expression_ > qi::lit("..") > expression_ > qi::lit("]") > -(qi::lit("init") > expression_[qi::_a = qi::_1]) > qi::lit(";"))[qi::_val = phoenix::bind(&PrismParser::createIntegerVariable, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_a)]; integerVariableDefinition.name("integer variable definition"); variableDefinition = (booleanVariableDefinition[phoenix::push_back(qi::_r1, qi::_1)] | integerVariableDefinition[phoenix::push_back(qi::_r2, qi::_1)]); @@ -433,13 +436,32 @@ namespace storm { } storm::prism::Formula PrismParser::createFormula(std::string const& formulaName, storm::expressions::Expression expression) { - // Only register formula in second run. This prevents the parser from accepting formulas that depend on future - // formulas. + // Only register formula in second run. + // This is necessary because the resulting type of the formula is only known in the second run. + // This prevents the parser from accepting formulas that depend on future formulas. if (this->secondRun) { - STORM_LOG_THROW(this->identifiers_.find(formulaName) == nullptr, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Duplicate identifier '" << formulaName << "'."); - this->identifiers_.add(formulaName, expression); + storm::expressions::Variable variable; + try { + if (expression.hasIntegerType()) { + variable = manager->declareIntegerVariable(formulaName); + } else if (expression.hasBooleanType()) { + variable = manager->declareBooleanVariable(formulaName); + } else { + STORM_LOG_ASSERT(expression.hasNumericalType(), "Unexpected type for formula expression of formula " << formulaName); + variable = manager->declareRationalVariable(formulaName); + } + this->identifiers_.add(formulaName, variable.getExpression()); + } catch (storm::exceptions::InvalidArgumentException const& e) { + if (manager->hasVariable(formulaName)) { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": Duplicate identifier '" << formulaName << "'."); + } else { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Parsing error in " << this->getFilename() << ", line " << get_line(qi::_3) << ": illegal identifier '" << formulaName << "'."); + } + } + return storm::prism::Formula(variable, expression, this->getFilename()); + } else { + return storm::prism::Formula(formulaName, expression, this->getFilename()); } - return storm::prism::Formula(formulaName, expression, this->getFilename()); } storm::prism::Label PrismParser::createLabel(std::string const& labelName, storm::expressions::Expression expression) const { diff --git a/src/storm/parser/PrismParser.h b/src/storm-parsers/parser/PrismParser.h similarity index 99% rename from src/storm/parser/PrismParser.h rename to src/storm-parsers/parser/PrismParser.h index a1ae1a4f7..a5367d2c6 100644 --- a/src/storm/parser/PrismParser.h +++ b/src/storm-parsers/parser/PrismParser.h @@ -6,8 +6,8 @@ #include #include -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" #include "storm/storage/prism/Program.h" #include "storm/storage/expressions/Expression.h" diff --git a/src/storm/parser/ReadValues.h b/src/storm-parsers/parser/ReadValues.h similarity index 100% rename from src/storm/parser/ReadValues.h rename to src/storm-parsers/parser/ReadValues.h diff --git a/src/storm/parser/SparseChoiceLabelingParser.cpp b/src/storm-parsers/parser/SparseChoiceLabelingParser.cpp similarity index 97% rename from src/storm/parser/SparseChoiceLabelingParser.cpp rename to src/storm-parsers/parser/SparseChoiceLabelingParser.cpp index b51e8b97c..452045319 100644 --- a/src/storm/parser/SparseChoiceLabelingParser.cpp +++ b/src/storm-parsers/parser/SparseChoiceLabelingParser.cpp @@ -1,10 +1,10 @@ -#include "storm/parser/SparseChoiceLabelingParser.h" +#include "storm-parsers/parser/SparseChoiceLabelingParser.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" #include "storm/exceptions/FileIoException.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/cstring.h" namespace storm { diff --git a/src/storm/parser/SparseChoiceLabelingParser.h b/src/storm-parsers/parser/SparseChoiceLabelingParser.h similarity index 100% rename from src/storm/parser/SparseChoiceLabelingParser.h rename to src/storm-parsers/parser/SparseChoiceLabelingParser.h diff --git a/src/storm/parser/SparseItemLabelingParser.cpp b/src/storm-parsers/parser/SparseItemLabelingParser.cpp similarity index 99% rename from src/storm/parser/SparseItemLabelingParser.cpp rename to src/storm-parsers/parser/SparseItemLabelingParser.cpp index 2e98e4673..9e5e7b154 100644 --- a/src/storm/parser/SparseItemLabelingParser.cpp +++ b/src/storm-parsers/parser/SparseItemLabelingParser.cpp @@ -1,11 +1,11 @@ -#include "storm/parser/SparseItemLabelingParser.h" +#include "storm-parsers/parser/SparseItemLabelingParser.h" #include #include #include #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm/parser/SparseItemLabelingParser.h b/src/storm-parsers/parser/SparseItemLabelingParser.h similarity index 98% rename from src/storm/parser/SparseItemLabelingParser.h rename to src/storm-parsers/parser/SparseItemLabelingParser.h index 4b901ab82..97c30cc25 100644 --- a/src/storm/parser/SparseItemLabelingParser.h +++ b/src/storm-parsers/parser/SparseItemLabelingParser.h @@ -4,7 +4,7 @@ #include #include -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/models/sparse/StateLabeling.h" #include "storm/models/sparse/ChoiceLabeling.h" diff --git a/src/storm/parser/SparseStateRewardParser.cpp b/src/storm-parsers/parser/SparseStateRewardParser.cpp similarity index 96% rename from src/storm/parser/SparseStateRewardParser.cpp rename to src/storm-parsers/parser/SparseStateRewardParser.cpp index f42b4cbe8..acb67e9fb 100644 --- a/src/storm/parser/SparseStateRewardParser.cpp +++ b/src/storm-parsers/parser/SparseStateRewardParser.cpp @@ -1,11 +1,11 @@ #include -#include "storm/parser/SparseStateRewardParser.h" +#include "storm-parsers/parser/SparseStateRewardParser.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/OutOfRangeException.h" #include "storm/exceptions/FileIoException.h" #include "storm/utility/cstring.h" -#include "storm/parser/MappedFile.h" +#include "storm-parsers/parser/MappedFile.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" diff --git a/src/storm/parser/SparseStateRewardParser.h b/src/storm-parsers/parser/SparseStateRewardParser.h similarity index 100% rename from src/storm/parser/SparseStateRewardParser.h rename to src/storm-parsers/parser/SparseStateRewardParser.h diff --git a/src/storm/parser/SpiritErrorHandler.h b/src/storm-parsers/parser/SpiritErrorHandler.h similarity index 95% rename from src/storm/parser/SpiritErrorHandler.h rename to src/storm-parsers/parser/SpiritErrorHandler.h index 34280e422..ab64008bc 100644 --- a/src/storm/parser/SpiritErrorHandler.h +++ b/src/storm-parsers/parser/SpiritErrorHandler.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" diff --git a/src/storm/parser/SpiritParserDefinitions.h b/src/storm-parsers/parser/SpiritParserDefinitions.h similarity index 76% rename from src/storm/parser/SpiritParserDefinitions.h rename to src/storm-parsers/parser/SpiritParserDefinitions.h index 412a6bc37..d48d7a7a6 100644 --- a/src/storm/parser/SpiritParserDefinitions.h +++ b/src/storm-parsers/parser/SpiritParserDefinitions.h @@ -6,6 +6,7 @@ // Include boost spirit. #define BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_UNICODE #include #include #include @@ -21,6 +22,10 @@ typedef std::string::const_iterator BaseIteratorType; typedef boost::spirit::line_pos_iterator PositionIteratorType; typedef PositionIteratorType Iterator; -typedef BOOST_TYPEOF(boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi)) Skipper; +namespace storm { + namespace spirit_encoding = boost::spirit::unicode; +} + +typedef BOOST_TYPEOF(storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi)) Skipper; #endif /* STORM_PARSER_SPIRITPARSERDEFINITIONS_H_ */ diff --git a/src/storm-parsers/parser/ValueParser.cpp b/src/storm-parsers/parser/ValueParser.cpp new file mode 100644 index 000000000..61cd5c0ac --- /dev/null +++ b/src/storm-parsers/parser/ValueParser.cpp @@ -0,0 +1,38 @@ +#include "storm-parsers/parser/ValueParser.h" + +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace parser { + + template + void ValueParser::addParameter(std::string const& parameter) { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); + } + + template<> + void ValueParser::addParameter(std::string const& parameter) { + storm::expressions::Variable var = manager->declareRationalVariable(parameter); + identifierMapping.emplace(var.getName(), var); + parser.setIdentifierMapping(identifierMapping); + STORM_LOG_TRACE("Added parameter: " << var.getName()); + } + + template<> + double ValueParser::parseValue(std::string const& value) const { + return NumberParser::parse(value); + } + + template<> + storm::RationalFunction ValueParser::parseValue(std::string const& value) const { + storm::RationalFunction rationalFunction = evaluator.asRational(parser.parseFromString(value)); + STORM_LOG_TRACE("Parsed expression: " << rationalFunction); + return rationalFunction; + } + + // Template instantiations. + template class ValueParser; + template class ValueParser; + + } // namespace parser +} // namespace storm diff --git a/src/storm-parsers/parser/ValueParser.h b/src/storm-parsers/parser/ValueParser.h new file mode 100644 index 000000000..626857a3e --- /dev/null +++ b/src/storm-parsers/parser/ValueParser.h @@ -0,0 +1,71 @@ +#ifndef STORM_PARSER_VALUEPARSER_H_ +#define STORM_PARSER_VALUEPARSER_H_ + +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm-parsers/parser/ExpressionParser.h" +#include "storm/storage/expressions/ExpressionEvaluator.h" +#include "storm/exceptions/WrongFormatException.h" + +namespace storm { + namespace parser { + /*! + * Parser for values according to their ValueType. + */ + template + class ValueParser { + public: + + /*! + * Constructor. + */ + ValueParser() : manager(new storm::expressions::ExpressionManager()), parser(*manager), evaluator(*manager) { + } + + /*! + * Parse ValueType from string. + * + * @param value String containing the value. + * + * @return ValueType + */ + ValueType parseValue(std::string const& value) const; + + /*! + * Add declaration of parameter. + * + * @param parameter New parameter. + */ + void addParameter(std::string const& parameter); + + private: + + std::shared_ptr manager; + storm::parser::ExpressionParser parser; + storm::expressions::ExpressionEvaluator evaluator; + std::unordered_map identifierMapping; + }; + + template + class NumberParser { + public: + /*! + * Parse number from string. + * + * @param value String containing the value. + * + * @return NumberType. + */ + static NumberType parse(std::string const& value) { + try { + return boost::lexical_cast(value); + } + catch(boost::bad_lexical_cast &) { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Could not parse value '" << value << "' into " << typeid(NumberType).name() << "."); + } + } + }; + + } // namespace parser +} // namespace storm + +#endif /* STORM_PARSER_VALUEPARSER_H_ */ diff --git a/src/storm-pgcl-cli/CMakeLists.txt b/src/storm-pgcl-cli/CMakeLists.txt index 4f2799d4d..506772fd9 100644 --- a/src/storm-pgcl-cli/CMakeLists.txt +++ b/src/storm-pgcl-cli/CMakeLists.txt @@ -5,4 +5,4 @@ set_target_properties(storm-pgcl-cli PROPERTIES OUTPUT_NAME "storm-pgcl") add_dependencies(binaries storm-pgcl-cli) # installation -install(TARGETS storm-pgcl-cli RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) \ No newline at end of file +install(TARGETS storm-pgcl-cli EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pgcl-cli/storm-pgcl.cpp b/src/storm-pgcl-cli/storm-pgcl.cpp index bfbb6cad4..30a72a09b 100644 --- a/src/storm-pgcl-cli/storm-pgcl.cpp +++ b/src/storm-pgcl-cli/storm-pgcl.cpp @@ -18,7 +18,8 @@ #include "storm-pgcl/settings/modules/PGCLSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" +#include "storm-conv/settings/modules/JaniExportSettings.h" +#include "storm-conv/api/storm-conv.h" #include "storm/utility/file.h" @@ -38,11 +39,14 @@ void initializeSettings() { } void handleJani(storm::jani::Model& model) { - if (!storm::settings::getModule().isJaniFileSet()) { - // For now, we have to have a jani file - storm::jani::JsonExporter::toStream(model, {}, std::cout); + auto const& jani = storm::settings::getModule(); + storm::converter::JaniConversionOptions options(jani); + std::vector properties; + storm::api::transformJani(model, properties, options); + if (storm::settings::getModule().isToJaniSet()) { + storm::api::exportJaniToFile(model, {}, storm::settings::getModule().getWriteToJaniFilename(), jani.isCompactJsonSet()); } else { - storm::jani::JsonExporter::toFile(model, {}, storm::settings::getModule().getJaniFilename()); + storm::api::printJaniToStream(model, {}, std::cout); } } diff --git a/src/storm-pgcl/CMakeLists.txt b/src/storm-pgcl/CMakeLists.txt index e20a99483..1adf442c6 100644 --- a/src/storm-pgcl/CMakeLists.txt +++ b/src/storm-pgcl/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB_RECURSE STORM_PGCL_HEADERS ${PROJECT_SOURCE_DIR}/src/storm-pgcl/*/*.h) # Create storm-pgcl. add_library(storm-pgcl SHARED ${STORM_PGCL_SOURCES} ${STORM_PGCL_HEADERS}) -target_link_libraries(storm-pgcl storm) +target_link_libraries(storm-pgcl storm storm-parsers storm-conv) # installation -install(TARGETS storm-pgcl RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) \ No newline at end of file +install(TARGETS storm-pgcl EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) diff --git a/src/storm-pgcl/builder/JaniProgramGraphBuilder.cpp b/src/storm-pgcl/builder/JaniProgramGraphBuilder.cpp index 0db2787bb..bcb569917 100644 --- a/src/storm-pgcl/builder/JaniProgramGraphBuilder.cpp +++ b/src/storm-pgcl/builder/JaniProgramGraphBuilder.cpp @@ -53,9 +53,9 @@ namespace storm { if(isRewardVariable(assignment.first)) { std::unordered_map eval; eval.emplace((variables.at(assignment.first))->getExpressionVariable(), expManager->integer(0)); - vec.emplace_back(*(variables.at(assignment.first)), assignment.second.substitute(eval).simplify(), level); + vec.emplace_back(storm::jani::LValue(*(variables.at(assignment.first))), assignment.second.substitute(eval).simplify(), level); } else { - vec.emplace_back(*(variables.at(assignment.first)), assignment.second, level); + vec.emplace_back(storm::jani::LValue(*(variables.at(assignment.first))), assignment.second, level); } } ++level; @@ -67,7 +67,7 @@ namespace storm { storm::ppg::ProbabilisticProgramAction const& act = static_cast(edge.getAction()); std::vector> vec; for(auto const& assign : act) { - storm::jani::Assignment assignment(automaton.getVariables().getVariable(act.getVariableName()), expManager->integer(assign.value), 0); + storm::jani::Assignment assignment(storm::jani::LValue(automaton.getVariables().getVariable(act.getVariableName())), expManager->integer(assign.value), 0); templateEdge.addDestination(storm::jani::TemplateEdgeDestination(storm::jani::OrderedAssignments(assignment))); vec.emplace_back(janiLocId.at(edge.getTargetId()), assign.probability); } diff --git a/src/storm-pgcl/builder/JaniProgramGraphBuilder.h b/src/storm-pgcl/builder/JaniProgramGraphBuilder.h index ad5feb8a4..ba3f1bd4e 100644 --- a/src/storm-pgcl/builder/JaniProgramGraphBuilder.h +++ b/src/storm-pgcl/builder/JaniProgramGraphBuilder.h @@ -76,6 +76,8 @@ namespace storm { addEdges(mainAutomaton); model->addAutomaton(mainAutomaton); model->setStandardSystemComposition(); + model->getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + model->finalize(); return model; } @@ -140,7 +142,7 @@ namespace storm { storm::jani::Location janiLoc(janiLocationName(it->second.id())); for(auto const& label : programGraph.getLabels(it->second.id())) { assert(labelVars.count(label) > 0); - janiLoc.addTransientAssignment(storm::jani::Assignment(*(labelVars.at(label)), expManager->boolean(true))); + janiLoc.addTransientAssignment(storm::jani::Assignment(storm::jani::LValue(*(labelVars.at(label))), expManager->boolean(true))); } result[it->second.id()] = automaton.addLocation(janiLoc); if (it->second.isInitial()) { diff --git a/src/storm-pgcl/parser/PgclParser.cpp b/src/storm-pgcl/parser/PgclParser.cpp index 6ecde3054..2afe737be 100755 --- a/src/storm-pgcl/parser/PgclParser.cpp +++ b/src/storm-pgcl/parser/PgclParser.cpp @@ -40,7 +40,7 @@ namespace storm { storm::parser::PgclParser grammar(filename, first); try { // Start the parsing run. - bool succeeded = qi::phrase_parse(iter, last, grammar, boost::spirit::ascii::space | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); + bool succeeded = qi::phrase_parse(iter, last, grammar, storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)) >> (qi::eol | qi::eoi), result); STORM_LOG_THROW(succeeded, storm::exceptions::WrongFormatException, "Parsing of PGCL program failed."); STORM_LOG_DEBUG("Parse of PGCL program finished."); } catch(qi::expectation_failure const& e) { diff --git a/src/storm-pgcl/parser/PgclParser.h b/src/storm-pgcl/parser/PgclParser.h index dfd75a810..0e31094b9 100755 --- a/src/storm-pgcl/parser/PgclParser.h +++ b/src/storm-pgcl/parser/PgclParser.h @@ -5,9 +5,9 @@ #include #include // Includes files for building and parsing the PGCL program -#include "storm/parser/SpiritParserDefinitions.h" -#include "storm/parser/SpiritErrorHandler.h" -#include "storm/parser/ExpressionParser.h" +#include "storm-parsers/parser/SpiritParserDefinitions.h" +#include "storm-parsers/parser/SpiritErrorHandler.h" +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/Expression.h" #include "storm-pgcl/storage/pgcl/PgclProgram.h" diff --git a/src/storm-pgcl/settings/modules/PGCLSettings.cpp b/src/storm-pgcl/settings/modules/PGCLSettings.cpp index a70b87f6f..c466943aa 100644 --- a/src/storm-pgcl/settings/modules/PGCLSettings.cpp +++ b/src/storm-pgcl/settings/modules/PGCLSettings.cpp @@ -26,7 +26,7 @@ namespace storm { PGCLSettings::PGCLSettings() : ModuleSettings(moduleName) { this->addOption(storm::settings::OptionBuilder(moduleName, pgclFileOptionName, false, "Parses the pgcl program.").setShortName(pgclFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createExistingFileValidator()).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, pgclToJaniOptionName, false, "Transform to JANI.").setShortName(pgclToJaniOptionShortName).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, pgclToJaniOptionName, false, "Transform to JANI.").setShortName(pgclToJaniOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").addValidatorString(ArgumentValidatorFactory::createWritableFileValidator()).build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, programGraphToDotOptionName, false, "Destination for the program graph dot output.").setShortName(programGraphToDotShortOptionName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, programVariableRestrictionsOptionName, false, "Restrictions of program variables").setShortName(programVariableRestrictionShortOptionName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("description", "description of the variable restrictions").build()).build()); } @@ -43,6 +43,11 @@ namespace storm { return this->getOption(pgclToJaniOptionName).getHasOptionBeenSet(); } + std::string PGCLSettings::getWriteToJaniFilename() const { + return this->getOption(pgclToJaniOptionName).getArgumentByName("filename").getValueAsString(); + } + + bool PGCLSettings::isProgramGraphToDotSet() const { return this->getOption(programGraphToDotOptionName).getHasOptionBeenSet(); } diff --git a/src/storm-pgcl/settings/modules/PGCLSettings.h b/src/storm-pgcl/settings/modules/PGCLSettings.h index 29e689366..8a2edf5eb 100644 --- a/src/storm-pgcl/settings/modules/PGCLSettings.h +++ b/src/storm-pgcl/settings/modules/PGCLSettings.h @@ -29,6 +29,11 @@ namespace storm { */ bool isToJaniSet() const; + /** + * returns the file name where jani output should be stored. + */ + std::string getWriteToJaniFilename() const; + /** * Whether the program graph should be drawn (dot output) */ diff --git a/src/storm-pomdp-cli/storm-pomdp.cpp b/src/storm-pomdp-cli/storm-pomdp.cpp index 0a223ad63..5d374e679 100644 --- a/src/storm-pomdp-cli/storm-pomdp.cpp +++ b/src/storm-pomdp-cli/storm-pomdp.cpp @@ -6,7 +6,6 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/modules/CuddSettings.h" #include "storm/settings/modules/SylvanSettings.h" #include "storm/settings/modules/EigenEquationSolverSettings.h" @@ -19,11 +18,9 @@ #include "storm/settings/modules/GlpkSettings.h" #include "storm/settings/modules/GurobiSettings.h" #include "storm/settings/modules/Smt2SmtSolverSettings.h" -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/AbstractionSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/BuildSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" @@ -64,10 +61,7 @@ void initializeSettings() { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); - storm::settings::addModule(); diff --git a/src/storm/CMakeLists.txt b/src/storm/CMakeLists.txt index 0cf8d3183..dcd1bb9f9 100644 --- a/src/storm/CMakeLists.txt +++ b/src/storm/CMakeLists.txt @@ -28,8 +28,6 @@ if (ADDITIONAL_LINK_DIRS) link_directories(${ADDITIONAL_LINK_DIRS}) endif(ADDITIONAL_LINK_DIRS) -# Disable Debug compiler flags for PrismParser to lessen memory consumption during compilation -SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/storm/parser/PrismParser.cpp PROPERTIES COMPILE_FLAGS -g0) ############################################################################### ## @@ -72,7 +70,7 @@ add_dependencies(storm copy_resources_headers) add_dependencies(binaries storm-main) # installation -install(TARGETS storm RUNTIME DESTINATION bin LIBRARY DESTINATION lib) -install(TARGETS storm-main RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) +install(TARGETS storm EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib) +install(TARGETS storm-main EXPORT storm_Targets RUNTIME DESTINATION bin LIBRARY DESTINATION lib OPTIONAL) install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include/storm FILES_MATCHING PATTERN "*.h") diff --git a/src/storm/abstraction/AbstractionInformation.cpp b/src/storm/abstraction/AbstractionInformation.cpp index 5e25b5530..23fb06985 100644 --- a/src/storm/abstraction/AbstractionInformation.cpp +++ b/src/storm/abstraction/AbstractionInformation.cpp @@ -14,7 +14,7 @@ namespace storm { namespace abstraction { template - AbstractionInformation::AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, std::shared_ptr> ddManager) : expressionManager(expressionManager), equivalenceChecker(std::move(smtSolver)), abstractedVariables(abstractedVariables), ddManager(ddManager), allPredicateIdentities(ddManager->getBddOne()), allLocationIdentities(ddManager->getBddOne()), expressionToBddMap() { + AbstractionInformation::AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, AbstractionInformationOptions const& options, std::shared_ptr> ddManager) : expressionManager(expressionManager), equivalenceChecker(std::move(smtSolver)), abstractedVariables(abstractedVariables), constraints(options.constraints), ddManager(ddManager), allPredicateIdentities(ddManager->getBddOne()), allLocationIdentities(ddManager->getBddOne()), expressionToBddMap() { // Intentionally left empty. } @@ -138,6 +138,23 @@ namespace storm { return result; } + template + std::vector AbstractionInformation::getPredicatesExcludingBottom(storm::storage::BitVector const& predicateValuation) const { + uint64_t offset = 1 + this->getNumberOfDdSourceLocationVariables(); + STORM_LOG_ASSERT(predicateValuation.size() == this->getNumberOfPredicates() + offset, "Size of predicate valuation does not match number of predicates."); + + std::vector result; + for (uint64_t index = 0; index < this->getNumberOfPredicates(); ++index) { + if (predicateValuation[index + offset]) { + result.push_back(this->getPredicateByIndex(index)); + } else { + result.push_back(!this->getPredicateByIndex(index)); + } + } + + return result; + } + template storm::expressions::Expression const& AbstractionInformation::getPredicateByIndex(uint_fast64_t index) const { return predicates[index]; @@ -446,7 +463,7 @@ namespace storm { template template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const { - std::map> result; + std::map> result; storm::dd::Add lowerChoiceAsAdd = choice.template toAdd(); for (auto const& successorValuePair : lowerChoiceAsAdd) { @@ -465,6 +482,19 @@ namespace storm { return result; } + template + template + std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const { + std::vector> splitChoices = choices.split(player2Variables); + + std::vector>> result; + for (auto const& choice : splitChoices) { + result.emplace_back(this->decodeChoiceToUpdateSuccessorMapping(choice)); + } + + return result; + } + template std::tuple AbstractionInformation::decodeStatePlayer1ChoiceAndUpdate(storm::dd::Bdd const& stateChoiceAndUpdate) const { STORM_LOG_ASSERT(stateChoiceAndUpdate.getNonZeroCount() == 1, "Wrong number of non-zero entries."); @@ -523,7 +553,7 @@ namespace storm { } template - storm::expressions::Variable const& AbstractionInformation::getDdLocationVariable(storm::expressions::Variable const& locationExpressionVariable, bool source) { + storm::expressions::Variable const& AbstractionInformation::getDdLocationMetaVariable(storm::expressions::Variable const& locationExpressionVariable, bool source) { auto const& metaVariablePair = locationExpressionToDdVariableMap.at(locationExpressionVariable); if (source) { return metaVariablePair.first; @@ -532,6 +562,15 @@ namespace storm { } } + template + uint64_t AbstractionInformation::getNumberOfDdSourceLocationVariables() const { + uint64_t result = 0; + for (auto const& locationVariableToMetaVariablePair : locationExpressionToDdVariableMap) { + result += ddManager->getMetaVariable(locationVariableToMetaVariablePair.second.first).getNumberOfDdVariables(); + } + return result; + } + template std::set const& AbstractionInformation::getLocationExpressionVariables() const { return locationExpressionVariables; @@ -547,5 +586,10 @@ namespace storm { template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; + template std::map> AbstractionInformation::decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; + + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; + template std::vector>> AbstractionInformation::decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; } } diff --git a/src/storm/abstraction/AbstractionInformation.h b/src/storm/abstraction/AbstractionInformation.h index 093342993..a6eb1f9c5 100644 --- a/src/storm/abstraction/AbstractionInformation.h +++ b/src/storm/abstraction/AbstractionInformation.h @@ -27,6 +27,16 @@ namespace storm { namespace abstraction { + struct AbstractionInformationOptions { + AbstractionInformationOptions() = default; + + AbstractionInformationOptions(std::vector const& constraints) : constraints(constraints) { + // Intentionally left empty. + } + + std::vector constraints; + }; + template class AbstractionInformation { public: @@ -38,7 +48,7 @@ namespace storm { * @param smtSolver An SMT solver that is used to detect equivalent predicates. * @param ddManager The manager responsible for the DDs. */ - AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, std::shared_ptr> ddManager = std::make_shared>()); + AbstractionInformation(storm::expressions::ExpressionManager& expressionManager, std::set const& abstractedVariables, std::unique_ptr&& smtSolver, AbstractionInformationOptions const& options = AbstractionInformationOptions(), std::shared_ptr> ddManager = std::make_shared>()); /*! * Adds the given variable. @@ -139,7 +149,13 @@ namespace storm { * Retrieves a list of expression that corresponds to the given predicate valuation. */ std::vector getPredicates(storm::storage::BitVector const& predicateValuation) const; - + + /*! + * Retrieves a list of expression that corresponds to the given predicate valuation that mentions all of the + * predicates' truth values *and* the value of the bottom variable (at the first index). + */ + std::vector getPredicatesExcludingBottom(storm::storage::BitVector const& predicateValuation) const; + /*! * Retrieves the predicate with the given index. * @@ -450,6 +466,13 @@ namespace storm { template std::map> decodeChoiceToUpdateSuccessorMapping(storm::dd::Bdd const& choice) const; + /*! + * Decodes the choices in the form of BDD over the destination variables where the choices are distinguished + * by player 2 variables. + */ + template + std::vector>> decodeChoicesToUpdateSuccessorMapping(std::set const& player2Variables, storm::dd::Bdd const& choices) const; + /*! * Decodes the given BDD (over source, player 1 and aux variables) into a bit vector indicating the truth * values of the predicates in the state and the choice/update indices. @@ -479,7 +502,12 @@ namespace storm { /*! * Retrieves the DD variable for the given location expression variable. */ - storm::expressions::Variable const& getDdLocationVariable(storm::expressions::Variable const& locationExpressionVariable, bool source); + storm::expressions::Variable const& getDdLocationMetaVariable(storm::expressions::Variable const& locationExpressionVariable, bool source); + + /*! + * Retrieves the number of DD variables associated with the source location variables. + */ + uint64_t getNumberOfDdSourceLocationVariables() const; /*! * Retrieves the source location variables. diff --git a/src/storm/abstraction/ExplicitGameStrategy.cpp b/src/storm/abstraction/ExplicitGameStrategy.cpp new file mode 100644 index 000000000..4445d697f --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategy.cpp @@ -0,0 +1,65 @@ +#include "storm/abstraction/ExplicitGameStrategy.h" + +#include +#include + +namespace storm { + namespace abstraction { + + const uint64_t ExplicitGameStrategy::UNDEFINED = std::numeric_limits::max(); + + ExplicitGameStrategy::ExplicitGameStrategy(uint64_t numberOfStates) : choices(numberOfStates, UNDEFINED) { + // Intentionally left empty. + } + + ExplicitGameStrategy::ExplicitGameStrategy(std::vector&& choices) : choices(std::move(choices)) { + // Intentionally left empty. + } + + uint64_t ExplicitGameStrategy::getNumberOfStates() const { + return choices.size(); + } + + uint64_t ExplicitGameStrategy::getChoice(uint64_t state) const { + return choices[state]; + } + + void ExplicitGameStrategy::setChoice(uint64_t state, uint64_t choice) { + choices[state] = choice; + } + + bool ExplicitGameStrategy::hasDefinedChoice(uint64_t state) const { + return choices[state] != UNDEFINED; + } + + void ExplicitGameStrategy::undefineAll() { + for (auto& e : choices) { + e = UNDEFINED; + } + } + + uint64_t ExplicitGameStrategy::getNumberOfUndefinedStates() const { + return std::count_if(choices.begin(), choices.end(), [] (uint64_t choice) { return choice == UNDEFINED; }); + } + + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategy const& strategy) { + std::vector undefinedStates; + for (uint64_t state = 0; state < strategy.getNumberOfStates(); ++state) { + uint64_t choice = strategy.getChoice(state); + if (choice == ExplicitGameStrategy::UNDEFINED) { + undefinedStates.emplace_back(state); + } else { + out << state << " -> " << choice << std::endl; + } + } + out << "undefined states: "; + for (auto state : undefinedStates) { + out << state << ", "; + } + out << std::endl; + + return out; + } + + } +} diff --git a/src/storm/abstraction/ExplicitGameStrategy.h b/src/storm/abstraction/ExplicitGameStrategy.h new file mode 100644 index 000000000..af96a1f69 --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategy.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +namespace storm { + namespace abstraction { + + class ExplicitGameStrategy { + public: + static const uint64_t UNDEFINED; + + ExplicitGameStrategy(uint64_t numberOfStates); + ExplicitGameStrategy(std::vector&& choices); + + uint64_t getNumberOfStates() const; + uint64_t getChoice(uint64_t state) const; + void setChoice(uint64_t state, uint64_t choice); + bool hasDefinedChoice(uint64_t state) const; + void undefineAll(); + + uint64_t getNumberOfUndefinedStates() const; + + private: + std::vector choices; + }; + + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategy const& strategy); + + } +} diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.cpp b/src/storm/abstraction/ExplicitGameStrategyPair.cpp new file mode 100644 index 000000000..eed00f455 --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategyPair.cpp @@ -0,0 +1,45 @@ +#include "storm/abstraction/ExplicitGameStrategyPair.h" + +namespace storm { + namespace abstraction { + + ExplicitGameStrategyPair::ExplicitGameStrategyPair(uint64_t numberOfPlayer1States, uint64_t numberOfPlayer2States) : player1Strategy(numberOfPlayer1States), player2Strategy(numberOfPlayer2States) { + // Intentionally left empty. + } + + ExplicitGameStrategyPair::ExplicitGameStrategyPair(ExplicitGameStrategy&& player1Strategy, ExplicitGameStrategy&& player2Strategy) : player1Strategy(std::move(player1Strategy)), player2Strategy(std::move(player2Strategy)) { + // Intentionally left empty. + } + + ExplicitGameStrategy& ExplicitGameStrategyPair::getPlayer1Strategy() { + return player1Strategy; + } + + ExplicitGameStrategy const& ExplicitGameStrategyPair::getPlayer1Strategy() const { + return player1Strategy; + } + + ExplicitGameStrategy& ExplicitGameStrategyPair::getPlayer2Strategy() { + return player2Strategy; + } + + ExplicitGameStrategy const& ExplicitGameStrategyPair::getPlayer2Strategy() const { + return player2Strategy; + } + + uint64_t ExplicitGameStrategyPair::getNumberOfUndefinedPlayer1States() const { + return player1Strategy.getNumberOfUndefinedStates(); + } + + uint64_t ExplicitGameStrategyPair::getNumberOfUndefinedPlayer2States() const { + return player2Strategy.getNumberOfUndefinedStates(); + } + + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategyPair const& strategyPair) { + out << "player 1 strategy: " << std::endl << strategyPair.getPlayer1Strategy() << std::endl; + out << "player 2 strategy: " << std::endl << strategyPair.getPlayer2Strategy() << std::endl; + return out; + } + + } +} diff --git a/src/storm/abstraction/ExplicitGameStrategyPair.h b/src/storm/abstraction/ExplicitGameStrategyPair.h new file mode 100644 index 000000000..b7428d987 --- /dev/null +++ b/src/storm/abstraction/ExplicitGameStrategyPair.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "storm/abstraction/ExplicitGameStrategy.h" + +namespace storm { + namespace abstraction { + + class ExplicitGameStrategyPair { + public: + ExplicitGameStrategyPair(uint64_t numberOfPlayer1States, uint64_t numberOfPlayer2States); + ExplicitGameStrategyPair(ExplicitGameStrategy&& player1Strategy, ExplicitGameStrategy&& player2Strategy); + + ExplicitGameStrategy& getPlayer1Strategy(); + ExplicitGameStrategy const& getPlayer1Strategy() const; + ExplicitGameStrategy& getPlayer2Strategy(); + ExplicitGameStrategy const& getPlayer2Strategy() const; + + uint64_t getNumberOfUndefinedPlayer1States() const; + uint64_t getNumberOfUndefinedPlayer2States() const; + + private: + ExplicitGameStrategy player1Strategy; + ExplicitGameStrategy player2Strategy; + }; + + std::ostream& operator<<(std::ostream& out, ExplicitGameStrategyPair const& strategyPair); + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeGameResult.cpp b/src/storm/abstraction/ExplicitQualitativeGameResult.cpp new file mode 100644 index 000000000..1a903249d --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResult.cpp @@ -0,0 +1,15 @@ +#include "storm/abstraction/ExplicitQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + ExplicitQualitativeGameResult::ExplicitQualitativeGameResult(storm::utility::graph::ExplicitGameProb01Result const& prob01Result) : storm::utility::graph::ExplicitGameProb01Result(prob01Result) { + // Intentionally left empty. + } + + storm::storage::BitVector const& ExplicitQualitativeGameResult::getStates() const { + return this->getPlayer1States(); + } + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeGameResult.h b/src/storm/abstraction/ExplicitQualitativeGameResult.h new file mode 100644 index 000000000..45b97964a --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResult.h @@ -0,0 +1,20 @@ +#pragma once + +#include "storm/utility/graph.h" +#include "storm/abstraction/ExplicitQualitativeResult.h" + +namespace storm { + namespace abstraction { + + class ExplicitQualitativeGameResult : public storm::utility::graph::ExplicitGameProb01Result, public ExplicitQualitativeResult { + public: + ExplicitQualitativeGameResult() = default; + + ExplicitQualitativeGameResult(storm::utility::graph::ExplicitGameProb01Result const& prob01Result); + + virtual storm::storage::BitVector const& getStates() const override; + }; + + } +} + diff --git a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp new file mode 100644 index 000000000..7a5456bd5 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.cpp @@ -0,0 +1,40 @@ +#include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" + +namespace storm { + namespace abstraction { + + ExplicitQualitativeGameResult const& ExplicitQualitativeGameResultMinMax::getProb0(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + ExplicitQualitativeGameResult const& ExplicitQualitativeGameResultMinMax::getProb1(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + + ExplicitQualitativeGameResult& ExplicitQualitativeGameResultMinMax::getProb0(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + ExplicitQualitativeGameResult& ExplicitQualitativeGameResultMinMax::getProb1(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + } +} + + diff --git a/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h new file mode 100644 index 000000000..5612ac9e7 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeGameResultMinMax.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/abstraction/ExplicitQualitativeResultMinMax.h" +#include "storm/abstraction/ExplicitQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + class ExplicitQualitativeGameResultMinMax : public ExplicitQualitativeResultMinMax { + public: + ExplicitQualitativeGameResultMinMax() = default; + + virtual ExplicitQualitativeGameResult const& getProb0(storm::OptimizationDirection const& dir) const override; + virtual ExplicitQualitativeGameResult const& getProb1(storm::OptimizationDirection const& dir) const override; + virtual ExplicitQualitativeGameResult& getProb0(storm::OptimizationDirection const& dir) override; + virtual ExplicitQualitativeGameResult& getProb1(storm::OptimizationDirection const& dir) override; + + ExplicitQualitativeGameResult prob0Min; + ExplicitQualitativeGameResult prob1Min; + ExplicitQualitativeGameResult prob0Max; + ExplicitQualitativeGameResult prob1Max; + }; + + } +} + diff --git a/src/storm/abstraction/ExplicitQualitativeResult.cpp b/src/storm/abstraction/ExplicitQualitativeResult.cpp new file mode 100644 index 000000000..b1237350e --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResult.cpp @@ -0,0 +1,17 @@ +#include "storm/abstraction/ExplicitQualitativeResult.h" + +#include "storm/abstraction/ExplicitQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + ExplicitQualitativeGameResult& ExplicitQualitativeResult::asExplicitQualitativeGameResult() { + return static_cast(*this); + } + + ExplicitQualitativeGameResult const& ExplicitQualitativeResult::asExplicitQualitativeGameResult() const { + return static_cast(*this); + } + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeResult.h b/src/storm/abstraction/ExplicitQualitativeResult.h new file mode 100644 index 000000000..d275fe91c --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResult.h @@ -0,0 +1,30 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/QualitativeResult.h" + +namespace storm { + namespace storage { + class BitVector; + } + + namespace abstraction { + + class ExplicitQualitativeGameResult; + + class ExplicitQualitativeResult : public QualitativeResult { + public: + virtual ~ExplicitQualitativeResult() = default; + + ExplicitQualitativeGameResult& asExplicitQualitativeGameResult(); + ExplicitQualitativeGameResult const& asExplicitQualitativeGameResult() const; + + virtual storm::storage::BitVector const& getStates() const = 0; + }; + + } +} + + + diff --git a/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp new file mode 100644 index 000000000..382a435f6 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResultMinMax.cpp @@ -0,0 +1,45 @@ +#include "storm/abstraction/ExplicitQualitativeResultMinMax.h" + +#include "storm/abstraction/ExplicitQualitativeResult.h" + +namespace storm { + namespace abstraction { + + bool ExplicitQualitativeResultMinMax::isExplicit() const { + return true; + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb0Min() const { + return getProb0(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb1Min() const { + return getProb1(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb0Max() const { + return getProb0(storm::OptimizationDirection::Maximize); + } + + ExplicitQualitativeResult const& ExplicitQualitativeResultMinMax::getProb1Max() const { + return getProb1(storm::OptimizationDirection::Maximize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb0Min() { + return getProb0(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb1Min() { + return getProb1(storm::OptimizationDirection::Minimize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb0Max() { + return getProb0(storm::OptimizationDirection::Maximize); + } + + ExplicitQualitativeResult& ExplicitQualitativeResultMinMax::getProb1Max() { + return getProb1(storm::OptimizationDirection::Maximize); + } + + } +} diff --git a/src/storm/abstraction/ExplicitQualitativeResultMinMax.h b/src/storm/abstraction/ExplicitQualitativeResultMinMax.h new file mode 100644 index 000000000..acccab839 --- /dev/null +++ b/src/storm/abstraction/ExplicitQualitativeResultMinMax.h @@ -0,0 +1,35 @@ +#pragma once + +#include "storm/solver/OptimizationDirection.h" + +#include "storm/abstraction/QualitativeResultMinMax.h" + +namespace storm { + namespace abstraction { + class ExplicitQualitativeResult; + class ExplicitQualitativeGameResultMinMax; + + class ExplicitQualitativeResultMinMax : public QualitativeResultMinMax { + public: + ExplicitQualitativeResultMinMax() = default; + + virtual bool isExplicit() const override; + + ExplicitQualitativeResult const& getProb0Min() const; + ExplicitQualitativeResult const& getProb1Min() const; + ExplicitQualitativeResult const& getProb0Max() const; + ExplicitQualitativeResult const& getProb1Max() const; + ExplicitQualitativeResult& getProb0Min(); + ExplicitQualitativeResult& getProb1Min(); + ExplicitQualitativeResult& getProb0Max(); + ExplicitQualitativeResult& getProb1Max(); + + virtual ExplicitQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; + virtual ExplicitQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; + virtual ExplicitQualitativeResult& getProb0(storm::OptimizationDirection const& dir) = 0; + virtual ExplicitQualitativeResult& getProb1(storm::OptimizationDirection const& dir) = 0; + }; + + } +} + diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.cpp b/src/storm/abstraction/ExplicitQuantitativeResult.cpp new file mode 100644 index 000000000..fc6cc14b0 --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResult.cpp @@ -0,0 +1,62 @@ +#include "storm/abstraction/ExplicitQuantitativeResult.h" + +#include "storm/storage/BitVector.h" + +#include "storm/adapters/RationalNumberAdapter.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace abstraction { + + template + ExplicitQuantitativeResult::ExplicitQuantitativeResult(uint64_t numberOfStates) : values(numberOfStates) { + // Intentionally left empty. + } + + template + ExplicitQuantitativeResult::ExplicitQuantitativeResult(std::vector&& values) : values(std::move(values)) { + // Intentionally left empty. + } + + template + std::vector const& ExplicitQuantitativeResult::getValues() const { + return values; + } + + template + std::vector& ExplicitQuantitativeResult::getValues() { + return values; + } + + template + void ExplicitQuantitativeResult::setValue(uint64_t state, ValueType const& value) { + values[state] = value; + } + + template + std::pair ExplicitQuantitativeResult::getRange(storm::storage::BitVector const& states) const { + STORM_LOG_THROW(!states.empty(), storm::exceptions::InvalidArgumentException, "Expected non-empty set of states."); + + auto stateIt = states.begin(); + std::pair result = std::make_pair(values[*stateIt], values[*stateIt]); + ++stateIt; + + while (stateIt != states.end()) { + if (values[*stateIt] < result.first) { + result.first = values[*stateIt]; + } else if (values[*stateIt] < result.first) { + result.second = values[*stateIt]; + } + + ++stateIt; + } + + return result; + } + + template class ExplicitQuantitativeResult; + template class ExplicitQuantitativeResult; + } +} diff --git a/src/storm/abstraction/ExplicitQuantitativeResult.h b/src/storm/abstraction/ExplicitQuantitativeResult.h new file mode 100644 index 000000000..449feb09e --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResult.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace storm { + namespace storage { + class BitVector; + } + + namespace abstraction { + + template + class ExplicitQuantitativeResult { + public: + ExplicitQuantitativeResult() = default; + ExplicitQuantitativeResult(uint64_t numberOfStates); + ExplicitQuantitativeResult(std::vector&& values); + + std::vector const& getValues() const; + std::vector& getValues(); + void setValue(uint64_t state, ValueType const& value); + + std::pair getRange(storm::storage::BitVector const& states) const; + + private: + std::vector values; + }; + + } +} + diff --git a/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp new file mode 100644 index 000000000..34a3ed22d --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.cpp @@ -0,0 +1,64 @@ +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" + +#include "storm/adapters/RationalNumberAdapter.h" + +namespace storm { + namespace abstraction { + + template + ExplicitQuantitativeResultMinMax::ExplicitQuantitativeResultMinMax(uint64_t numberOfStates) : min(numberOfStates), max(numberOfStates) { + // Intentionally left empty. + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMin() const { + return min; + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMin() { + return min; + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::getMax() const { + return max; + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::getMax() { + return max; + } + + template + void ExplicitQuantitativeResultMinMax::setMin(ExplicitQuantitativeResult&& newMin) { + min = std::move(newMin); + } + + template + void ExplicitQuantitativeResultMinMax::setMax(ExplicitQuantitativeResult&& newMax) { + max = std::move(newMax); + } + + template + ExplicitQuantitativeResult const& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return this->getMin(); + } else { + return this->getMax(); + } + } + + template + ExplicitQuantitativeResult& ExplicitQuantitativeResultMinMax::get(storm::OptimizationDirection const& dir) { + if (dir == storm::OptimizationDirection::Minimize) { + return this->getMin(); + } else { + return this->getMax(); + } + } + + template class ExplicitQuantitativeResultMinMax; + template class ExplicitQuantitativeResultMinMax; + } +} diff --git a/src/storm/abstraction/ExplicitQuantitativeResultMinMax.h b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.h new file mode 100644 index 000000000..f22ff4edb --- /dev/null +++ b/src/storm/abstraction/ExplicitQuantitativeResultMinMax.h @@ -0,0 +1,32 @@ +#pragma once + +#include "storm/abstraction/ExplicitQuantitativeResult.h" + +#include "storm/solver/OptimizationDirection.h" + +namespace storm { + namespace abstraction { + + template + class ExplicitQuantitativeResultMinMax { + public: + ExplicitQuantitativeResultMinMax() = default; + ExplicitQuantitativeResultMinMax(uint64_t numberOfStates); + + ExplicitQuantitativeResult const& getMin() const; + ExplicitQuantitativeResult& getMin(); + ExplicitQuantitativeResult const& getMax() const; + ExplicitQuantitativeResult& getMax(); + ExplicitQuantitativeResult const& get(storm::OptimizationDirection const& dir) const; + ExplicitQuantitativeResult& get(storm::OptimizationDirection const& dir); + + void setMin(ExplicitQuantitativeResult&& newMin); + void setMax(ExplicitQuantitativeResult&& newMax); + + private: + ExplicitQuantitativeResult min; + ExplicitQuantitativeResult max; + }; + + } +} diff --git a/src/storm/abstraction/ExpressionTranslator.cpp b/src/storm/abstraction/ExpressionTranslator.cpp index fe2d28f97..40e2b995d 100644 --- a/src/storm/abstraction/ExpressionTranslator.cpp +++ b/src/storm/abstraction/ExpressionTranslator.cpp @@ -17,7 +17,8 @@ namespace storm { template ExpressionTranslator::ExpressionTranslator(AbstractionInformation& abstractionInformation, std::unique_ptr&& smtSolver) : abstractionInformation(abstractionInformation), equivalenceChecker(std::move(smtSolver)), locationVariables(abstractionInformation.getLocationExpressionVariables()), abstractedVariables(abstractionInformation.getAbstractedVariables()) { - // Intentionally left empty. + + equivalenceChecker.addConstraints(abstractionInformation.getConstraints()); } template @@ -51,6 +52,8 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } @@ -108,12 +111,14 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } // At this point, none of the predicates was found to be equivalent, but there is no need to split as the subexpressions are not valid predicates. - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expressions of this kind are currently not supported by the abstraction expression translator."); + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expressions of this kind are currently not supported by the abstraction expression translator (" << expression << ")."); } return boost::any(); } @@ -124,12 +129,14 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Expressions of this kind are currently not supported by the abstraction expression translator."); } else { - return abstractionInformation.get().getDdManager().template getIdentity(abstractionInformation.get().getDdLocationVariable(expression.getVariable(), true)); + return abstractionInformation.get().getDdManager().template getIdentity(abstractionInformation.get().getDdLocationMetaVariable(expression.getVariable(), true)); } } @@ -154,6 +161,8 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.get().getNumberOfPredicates(); ++predicateIndex) { if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), expression.toExpression())) { return abstractionInformation.get().encodePredicateAsSource(predicateIndex); + } else if (equivalenceChecker.areEquivalent(abstractionInformation.get().getPredicateByIndex(predicateIndex), !expression.toExpression())) { + return !abstractionInformation.get().encodePredicateAsSource(predicateIndex); } } diff --git a/src/storm/abstraction/MenuGame.cpp b/src/storm/abstraction/MenuGame.cpp index 6252697bc..8258ddb51 100644 --- a/src/storm/abstraction/MenuGame.cpp +++ b/src/storm/abstraction/MenuGame.cpp @@ -82,8 +82,9 @@ namespace storm { template class MenuGame; template class MenuGame; + #ifdef STORM_HAVE_CARL - template class MenuGame; + template class MenuGame; #endif } } diff --git a/src/storm/abstraction/MenuGameAbstractor.cpp b/src/storm/abstraction/MenuGameAbstractor.cpp index 7ce40950b..2094568a2 100644 --- a/src/storm/abstraction/MenuGameAbstractor.cpp +++ b/src/storm/abstraction/MenuGameAbstractor.cpp @@ -4,6 +4,9 @@ #include "storm/models/symbolic/StandardRewardModel.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/AbstractionSettings.h" + #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" #include "storm/utility/dd.h" @@ -15,6 +18,20 @@ namespace storm { namespace abstraction { + template + MenuGameAbstractor::MenuGameAbstractor() : restrictToRelevantStates(storm::settings::getModule().isRestrictToRelevantStatesSet()) { + // Intentionally left empty. + } + + template + std::vector> MenuGameAbstractor::getVariableUpdates(uint64_t player1Choice) const { + std::vector> result(this->getNumberOfUpdates(player1Choice)); + for (uint64_t i = 0; i < result.size(); ++i) { + result[i] = this->getVariableUpdates(player1Choice, i); + } + return result; + } + template std::string getStateName(std::pair const& stateValue, std::set const& locationVariables, std::set const& predicateVariables, storm::expressions::Variable const& bottomVariable) { std::stringstream stateName; @@ -45,6 +62,11 @@ namespace storm { return stateName.str(); } + template + bool MenuGameAbstractor::isRestrictToRelevantStatesSet() const { + return restrictToRelevantStates; + } + template void MenuGameAbstractor::exportToDot(storm::abstraction::MenuGame const& currentGame, std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const { @@ -135,11 +157,26 @@ namespace storm { storm::utility::closeFile(out); } + template + void MenuGameAbstractor::setTargetStates(storm::expressions::Expression const& targetStateExpression) { + this->targetStateExpression = targetStateExpression; + } + + template + storm::expressions::Expression const& MenuGameAbstractor::getTargetStateExpression() const { + return this->targetStateExpression; + } + + template + bool MenuGameAbstractor::hasTargetStateExpression() const { + return this->targetStateExpression.isInitialized(); + } + template class MenuGameAbstractor; template class MenuGameAbstractor; #ifdef STORM_HAVE_CARL - template class MenuGameAbstractor; + template class MenuGameAbstractor; #endif } } diff --git a/src/storm/abstraction/MenuGameAbstractor.h b/src/storm/abstraction/MenuGameAbstractor.h index 946fb0a97..92b3cc97b 100644 --- a/src/storm/abstraction/MenuGameAbstractor.h +++ b/src/storm/abstraction/MenuGameAbstractor.h @@ -21,9 +21,19 @@ namespace storm { template class AbstractionInformation; + struct MenuGameAbstractorOptions { + MenuGameAbstractorOptions() = default; + MenuGameAbstractorOptions(std::vector&& constraints) : constraints(std::move(constraints)) { + // Intentionally left empty. + } + + std::vector constraints; + }; + template class MenuGameAbstractor { public: + MenuGameAbstractor(); virtual ~MenuGameAbstractor() = default; /// Retrieves the abstraction. @@ -33,7 +43,10 @@ namespace storm { virtual AbstractionInformation const& getAbstractionInformation() const = 0; virtual storm::expressions::Expression const& getGuard(uint64_t player1Choice) const = 0; virtual std::pair getPlayer1ChoiceRange() const = 0; + virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const = 0; + std::vector> getVariableUpdates(uint64_t player1Choice) const; virtual std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const = 0; + virtual std::set const& getAssignedVariables(uint64_t player1Choice) const = 0; virtual storm::expressions::Expression getInitialExpression() const = 0; /*! @@ -48,8 +61,41 @@ namespace storm { /// Exports a representation of the current abstraction state in the dot format. virtual void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const = 0; + /// Retrieves the number of predicates currently in use. + virtual uint64_t getNumberOfPredicates() const = 0; + + /*! + * Adds the expression to the ones characterizing terminal states, i.e. states whose transitions are not + * explored. For this to work, appropriate predicates must have been used to refine the abstraction, + * otherwise this will fail. + */ + virtual void addTerminalStates(storm::expressions::Expression const& expression) = 0; + + /*! + * Sets the expression characterizing the target states. For this to work, appropriate predicates must have + * been used to refine the abstraction, otherwise this will fail. + */ + void setTargetStates(storm::expressions::Expression const& targetStateExpression); + + storm::expressions::Expression const& getTargetStateExpression() const; + bool hasTargetStateExpression() const; + + /*! + * Notifies the abstractor that the guards are predicates, which may be used to improve the bottom state + * computation. + */ + virtual void notifyGuardsArePredicates() = 0; + protected: + bool isRestrictToRelevantStatesSet() const; + void exportToDot(storm::abstraction::MenuGame const& currentGame, std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const; + + private: + bool restrictToRelevantStates; + + // An expression characterizing the target states. + storm::expressions::Expression targetStateExpression; }; } diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp index 642cb83fb..23f2f4f34 100644 --- a/src/storm/abstraction/MenuGameRefiner.cpp +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -3,9 +3,18 @@ #include "storm/abstraction/AbstractionInformation.h" #include "storm/abstraction/MenuGameAbstractor.h" +#include "storm/storage/BitVector.h" +#include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" +#include "storm/abstraction/ExplicitGameStrategyPair.h" +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" + #include "storm/storage/dd/DdManager.h" +#include "storm/storage/dd/Odd.h" #include "storm/utility/dd.h" #include "storm/utility/solver.h" +#include "storm/utility/shortestPaths.h" + +#include "storm-parsers/parser/ExpressionParser.h" #include "storm/solver/MathsatSmtSolver.h" @@ -40,7 +49,7 @@ namespace storm { } template - MostProbablePathsResult::MostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree) : maxProbabilities(maxProbabilities), spanningTree(spanningTree) { + SymbolicMostProbablePathsResult::SymbolicMostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree) : maxProbabilities(maxProbabilities), spanningTree(spanningTree) { // Intentionally left empty. } @@ -52,18 +61,24 @@ namespace storm { }; template - PivotStateResult::PivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& mostProbablePathsResult) : pivotState(pivotState), fromDirection(fromDirection), mostProbablePathsResult(mostProbablePathsResult) { + SymbolicPivotStateResult::SymbolicPivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& symbolicMostProbablePathsResult) : pivotState(pivotState), fromDirection(fromDirection), symbolicMostProbablePathsResult(symbolicMostProbablePathsResult) { // Intentionally left empty. } template - MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), addedAllGuardsFlag(false), pivotSelectionHeuristic(storm::settings::getModule().getPivotSelectionHeuristic()), splitter(), equivalenceChecker(std::move(smtSolver)) { + MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver, MenuGameRefinerOptions const& options) : abstractor(abstractor), useInterpolation(storm::settings::getModule().isUseInterpolationSet()), splitAll(false), splitPredicates(false), rankPredicates(false), addedAllGuardsFlag(false), refinementPredicatesToInject(options.refinementPredicates), pivotSelectionHeuristic(), splitter(), equivalenceChecker(std::move(smtSolver)) { + auto const& abstractionSettings = storm::settings::getModule(); + + pivotSelectionHeuristic = abstractionSettings.getPivotSelectionHeuristic(); AbstractionSettings::SplitMode splitMode = storm::settings::getModule().getSplitMode(); splitAll = splitMode == AbstractionSettings::SplitMode::All; splitPredicates = splitMode == AbstractionSettings::SplitMode::NonGuard; + rankPredicates = abstractionSettings.isRankRefinementPredicatesSet(); + addPredicatesEagerly = abstractionSettings.isUseEagerRefinementSet(); - if (storm::settings::getModule().isAddAllGuardsSet()) { + equivalenceChecker.addConstraints(abstractor.getAbstractionInformation().getConstraints()); + if (abstractionSettings.isAddAllGuardsSet()) { std::vector guards; std::pair player1Choices = this->abstractor.get().getPlayer1ChoiceRange(); @@ -75,17 +90,22 @@ namespace storm { } performRefinement(createGlobalRefinement(preprocessPredicates(guards, RefinementPredicates::Source::InitialGuard))); + this->abstractor.get().notifyGuardsArePredicates(); addedAllGuardsFlag = true; } + if (abstractionSettings.isAddAllInitialExpressionsSet()) { + storm::expressions::Expression initialExpression = this->abstractor.get().getInitialExpression(); + performRefinement(createGlobalRefinement(preprocessPredicates({initialExpression}, RefinementPredicates::Source::InitialExpression))); + } } template - void MenuGameRefiner::refine(std::vector const& predicates) const { - performRefinement(createGlobalRefinement(preprocessPredicates(predicates, RefinementPredicates::Source::Manual))); + void MenuGameRefiner::refine(std::vector const& predicates, bool allowInjection) const { + performRefinement(createGlobalRefinement(preprocessPredicates(predicates, RefinementPredicates::Source::Manual)), allowInjection); } template - MostProbablePathsResult getMostProbablePathSpanningTree(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionFilter) { + SymbolicMostProbablePathsResult getMostProbablePathSpanningTree(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionFilter) { storm::dd::Add maxProbabilities = game.getInitialStates().template toAdd(); storm::dd::Bdd border = game.getInitialStates(); @@ -116,11 +136,11 @@ namespace storm { border = updateStates; } - return MostProbablePathsResult(maxProbabilities, spanningTree); + return SymbolicMostProbablePathsResult(maxProbabilities, spanningTree); } template - PivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic const& heuristic, storm::abstraction::MenuGame const& game, PivotStateCandidatesResult const& pivotStateCandidateResult, boost::optional> const& qualitativeResult, boost::optional> const& quantitativeResult) { + SymbolicPivotStateResult pickPivotState(AbstractionSettings::PivotSelectionHeuristic const& heuristic, storm::abstraction::MenuGame const& game, PivotStateCandidatesResult const& pivotStateCandidateResult, boost::optional> const& qualitativeResult, boost::optional> const& quantitativeResult) { // Get easy access to strategies. storm::dd::Bdd minPlayer1Strategy; @@ -159,7 +179,7 @@ namespace storm { bool foundPivotState = !frontierPivotStates.isZero(); if (foundPivotState) { STORM_LOG_TRACE("Picked pivot state from " << frontierPivotStates.getNonZeroCount() << " candidates on level " << level << ", " << pivotStates.getNonZeroCount() << " candidates in total."); - return PivotStateResult(frontierPivotStates.existsAbstractRepresentative(rowVariables), storm::OptimizationDirection::Minimize); + return SymbolicPivotStateResult(frontierPivotStates.existsAbstractRepresentative(rowVariables), storm::OptimizationDirection::Minimize); } else { // Otherwise, we perform a simulatenous BFS in the sense that we make one step in both the min and max // transitions and check for pivot states we encounter. @@ -191,7 +211,7 @@ namespace storm { } STORM_LOG_TRACE("Picked pivot state with difference " << diffValue << " from " << numberOfPivotStateCandidatesOnLevel << " candidates on level " << level << ", " << pivotStates.getNonZeroCount() << " candidates in total."); - return PivotStateResult(direction == storm::OptimizationDirection::Minimize ? diffMin.maxAbstractRepresentative(rowVariables) : diffMax.maxAbstractRepresentative(rowVariables), direction); + return SymbolicPivotStateResult(direction == storm::OptimizationDirection::Minimize ? diffMin.maxAbstractRepresentative(rowVariables) : diffMax.maxAbstractRepresentative(rowVariables), direction); } else { STORM_LOG_TRACE("Picked pivot state from " << numberOfPivotStateCandidatesOnLevel << " candidates on level " << level << ", " << pivotStates.getNonZeroCount() << " candidates in total."); @@ -202,18 +222,18 @@ namespace storm { direction = storm::OptimizationDirection::Maximize; } - return PivotStateResult(direction == storm::OptimizationDirection::Minimize ? frontierMinPivotStates.existsAbstractRepresentative(rowVariables) : frontierMaxPivotStates.existsAbstractRepresentative(rowVariables), direction); + return SymbolicPivotStateResult(direction == storm::OptimizationDirection::Minimize ? frontierMinPivotStates.existsAbstractRepresentative(rowVariables) : frontierMaxPivotStates.existsAbstractRepresentative(rowVariables), direction); } } } } } else { // Compute the most probable paths to the reachable states and the corresponding spanning trees. - MostProbablePathsResult minMostProbablePathsResult = getMostProbablePathSpanningTree(game, minPlayer1Strategy && minPlayer2Strategy); - MostProbablePathsResult maxMostProbablePathsResult = getMostProbablePathSpanningTree(game, maxPlayer1Strategy && maxPlayer2Strategy); + SymbolicMostProbablePathsResult minSymbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, minPlayer1Strategy && minPlayer2Strategy); + SymbolicMostProbablePathsResult maxSymbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, maxPlayer1Strategy && maxPlayer2Strategy); storm::dd::Bdd selectedPivotState; - storm::dd::Add score = pivotStates.template toAdd() * minMostProbablePathsResult.maxProbabilities.maximum(maxMostProbablePathsResult.maxProbabilities); + storm::dd::Add score = pivotStates.template toAdd() * minSymbolicMostProbablePathsResult.maxProbabilities.maximum(maxSymbolicMostProbablePathsResult.maxProbabilities); if (heuristic == AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation && quantitativeResult) { score = score * (quantitativeResult.get().max.values - quantitativeResult.get().min.values); @@ -223,15 +243,15 @@ namespace storm { storm::OptimizationDirection fromDirection = storm::OptimizationDirection::Minimize; storm::dd::Add selectedPivotStateAsAdd = selectedPivotState.template toAdd(); - if ((selectedPivotStateAsAdd * maxMostProbablePathsResult.maxProbabilities).getMax() > (selectedPivotStateAsAdd * minMostProbablePathsResult.maxProbabilities).getMax()) { + if ((selectedPivotStateAsAdd * maxSymbolicMostProbablePathsResult.maxProbabilities).getMax() > (selectedPivotStateAsAdd * minSymbolicMostProbablePathsResult.maxProbabilities).getMax()) { fromDirection = storm::OptimizationDirection::Maximize; } - return PivotStateResult(selectedPivotState, fromDirection, fromDirection == storm::OptimizationDirection::Minimize ? minMostProbablePathsResult : maxMostProbablePathsResult); + return SymbolicPivotStateResult(selectedPivotState, fromDirection, fromDirection == storm::OptimizationDirection::Minimize ? minSymbolicMostProbablePathsResult : maxSymbolicMostProbablePathsResult); } STORM_LOG_ASSERT(false, "This point must not be reached, because then no pivot state could be found."); - return PivotStateResult(storm::dd::Bdd(), storm::OptimizationDirection::Minimize); + return SymbolicPivotStateResult(storm::dd::Bdd(), storm::OptimizationDirection::Minimize); } template @@ -240,7 +260,7 @@ namespace storm { storm::expressions::Expression newPredicate; bool fromGuard = false; - // Get abstraction informatin for easier access. + // Get abstraction information for easier access. AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); // Decode the index of the command chosen by player 1. @@ -290,63 +310,157 @@ namespace storm { for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) { if (lower[predicateIndex] != upper[predicateIndex]) { possibleRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify()); + if (!rankPredicates) { + break; + } } } - ++orderedUpdateIndex; break; } } STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates."); - // Since we can choose any of the deviation predicates to perform the split, we go through the remaining - // updates and build all deviation predicates. We can then check whether any of the possible refinement - // predicates also eliminates another deviation. - std::vector otherRefinementPredicates; - for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) { - storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; - storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; - - bool deviates = lower != upper; - if (deviates) { - std::map newVariableUpdates = abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first); - for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) { - if (lower[predicateIndex] != upper[predicateIndex]) { - otherRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(newVariableUpdates).simplify()); + STORM_LOG_TRACE("Possible refinement predicates:"); + for (auto const& pred : possibleRefinementPredicates) { + STORM_LOG_TRACE(pred); + } + + if (rankPredicates) { + // Since we can choose any of the deviation predicates to perform the split, we go through the remaining + // updates and build all deviation predicates. We can then check whether any of the possible refinement + // predicates also eliminates another deviation. + std::vector otherRefinementPredicates; + for (; orderedUpdateIndex < updateIndicesAndMasses.size(); ++orderedUpdateIndex) { + storm::storage::BitVector const& lower = lowerChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; + storm::storage::BitVector const& upper = upperChoiceUpdateToSuccessorMapping.at(updateIndicesAndMasses[orderedUpdateIndex].first).first; + + bool deviates = lower != upper; + if (deviates) { + std::map newVariableUpdates = abstractor.get().getVariableUpdates(player1Index, updateIndicesAndMasses[orderedUpdateIndex].first); + for (uint64_t predicateIndex = 0; predicateIndex < lower.size(); ++predicateIndex) { + if (lower[predicateIndex] != upper[predicateIndex]) { + otherRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(newVariableUpdates).simplify()); + } } } } - } - - // Finally, go through the refinement predicates and see how many deviations they cover. - std::vector refinementPredicateIndexToCount(possibleRefinementPredicates.size(), 0); - for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - refinementPredicateIndexToCount[index] = 1; - } - for (auto const& otherPredicate : otherRefinementPredicates) { + + // Finally, go through the refinement predicates and see how many deviations they cover. + std::vector refinementPredicateIndexToCount(possibleRefinementPredicates.size(), 0); for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - if (equivalenceChecker.areEquivalent(otherPredicate, possibleRefinementPredicates[index])) { - ++refinementPredicateIndexToCount[index]; + refinementPredicateIndexToCount[index] = 1; + } + for (auto const& otherPredicate : otherRefinementPredicates) { + for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { + if (equivalenceChecker.areEquivalentModuloNegation(otherPredicate, possibleRefinementPredicates[index])) { + ++refinementPredicateIndexToCount[index]; + } } } - } - - // Find predicate that covers the most deviations. - uint64_t chosenPredicateIndex = 0; - for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { - if (refinementPredicateIndexToCount[index] > refinementPredicateIndexToCount[chosenPredicateIndex]) { - chosenPredicateIndex = index; + + // Find predicate that covers the most deviations. + uint64_t chosenPredicateIndex = 0; + for (uint64_t index = 0; index < possibleRefinementPredicates.size(); ++index) { + if (refinementPredicateIndexToCount[index] > refinementPredicateIndexToCount[chosenPredicateIndex]) { + chosenPredicateIndex = index; + } } + newPredicate = possibleRefinementPredicates[chosenPredicateIndex]; + STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << ", (equivalent to " << (refinementPredicateIndexToCount[chosenPredicateIndex] - 1) << " other refinement predicates)."); + } else { + newPredicate = possibleRefinementPredicates.front(); + STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << "."); } - newPredicate = possibleRefinementPredicates[chosenPredicateIndex]; STORM_LOG_ASSERT(newPredicate.isInitialized(), "Could not derive new predicate as there is no deviation."); - STORM_LOG_DEBUG("Derived new predicate (based on weakest-precondition): " << newPredicate << ", (equivalent to " << (refinementPredicateIndexToCount[chosenPredicateIndex] - 1) << " other refinement predicates)"); } return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {newPredicate}); } + template + RefinementPredicates MenuGameRefiner::derivePredicatesFromChoice(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& pivotState, storm::dd::Bdd const& player1Choice, storm::dd::Bdd const& choice, storm::dd::Bdd const& choiceSuccessors) const { + // Prepare result. + storm::expressions::Expression newPredicate; + bool fromGuard = false; + + // Get abstraction information for easier access. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + + // Decode the index of the command chosen by player 1. + storm::dd::Add player1ChoiceAsAdd = player1Choice.template toAdd(); + auto pl1It = player1ChoiceAsAdd.begin(); + uint_fast64_t player1Index = abstractionInformation.decodePlayer1Choice((*pl1It).first, abstractionInformation.getPlayer1VariableCount()); + + // Check whether there are bottom states in the game and whether the choice actually picks the bottom state + // as the successor. + bool buttomStateSuccessor = !((abstractionInformation.getBottomStateBdd(false, false) && choiceSuccessors)).isZero(); + + std::vector possibleRefinementPredicates; + + // If the choice picks the bottom state, the new predicate is based on the guard of the appropriate command + // (that is the player 1 choice). + if (buttomStateSuccessor) { + STORM_LOG_TRACE("One of the successors is a bottom state, taking a guard as a new predicate."); + possibleRefinementPredicates.emplace_back(abstractor.get().getGuard(player1Index)); + fromGuard = true; + STORM_LOG_DEBUG("Derived new predicate (based on guard): " << possibleRefinementPredicates.back()); + } else { + STORM_LOG_TRACE("No bottom state successor. Deriving a new predicate using weakest precondition."); + + // Decode the choice successors. + std::map> choiceUpdateToSuccessorMapping = abstractionInformation.template decodeChoiceToUpdateSuccessorMapping(choiceSuccessors); + std::vector> sortedChoiceUpdateIndicesAndMasses; + for (auto const& e : choiceUpdateToSuccessorMapping) { + sortedChoiceUpdateIndicesAndMasses.emplace_back(e.first, e.second.second); + } + std::sort(sortedChoiceUpdateIndicesAndMasses.begin(), sortedChoiceUpdateIndicesAndMasses.end(), [] (std::pair const& a, std::pair const& b) { return a.second > b.second; }); + + // Compute all other (not taken) choices. + std::set variablesToAbstract = game.getRowVariables(); + variablesToAbstract.insert(game.getPlayer1Variables().begin(), game.getPlayer1Variables().end()); + + storm::dd::Bdd otherChoices = (pivotState && !choice && player1Choice && game.getExtendedTransitionMatrix().toBdd()).existsAbstract(variablesToAbstract); + STORM_LOG_ASSERT(!otherChoices.isZero(), "Expected other choices."); + + // Decode the other choices. + std::vector>> otherChoicesUpdateToSuccessorMappings = abstractionInformation.template decodeChoicesToUpdateSuccessorMapping(game.getPlayer2Variables(), otherChoices); + + for (auto const& otherChoice : otherChoicesUpdateToSuccessorMappings) { + for (uint64_t updateIndex = 0; updateIndex < sortedChoiceUpdateIndicesAndMasses.size(); ++updateIndex) { + storm::storage::BitVector const& choiceSuccessor = choiceUpdateToSuccessorMapping.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first; + storm::storage::BitVector const& otherChoiceSuccessor = otherChoice.at(sortedChoiceUpdateIndicesAndMasses[updateIndex].first).first; + + bool deviates = choiceSuccessor != otherChoiceSuccessor; + if (deviates) { + std::map variableUpdates = abstractor.get().getVariableUpdates(player1Index, sortedChoiceUpdateIndicesAndMasses[updateIndex].first); + + for (uint64_t predicateIndex = 0; predicateIndex < choiceSuccessor.size(); ++predicateIndex) { + if (choiceSuccessor[predicateIndex] != otherChoiceSuccessor[predicateIndex]) { + possibleRefinementPredicates.push_back(abstractionInformation.getPredicateByIndex(predicateIndex).substitute(variableUpdates).simplify()); + if (!rankPredicates) { + break; + } + } + } + + break; + } + } + } + + STORM_LOG_ASSERT(!possibleRefinementPredicates.empty(), "Expected refinement predicates."); + + STORM_LOG_TRACE("Possible refinement predicates:"); + for (auto const& pred : possibleRefinementPredicates) { + STORM_LOG_TRACE(pred); + } + } + + return RefinementPredicates(fromGuard ? RefinementPredicates::Source::Guard : RefinementPredicates::Source::WeakestPrecondition, {possibleRefinementPredicates}); + } + template PivotStateCandidatesResult computePivotStates(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) { @@ -389,31 +503,43 @@ namespace storm { storm::dd::Bdd lowerChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; storm::dd::Bdd lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); storm::dd::Bdd lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - - bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero(); + + bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero() && !lowerChoice1.isZero() && !lowerChoice2.isZero(); if (lowerChoicesDifferent) { - STORM_LOG_TRACE("Deriving predicate based on lower choice."); - predicates = derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2); + STORM_LOG_TRACE("Deriving predicates based on lower choice."); + if (this->addPredicatesEagerly) { + predicates = derivePredicatesFromChoice(game, pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice && minPlayer2Strategy, lowerChoice1); + } else { + predicates = derivePredicatesFromDifferingChoices((pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2); + } } - if (predicates && (!player1ChoicesDifferent || predicates.get().getSource() == RefinementPredicates::Source::Guard)) { + if (predicates && !player1ChoicesDifferent) { return predicates.get(); - } else { - boost::optional additionalPredicates; - - storm::dd::Bdd upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; - storm::dd::Bdd upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); - storm::dd::Bdd upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); - - bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero(); - if (upperChoicesDifferent) { - STORM_LOG_TRACE("Deriving predicate based on upper choice."); + } + + boost::optional additionalPredicates; + + storm::dd::Bdd upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; + storm::dd::Bdd upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract); + storm::dd::Bdd upperChoice2 = (upperChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract); + + bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero() && !upperChoice1.isZero() && !upperChoice2.isZero(); + if (upperChoicesDifferent) { + STORM_LOG_TRACE("Deriving predicates based on upper choice."); + if (this->addPredicatesEagerly) { + additionalPredicates = derivePredicatesFromChoice(game, pivotState, (pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice && maxPlayer2Strategy, upperChoice1); + } else { additionalPredicates = derivePredicatesFromDifferingChoices((pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice1, upperChoice2); } - - if (additionalPredicates) { - if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) { - return additionalPredicates.get(); + } + + if (additionalPredicates) { + if (additionalPredicates.get().getSource() == RefinementPredicates::Source::Guard) { + return additionalPredicates.get(); + } else { + if (!predicates) { + predicates = additionalPredicates; } else { predicates.get().addPredicates(additionalPredicates.get().getPredicates()); } @@ -459,6 +585,10 @@ namespace storm { for (auto& predicate : predicates.back()) { predicate = predicate.changeManager(expressionManager); } + // Add ranges of variables. + for (auto const& pred : abstractionInformation.getConstraints()) { + predicates.back().push_back(pred.changeManager(expressionManager)); + } // Perform a backward search for an initial state. storm::dd::Bdd currentState = pivotState; @@ -476,12 +606,26 @@ namespace storm { // Retrieve the variable updates that the predecessor needs to perform to get to the current state. auto variableUpdates = abstractor.get().getVariableUpdates(std::get<1>(decodedPredecessor), std::get<2>(decodedPredecessor)); - for (auto const& update : variableUpdates) { - storm::expressions::Variable newVariable = oldToNewVariables.at(update.first); - if (update.second.hasBooleanType()) { - predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(oldToNewVariables.at(update.first)), update.second.changeManager(expressionManager).substitute(substitution))); + for (auto const& oldNewVariablePair : oldToNewVariables) { + storm::expressions::Variable const& newVariable = oldNewVariablePair.second; + + // If the variable was set, use its update expression. + auto updateIt = variableUpdates.find(oldNewVariablePair.first); + if (updateIt != variableUpdates.end()) { + auto const& update = *updateIt; + + if (update.second.hasBooleanType()) { + predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(newVariable), update.second.changeManager(expressionManager).substitute(substitution))); + } else { + predicates.back().push_back(lastSubstitution.at(newVariable) == update.second.changeManager(expressionManager).substitute(substitution)); + } } else { - predicates.back().push_back(lastSubstitution.at(oldToNewVariables.at(update.first)) == update.second.changeManager(expressionManager).substitute(substitution)); + // Otherwise, make sure that the new variable maintains the old value. + if (newVariable.hasBooleanType()) { + predicates.back().push_back(storm::expressions::iff(lastSubstitution.at(newVariable), substitution.at(newVariable))); + } else { + predicates.back().push_back(lastSubstitution.at(newVariable) == substitution.at(newVariable)); + } } } @@ -493,7 +637,10 @@ namespace storm { for (auto& predicate : predicates.back()) { predicate = predicate.changeManager(expressionManager).substitute(substitution); } - + // Add ranges of variables. + for (auto const& pred : abstractionInformation.getConstraints()) { + predicates.back().push_back(pred.changeManager(expressionManager).substitute(substitution)); + } // Move backwards one step. lastSubstitution = std::move(substitution); currentState = predecessorTransition.existsAbstract(variablesToAbstract); @@ -503,49 +650,219 @@ namespace storm { return std::make_pair(predicates, stepVariableToCopiedVariableMap); } + template + const uint64_t ExplicitPivotStateResult::NO_PREDECESSOR = std::numeric_limits::max(); + + template + std::pair, std::vector> MenuGameRefiner::buildReversedLabeledPath(ExplicitPivotStateResult const& pivotStateResult) const { + + std::pair, std::vector> result; + result.first.emplace_back(pivotStateResult.pivotState); + + uint64_t currentState = pivotStateResult.predecessors[pivotStateResult.pivotState].first; + uint64_t currentAction = pivotStateResult.predecessors[pivotStateResult.pivotState].second; + while (currentState != ExplicitPivotStateResult::NO_PREDECESSOR) { + STORM_LOG_ASSERT(currentAction != ExplicitPivotStateResult::NO_PREDECESSOR, "Expected predecessor action."); + result.first.emplace_back(currentState); + result.second.emplace_back(currentAction); + currentAction = pivotStateResult.predecessors[currentState].second; + currentState = pivotStateResult.predecessors[currentState].first; + } + + STORM_LOG_ASSERT(result.first.size() == result.second.size() + 1, "Path size mismatch."); + return result; + } + template - boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, PivotStateResult const& pivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { + std::pair>, std::map> MenuGameRefiner::buildTraceFromReversedLabeledPath(storm::expressions::ExpressionManager& expressionManager, std::vector const& reversedPath, std::vector const& reversedLabels, storm::dd::Odd const& odd, std::vector const* stateToOffset) const { + STORM_LOG_ASSERT(reversedPath.size() == reversedLabels.size() + 1, "Path size mismatch."); + + std::vector> predicates; AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + storm::expressions::Expression initialExpression = abstractor.get().getInitialExpression(); - // Compute the most probable path from any initial state to the pivot state. - MostProbablePathsResult mostProbablePathsResult; - if (!pivotStateResult.mostProbablePathsResult) { - mostProbablePathsResult = getMostProbablePathSpanningTree(game, pivotStateResult.fromDirection == storm::OptimizationDirection::Minimize ? minPlayer1Strategy && minPlayer2Strategy : maxPlayer1Strategy && maxPlayer2Strategy); - } else { - mostProbablePathsResult = pivotStateResult.mostProbablePathsResult.get(); + std::set oldVariables = initialExpression.getVariables(); + for (auto const& predicate : abstractionInformation.getPredicates()) { + std::set usedVariables = predicate.getVariables(); + oldVariables.insert(usedVariables.begin(), usedVariables.end()); } - // Create a new expression manager that we can use for the interpolation. - std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + std::map oldToNewVariables; + for (auto const& variable : oldVariables) { + oldToNewVariables[variable] = expressionManager.getVariable(variable.getName()); + } + std::map currentSubstitution; + for (auto const& variable : oldToNewVariables) { + currentSubstitution[variable.second] = variable.second; + } + std::map stepVariableToCopiedVariableMap; - // Build the trace of the most probable path in terms of which predicates hold in each step. - std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, mostProbablePathsResult.spanningTree, pivotStateResult.pivotState); - auto const& trace = traceAndVariableSubstitution.first; - auto const& variableSubstitution = traceAndVariableSubstitution.second; + auto pathIt = reversedPath.rbegin(); + + // Decode pivot state. The state valuation also includes + // * the bottom state, so we need to reserve one more, and + // * the location variables, + // so we need to reserve an appropriate size. + uint64_t predicateValuationOffset = abstractionInformation.getNumberOfDdSourceLocationVariables() + 1; + storm::storage::BitVector extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset); + ++pathIt; + + // Add all predicates of initial block. + predicates.emplace_back(abstractionInformation.getPredicatesExcludingBottom(extendedPredicateValuation)); + for (auto& predicate : predicates.back()) { + predicate = predicate.changeManager(expressionManager); + } + + // Add further constraints (like ranges). + for (auto const& pred : abstractionInformation.getConstraints()) { + predicates.back().push_back(pred.changeManager(expressionManager)); + } + + // Add initial expression. + predicates.back().push_back(initialExpression.changeManager(expressionManager)); + + // Traverse the path and construct necessary formula parts. + auto actionIt = reversedLabels.rbegin(); + uint64_t step = 0; + for (; pathIt != reversedPath.rend(); ++pathIt) { + + // Add new predicate frame. + predicates.emplace_back(); + + // Add guard of action. + predicates.back().emplace_back(abstractor.get().getGuard(*actionIt).changeManager(expressionManager).substitute(currentSubstitution)); + + // Determine which variables are affected by the updates of the player 1 choice. + std::set const& assignedVariables = abstractor.get().getAssignedVariables(*actionIt); + + // Create new instances of the affected variables. + std::map newVariableMaps; + for (auto const& variable : assignedVariables) { + storm::expressions::Variable variableCopy = expressionManager.declareVariableCopy(variable); + newVariableMaps[oldToNewVariables.at(variable)] = variableCopy; + stepVariableToCopiedVariableMap[variableCopy] = variable; + } + + // Retrieves the possible updates to the variables. + auto variableUpdateVector = abstractor.get().getVariableUpdates(*actionIt); + + // Encode these updates. + storm::expressions::Expression allVariableUpdateExpression; + for (auto const& variableUpdates : variableUpdateVector) { + storm::expressions::Expression variableUpdateExpression; + for (auto const& update : variableUpdates) { + if (update.second.hasBooleanType()) { + variableUpdateExpression = variableUpdateExpression && storm::expressions::iff(newVariableMaps.at(update.first), update.second.changeManager(expressionManager).substitute(currentSubstitution)); + } else { + variableUpdateExpression = variableUpdateExpression && newVariableMaps.at(update.first) == update.second.changeManager(expressionManager).substitute(currentSubstitution); + } + } + + allVariableUpdateExpression = allVariableUpdateExpression || variableUpdateExpression; + } + if (!allVariableUpdateExpression.isInitialized()) { + allVariableUpdateExpression = expressionManager.boolean(true); + } + predicates.back().emplace_back(allVariableUpdateExpression); + + // Incorporate the new variables in the current substitution. + for (auto const& variablePair : newVariableMaps) { + currentSubstitution[variablePair.first] = variablePair.second; + } + + // Decode current state. + extendedPredicateValuation = odd.getEncoding(stateToOffset ? (*stateToOffset)[*pathIt] : *pathIt, abstractionInformation.getNumberOfPredicates() + predicateValuationOffset); + + // Encode the predicates whose value might have changed. + // FIXME: could be optimized by precomputation. + for (uint64_t predicateIndex = 0; predicateIndex < abstractionInformation.getNumberOfPredicates(); ++predicateIndex) { + auto const& predicate = abstractionInformation.getPredicateByIndex(predicateIndex); + std::set usedVariables = predicate.getVariables(); + + bool containsAssignedVariables = false; + for (auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) { + if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) { + break; + } + + if (*usedIt == *assignedIt) { + containsAssignedVariables = true; + break; + } + + if (*usedIt < *assignedIt) { + ++usedIt; + } else { + ++assignedIt; + } + } + + if (containsAssignedVariables) { + auto transformedPredicate = predicate.changeManager(expressionManager).substitute(currentSubstitution); + predicates.back().emplace_back(extendedPredicateValuation.get(predicateIndex + predicateValuationOffset) ? transformedPredicate : !transformedPredicate); + } + } + + // Enforce constraints of all assigned variables. + for (auto const& constraint : abstractionInformation.getConstraints()) { + std::set usedVariables = constraint.getVariables(); + + bool containsAssignedVariables = false; + for (auto usedIt = usedVariables.begin(), assignedIt = assignedVariables.begin();;) { + if (usedIt == usedVariables.end() || assignedIt == assignedVariables.end()) { + break; + } + + if (*usedIt == *assignedIt) { + containsAssignedVariables = true; + break; + } + + if (*usedIt < *assignedIt) { + ++usedIt; + } else { + ++assignedIt; + } + } + + if (containsAssignedVariables) { + auto transformedConstraint = constraint.changeManager(expressionManager).substitute(currentSubstitution); + predicates.back().emplace_back(transformedConstraint); + } + } + + ++actionIt; + ++step; + } + + return std::make_pair(predicates, stepVariableToCopiedVariableMap); + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolationFromTrace(storm::expressions::ExpressionManager& interpolationManager, std::vector> const& trace, std::map const& variableSubstitution) const { + + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + + auto start = std::chrono::high_resolution_clock::now(); + boost::optional predicates; // Create solver and interpolation groups. - storm::solver::MathsatSmtSolver interpolatingSolver(*interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); + auto assertionStart = std::chrono::high_resolution_clock::now(); + storm::solver::MathsatSmtSolver interpolatingSolver(interpolationManager, storm::solver::MathsatSmtSolver::Options(true, false, true)); uint64_t stepCounter = 0; - auto traceIt = trace.rbegin(); - auto traceIte = trace.rend(); - for (; traceIt != traceIte; ++traceIt) { - auto const& step = *traceIt; - interpolatingSolver.push(); + for (auto const& traceElement : trace) { + // interpolatingSolver.push(); interpolatingSolver.setInterpolationGroup(stepCounter); - for (auto const& predicate : step) { + for (auto const& predicate : traceElement) { interpolatingSolver.add(predicate); } + ++stepCounter; - - storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); - // If the result already became unsatisfiable - if (result == storm::solver::SmtSolver::CheckResult::Unsat) { - STORM_LOG_TRACE("Trace formula became unsatisfiable after step " << (stepCounter - 1) << "."); - break; - } } + auto assertionEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Asserting trace formula took " << std::chrono::duration_cast(assertionEnd - assertionStart).count() << "ms."); // Now encode the trace as an SMT problem. storm::solver::SmtSolver::CheckResult result = interpolatingSolver.check(); @@ -554,24 +871,86 @@ namespace storm { std::vector interpolants; std::vector prefix; - for (uint64_t step = 0; step + 1 < stepCounter; ++step) { + for (uint64_t step = 0; step < stepCounter; ++step) { prefix.push_back(step); storm::expressions::Expression interpolant = interpolatingSolver.getInterpolant(prefix).substitute(variableSubstitution).changeManager(abstractionInformation.getExpressionManager()); - if (!interpolant.isTrue() && !interpolant.isFalse()) { - STORM_LOG_DEBUG("Derived new predicate (based on interpolation): " << interpolant); + if (interpolant.isFalse()) { + // If the interpolant is false, it means that the prefix has become unsatisfiable. + STORM_LOG_TRACE("Trace formula became unsatisfiable at position " << step << " of " << stepCounter << "."); + break; + } + if (!interpolant.isTrue()) { + STORM_LOG_DEBUG("Derived new predicate (based on interpolation at step " << step << " out of " << stepCounter << "): " << interpolant); interpolants.push_back(interpolant); } } - return boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); + + STORM_LOG_ASSERT(!interpolants.empty(), "Expected to have non-empty set of interpolants."); + + predicates = boost::make_optional(RefinementPredicates(RefinementPredicates::Source::Interpolation, interpolants)); } else { STORM_LOG_TRACE("Trace formula is satisfiable, not using interpolation."); } + auto end = std::chrono::high_resolution_clock::now(); - return boost::none; + if (predicates) { + STORM_LOG_TRACE("Deriving predicates using interpolation from witness of size " << trace.size() << " took " << std::chrono::duration_cast(end - start).count() << "ms."); + } else { + STORM_LOG_TRACE("Tried deriving predicates using interpolation but failed in " << std::chrono::duration_cast(end - start).count() << "ms."); + } + + return predicates; + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const { + + // Compute the most probable path from any initial state to the pivot state. + SymbolicMostProbablePathsResult symbolicMostProbablePathsResult; + if (!symbolicPivotStateResult.symbolicMostProbablePathsResult) { + symbolicMostProbablePathsResult = getMostProbablePathSpanningTree(game, symbolicPivotStateResult.fromDirection == storm::OptimizationDirection::Minimize ? minPlayer1Strategy && minPlayer2Strategy : maxPlayer1Strategy && maxPlayer2Strategy); + } else { + symbolicMostProbablePathsResult = symbolicPivotStateResult.symbolicMostProbablePathsResult.get(); + } + + // Create a new expression manager that we can use for the interpolation. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + + // Build the trace of the most probable path in terms of which predicates hold in each step. + auto start = std::chrono::high_resolution_clock::now(); + std::pair>, std::map> traceAndVariableSubstitution = buildTrace(*interpolationManager, game, symbolicMostProbablePathsResult.spanningTree, symbolicPivotStateResult.pivotState); + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from symbolic most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); + + return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const { + + // Create a new expression manager that we can use for the interpolation. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + + // Build the trace of the most probable path in terms of which predicates hold in each step. + auto start = std::chrono::high_resolution_clock::now(); + std::pair, std::vector> labeledReversedPath = buildReversedLabeledPath(pivotStateResult); + + // If the initial state is the pivot state, we can stop here. + if (labeledReversedPath.first.size() == 1) { + return boost::none; + } + + std::pair>, std::map> traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(*interpolationManager, labeledReversedPath.first, labeledReversedPath.second, odd); + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); + + return derivePredicatesFromInterpolationFromTrace(*interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); } template - bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QualitativeGameResultMinMax const& qualitativeResult) const { + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQualitativeGameResultMinMax const& qualitativeResult) const { STORM_LOG_TRACE("Trying refinement after qualitative check."); // Get all relevant strategies. storm::dd::Bdd minPlayer1Strategy = qualitativeResult.prob0Min.getPlayer1Strategy(); @@ -581,6 +960,7 @@ namespace storm { // Redirect all player 1 choices of the min strategy to that of the max strategy if this leads to a player 2 // state that is also a prob 0 state. + auto oldMinPlayer1Strategy = minPlayer1Strategy; minPlayer1Strategy = (maxPlayer1Strategy && qualitativeResult.prob0Min.getPlayer2States()).existsAbstract(game.getPlayer1Variables()).ite(maxPlayer1Strategy, minPlayer1Strategy); // Compute all reached pivot states. @@ -591,21 +971,64 @@ namespace storm { // strategies and they differ. Hence, it is possible that we arrive at a point where no suitable pivot state // is found. In this case, we abort the qualitative refinement here. if (pivotStateCandidatesResult.pivotStates.isZero()) { + STORM_LOG_TRACE("Did not find pivot state in qualitative fragment."); return false; } STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to proceed without pivot state candidates."); // Now that we have the pivot state candidates, we need to pick one. - PivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); - + SymbolicPivotStateResult symbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, qualitativeResult, boost::none); + +// // SANITY CHECK TO MAKE SURE OUR STRATEGIES ARE NOT BROKEN. +// // FIXME. +// auto min1ChoiceInPivot = SymbolicPivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy; +// STORM_LOG_ASSERT(!min1ChoiceInPivot.isZero(), "wth?"); +// bool min1ChoiceInPivotIsProb0Min = !(min1ChoiceInPivot && qualitativeResult.prob0Min.getPlayer2States()).isZero(); +// bool min1ChoiceInPivotIsProb0Max = !(min1ChoiceInPivot && qualitativeResult.prob0Max.getPlayer2States()).isZero(); +// bool min1ChoiceInPivotIsProb1Min = !(min1ChoiceInPivot && qualitativeResult.prob1Min.getPlayer2States()).isZero(); +// bool min1ChoiceInPivotIsProb1Max = !(min1ChoiceInPivot && qualitativeResult.prob1Max.getPlayer2States()).isZero(); +// std::cout << "after redirection (min)" << std::endl; +// std::cout << "min choice is prob0 in min? " << min1ChoiceInPivotIsProb0Min << ", max? " << min1ChoiceInPivotIsProb0Max << std::endl; +// std::cout << "min choice is prob1 in min? " << min1ChoiceInPivotIsProb1Min << ", max? " << min1ChoiceInPivotIsProb1Max << std::endl; +// std::cout << "min" << std::endl; +// for (auto const& e : (min1ChoiceInPivot && minPlayer2Strategy).template toAdd()) { +// std::cout << e.first << " -> " << e.second << std::endl; +// } +// std::cout << "max" << std::endl; +// for (auto const& e : (min1ChoiceInPivot && maxPlayer2Strategy).template toAdd()) { +// std::cout << e.first << " -> " << e.second << std::endl; +// } +// bool different = (min1ChoiceInPivot && minPlayer2Strategy) != (min1ChoiceInPivot && maxPlayer2Strategy); +// std::cout << "min/max choice of player 2 is different? " << different << std::endl; +// bool min1MinPlayer2Choice = !(min1ChoiceInPivot && minPlayer2Strategy).isZero(); +// bool min1MaxPlayer2Choice = !(min1ChoiceInPivot && maxPlayer2Strategy).isZero(); +// std::cout << "max/min choice there? " << min1MinPlayer2Choice << std::endl; +// std::cout << "max/max choice there? " << min1MaxPlayer2Choice << std::endl; +// +// auto max1ChoiceInPivot = SymbolicPivotStateResult.pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy; +// STORM_LOG_ASSERT(!max1ChoiceInPivot.isZero(), "wth?"); +// bool max1ChoiceInPivotIsProb0Min = !(max1ChoiceInPivot && qualitativeResult.prob0Min.getPlayer2States()).isZero(); +// bool max1ChoiceInPivotIsProb0Max = !(max1ChoiceInPivot && qualitativeResult.prob0Max.getPlayer2States()).isZero(); +// bool max1ChoiceInPivotIsProb1Min = !(max1ChoiceInPivot && qualitativeResult.prob1Min.getPlayer2States()).isZero(); +// bool max1ChoiceInPivotIsProb1Max = !(max1ChoiceInPivot && qualitativeResult.prob1Max.getPlayer2States()).isZero(); +// std::cout << "after redirection (max)" << std::endl; +// std::cout << "max choice is prob0 in min? " << max1ChoiceInPivotIsProb0Min << ", max? " << max1ChoiceInPivotIsProb0Max << std::endl; +// std::cout << "max choice is prob1 in min? " << max1ChoiceInPivotIsProb1Min << ", max? " << max1ChoiceInPivotIsProb1Max << std::endl; +// different = (max1ChoiceInPivot && minPlayer2Strategy) != (max1ChoiceInPivot && maxPlayer2Strategy); +// std::cout << "min/max choice of player 2 is different? " << different << std::endl; +// bool max1MinPlayer2Choice = !(max1ChoiceInPivot && minPlayer2Strategy).isZero(); +// bool max1MaxPlayer2Choice = !(max1ChoiceInPivot && maxPlayer2Strategy).isZero(); +// std::cout << "max/min choice there? " << max1MinPlayer2Choice << std::endl; +// std::cout << "max/max choice there? " << max1MaxPlayer2Choice << std::endl; + boost::optional predicates; if (useInterpolation) { - predicates = derivePredicatesFromInterpolation(game, pivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } if (predicates) { STORM_LOG_TRACE("Obtained predicates by interpolation."); } else { - predicates = derivePredicatesFromPivotState(game, pivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); @@ -615,8 +1038,449 @@ namespace storm { return true; } + template + struct ExplicitDijkstraQueueElement { + ExplicitDijkstraQueueElement(ValueType const& distance, uint64_t state, bool lower) : distance(distance), state(state), lower(lower) { + // Intentionally left empty. + } + + ValueType distance; + uint64_t state; + bool lower; + }; + + template + struct ExplicitDijkstraQueueElementLess { + bool operator()(ExplicitDijkstraQueueElement const& a, ExplicitDijkstraQueueElement const& b) const { + if (a.distance < b.distance) { + return true; + } else if (a.distance > b.distance) { + return false; + } else { + if (a.state < b.state) { + return true; + } else if (a.state > b.state) { + return false; + } else { + if (a.lower < b.lower) { + return true; + } else { + return false; + } + } + } + } + }; + + template + void performDijkstraStep(std::set, ExplicitDijkstraQueueElementLess>& dijkstraQueue, bool probabilityDistances, std::vector& distances, std::vector>& predecessors, bool generatePredecessors, bool lower, uint64_t currentState, ValueType const& currentDistance, bool isPivotState, ExplicitGameStrategyPair const& strategyPair, ExplicitGameStrategyPair const& otherStrategyPair, std::vector const& player1Labeling, std::vector const& player2Grouping, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& relevantStates) { + if (strategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2Successor = strategyPair.getPlayer1Strategy().getChoice(currentState); + uint64_t player2Choice = strategyPair.getPlayer2Strategy().getChoice(player2Successor); + STORM_LOG_ASSERT(isPivotState || !otherStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) || strategyPair.getPlayer2Strategy().getChoice(player2Successor) == player2Choice, "Did not expect deviation in player 2 strategy."); + STORM_LOG_ASSERT(player2Grouping[player2Successor] <= player2Choice && player2Choice < player2Grouping[player2Successor + 1], "Illegal choice for player 2."); + + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + uint64_t player1Successor = entry.getColumn(); + if (!relevantStates.get(player1Successor)) { + continue; + } + + ValueType alternateDistance; + if (probabilityDistances) { + alternateDistance = currentDistance * entry.getValue(); + } else { + alternateDistance = currentDistance + storm::utility::one(); + } + if (probabilityDistances ? alternateDistance > distances[player1Successor] : alternateDistance < distances[player1Successor]) { + distances[player1Successor] = alternateDistance; + if (generatePredecessors) { + predecessors[player1Successor] = std::make_pair(currentState, player1Labeling[player2Successor]); + } + dijkstraQueue.emplace(alternateDistance, player1Successor, lower); + } + } + } else { + STORM_LOG_ASSERT(targetStates.get(currentState), "Expecting min strategy for non-target states."); + } + } + + template + boost::optional> pickPivotState(bool generatePredecessors, AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& relevantStates, storm::storage::BitVector const& targetStates, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair, std::vector const* lowerValues = nullptr, std::vector const* upperValues = nullptr) { + + STORM_LOG_ASSERT(!lowerValues || upperValues, "Expected none or both value results."); + STORM_LOG_ASSERT(!upperValues || lowerValues, "Expected none or both value results."); + + // Perform Dijkstra search that stays within the relevant states and searches for a (pivot) state in which + // the strategies the lower or upper player 1 action leads to a player 2 state in which the choices differ. + // To guarantee that the pivot state is reachable by either of the strategies, we do a parallel Dijkstra + // search in both the lower and upper strategy. + + bool probabilityDistances = pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MostProbablePath; + uint64_t numberOfStates = initialStates.size(); + ValueType inftyDistance = probabilityDistances ? storm::utility::zero() : storm::utility::infinity(); + ValueType zeroDistance = probabilityDistances ? storm::utility::one() : storm::utility::zero(); + + // Create storages for the lower and upper Dijkstra search. + std::vector lowerDistances(numberOfStates, inftyDistance); + std::vector> lowerPredecessors; + std::vector upperDistances(numberOfStates, inftyDistance); + std::vector> upperPredecessors; + + if (generatePredecessors) { + lowerPredecessors.resize(numberOfStates, std::make_pair(ExplicitPivotStateResult::NO_PREDECESSOR, ExplicitPivotStateResult::NO_PREDECESSOR)); + upperPredecessors.resize(numberOfStates, std::make_pair(ExplicitPivotStateResult::NO_PREDECESSOR, ExplicitPivotStateResult::NO_PREDECESSOR)); + } + + // Use set as priority queue with unique membership. + std::set, ExplicitDijkstraQueueElementLess> dijkstraQueue; + + for (auto initialState : initialStates) { + if (!relevantStates.get(initialState)) { + continue; + } + + lowerDistances[initialState] = zeroDistance; + upperDistances[initialState] = zeroDistance; + dijkstraQueue.emplace(zeroDistance, initialState, true); + dijkstraQueue.emplace(zeroDistance, initialState, false); + } + + // For some heuristics, we need to potentially find more than just one pivot. + bool considerDeviation = (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::NearestMaximalDeviation || pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) && lowerValues && upperValues; + bool foundPivotState = false; + + ExplicitDijkstraQueueElement pivotState(inftyDistance, 0, true); + ValueType pivotStateDeviation = storm::utility::zero(); + auto const& player2Grouping = transitionMatrix.getRowGroupIndices(); + + while (!dijkstraQueue.empty()) { + // Take out currently best state. + auto currentDijkstraElement = *dijkstraQueue.begin(); + ValueType currentDistance = currentDijkstraElement.distance; + uint64_t currentState = currentDijkstraElement.state; + bool currentLower = currentDijkstraElement.lower; + dijkstraQueue.erase(dijkstraQueue.begin()); + + if (foundPivotState && (probabilityDistances ? currentDistance < pivotState.distance : currentDistance > pivotState.distance)) { + if (pivotSelectionHeuristic != storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) { + // For the nearest maximal deviation and most probable path heuristics, future pivot states are + // not important any more, because their distance will be strictly larger, so we can return the + // current pivot state. + + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); + } else if (pivotStateDeviation >= currentDistance) { + // If the heuristic is maximal weighted deviation and the weighted deviation for any future pivot + // state is necessarily at most as high as the current one, we can abort the search. + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); + } + } + + // Determine whether the current state is a pivot state. + bool isPivotState = false; + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2Successor = minStrategyPair.getPlayer1Strategy().getChoice(currentState); + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { + isPivotState = true; + } + } + if (!isPivotState && maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(currentState)) { + uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2Successor) && minStrategyPair.getPlayer2Strategy().getChoice(player2Successor) != maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor)) { + isPivotState = true; + } + } + + // If it is indeed a pivot state, we can potentially abort the search here. + if (isPivotState) { + if (considerDeviation && foundPivotState) { + ValueType deviationOfCurrentState = (*upperValues)[currentState] - (*lowerValues)[currentState]; + + if (deviationOfCurrentState > pivotStateDeviation) { + pivotState = currentDijkstraElement; + pivotStateDeviation = deviationOfCurrentState; + if (pivotSelectionHeuristic == storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic::MaxWeightedDeviation) { + // Scale the deviation with the distance (probability) for this heuristic. + pivotStateDeviation *= currentDistance; + } + } + } else if (!foundPivotState) { + pivotState = currentDijkstraElement; + foundPivotState = true; + } + + // If there is no need to look at other deviations, stop here. + if (!considerDeviation) { + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); + } + } + + // We only need to search further if the state has some value deviation. + if (!lowerValues || !upperValues || (*lowerValues)[currentState] < (*upperValues)[currentState]) { + if (currentLower) { + performDijkstraStep(dijkstraQueue, probabilityDistances, lowerDistances, lowerPredecessors, generatePredecessors, true, currentState, currentDistance, isPivotState, minStrategyPair, maxStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); + } else { + performDijkstraStep(dijkstraQueue, probabilityDistances, upperDistances, upperPredecessors, generatePredecessors, false, currentState, currentDistance, isPivotState, maxStrategyPair, minStrategyPair, player1Labeling, player2Grouping, transitionMatrix, targetStates, relevantStates); + } + } + } + + if (foundPivotState) { + return ExplicitPivotStateResult(pivotState.state, pivotState.distance, pivotState.lower ? std::move(lowerPredecessors) : std::move(upperPredecessors)); + } + + // If we arrived at this point, we have explored all relevant states, but none of them was a pivot state, + // which can happen when trying to refine using the qualitative result only. + STORM_LOG_TRACE("Did not find pivot state in explicit Dijkstra search."); + return boost::none; + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolationReversedPath(storm::dd::Odd const& odd, storm::expressions::ExpressionManager& interpolationManager, std::vector const& reversedPath, std::vector const& stateToOffset, std::vector const& reversedLabels) const { + + // Build the trace of the most probable path in terms of which predicates hold in each step. + auto start = std::chrono::high_resolution_clock::now(); + std::pair>, std::map> traceAndVariableSubstitution = buildTraceFromReversedLabeledPath(interpolationManager, reversedPath, reversedLabels, odd, &stateToOffset); + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_DEBUG("Building the trace and variable substitution for interpolation from explicit most-probable paths result took " << std::chrono::duration_cast(end - start).count() << "ms."); + + return derivePredicatesFromInterpolationFromTrace(interpolationManager, traceAndVariableSubstitution.first, traceAndVariableSubstitution.second); + } + + template + boost::optional MenuGameRefiner::derivePredicatesFromInterpolationKShortestPaths(storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ValueType minProbability, ValueType maxProbability, ExplicitGameStrategyPair const& maxStrategyPair) const { + + // Extract the underlying DTMC of the max strategy pair. + + // Start by determining which states are reachable. + storm::storage::BitVector reachableStatesInMaxFragment(initialStates); + std::vector stack(initialStates.begin(), initialStates.end()); + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor); + for (auto const& successorEntry : transitionMatrix.getRow(player2Choice)) { + if (!reachableStatesInMaxFragment.get(successorEntry.getColumn())) { + reachableStatesInMaxFragment.set(successorEntry.getColumn()); + if (!targetStates.get(successorEntry.getColumn())) { + stack.push_back(successorEntry.getColumn()); + } + } + } + } + + uint64_t numberOfReachableStates = reachableStatesInMaxFragment.getNumberOfSetBits(); + std::vector reachableStatesWithLowerIndex = reachableStatesInMaxFragment.getNumberOfSetBitsBeforeIndices(); + + // Now construct the matrix just for these entries. + storm::storage::SparseMatrixBuilder builder(numberOfReachableStates, numberOfReachableStates); + storm::storage::BitVector dtmcInitialStates(numberOfReachableStates); + typename storm::utility::ksp::ShortestPathsGenerator::StateProbMap targetProbabilities; + std::vector stateToOffset(numberOfReachableStates); + std::vector dtmcPlayer1Labels(numberOfReachableStates); + uint64_t currentRow = 0; + for (auto currentState : reachableStatesInMaxFragment) { + stateToOffset[currentRow] = currentState; + if (targetStates.get(currentState)) { + targetProbabilities[currentRow] = storm::utility::one(); + builder.addNextValue(currentRow, currentRow, storm::utility::one()); + } else { + uint64_t player2Successor = maxStrategyPair.getPlayer1Strategy().getChoice(currentState); + dtmcPlayer1Labels[currentRow] = player1Labeling[player2Successor]; + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2Successor); + + for (auto const& successorEntry : transitionMatrix.getRow(player2Choice)) { + builder.addNextValue(currentRow, reachableStatesWithLowerIndex[successorEntry.getColumn()], successorEntry.getValue()); + } + } + + if (initialStates.get(currentState)) { + dtmcInitialStates.set(currentRow); + } + ++currentRow; + } + storm::storage::SparseMatrix dtmcMatrix = builder.build(); + + // Create a new expression manager that we can use for the interpolation. + AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); + std::shared_ptr interpolationManager = abstractionInformation.getExpressionManager().clone(); + + // Use a path generator to compute k-shortest-paths. + storm::utility::ksp::ShortestPathsGenerator pathGenerator(dtmcMatrix, targetProbabilities, dtmcInitialStates, storm::utility::ksp::MatrixFormat::straight); + uint64_t currentShortestPath = 1; + bool considerNextPath = true; + + boost::optional result; + + while (currentShortestPath < 100 && considerNextPath) { + auto reversedPath = pathGenerator.getPathAsList(currentShortestPath); + std::vector reversedLabels; + for (auto stateIt = reversedPath.rbegin(); stateIt != reversedPath.rend() - 1; ++stateIt) { + reversedLabels.push_back(player1Labeling[maxStrategyPair.getPlayer1Strategy().getChoice(stateToOffset[*stateIt])]); + } + + boost::optional pathPredicates = derivePredicatesFromInterpolationReversedPath(odd, *interpolationManager, reversedPath, stateToOffset, reversedLabels); + if (pathPredicates) { + if (!result) { + result = RefinementPredicates(RefinementPredicates::Source::Interpolation, pathPredicates.get().getPredicates()); + } else { + result.get().addPredicates(pathPredicates.get().getPredicates()); + } + } + ++currentShortestPath; + } + + exit(-1); + return result; + } + + template + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { + +// boost::optional kShortestPathPredicates = derivePredicatesFromInterpolationKShortestPaths(odd, transitionMatrix, player1Grouping, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, storm::utility::zero(), storm::utility::one(), maxStrategyPair); + + // Compute the set of states whose result we have for the min and max case. + storm::storage::BitVector relevantStates = (qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()) & (qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); + + boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, minStrategyPair, maxStrategyPair); + + // If there was no pivot state, continue the search. + if (!optionalPivotStateResult) { + STORM_LOG_TRACE("Did not find pivot state in qualitative fragment."); + return false; + } + + // Otherwise, we can refine. + auto const& pivotStateResult = optionalPivotStateResult.get(); + STORM_LOG_TRACE("Found pivot state " << pivotStateResult.pivotState << " with distance " << pivotStateResult.distance << "."); + + // Translate the explicit states/choices to the symbolic ones, so we can reuse the predicate derivation techniques. + auto const& abstractionInformation = abstractor.get().getAbstractionInformation(); + uint64_t pivotState = pivotStateResult.pivotState; + storm::dd::Bdd symbolicPivotState = storm::dd::Bdd::getEncoding(game.getManager(), pivotState, odd, game.getRowVariables()); + storm::dd::Bdd minPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd minPlayer2Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer2Strategy = game.getManager().getBddZero(); + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + minPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + maxPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + auto end = std::chrono::high_resolution_clock::now(); + + boost::optional predicates; + if (useInterpolation) { + predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); + } + if (!predicates) { + predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + } + end = std::chrono::high_resolution_clock::now(); + STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); + + std::vector preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource()); + performRefinement(createGlobalRefinement(preparedPredicates)); + return true; + } + template - bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QuantitativeGameResultMinMax const& quantitativeResult) const { + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const { + +// ValueType lower = quantitativeResult.getMin().getRange(initialStates).first; +// ValueType upper = quantitativeResult.getMax().getRange(initialStates).second; + +// boost::optional kShortestPathPredicates = derivePredicatesFromInterpolationKShortestPaths(odd, transitionMatrix, player1Grouping, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, lower, upper, maxStrategyPair); + + // Compute the set of states whose result we have for the min and max case. + storm::storage::BitVector relevantStates(odd.getTotalOffset(), true); + + boost::optional> optionalPivotStateResult = pickPivotState(useInterpolation, pivotSelectionHeuristic, transitionMatrix, player1Grouping, player1Labeling, initialStates, relevantStates, targetStates, minStrategyPair, maxStrategyPair, &quantitativeResult.getMin().getValues(), &quantitativeResult.getMax().getValues()); + + STORM_LOG_THROW(optionalPivotStateResult, storm::exceptions::InvalidStateException, "Did not find pivot state to proceed."); + + // Otherwise, we can refine. + auto const& pivotStateResult = optionalPivotStateResult.get(); + STORM_LOG_TRACE("Found pivot state " << pivotStateResult.pivotState << " with distance " << pivotStateResult.distance << "."); + + // Translate the explicit states/choices to the symbolic ones, so we can reuse the predicate derivation techniques. + auto const& abstractionInformation = abstractor.get().getAbstractionInformation(); + uint64_t pivotState = pivotStateResult.pivotState; + storm::dd::Bdd symbolicPivotState = storm::dd::Bdd::getEncoding(game.getManager(), pivotState, odd, game.getRowVariables()); + storm::dd::Bdd minPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer1Strategy = game.getManager().getBddZero(); + storm::dd::Bdd minPlayer2Strategy = game.getManager().getBddZero(); + storm::dd::Bdd maxPlayer2Strategy = game.getManager().getBddZero(); + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = minStrategyPair.getPlayer1Strategy().getChoice(pivotState); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + minPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= minPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(pivotState)) { + uint64_t player2State = maxStrategyPair.getPlayer1Strategy().getChoice(pivotState); + STORM_LOG_ASSERT(player1Grouping[pivotState] <= player2State && player2State < player1Grouping[pivotState + 1], "Illegal choice for player 1."); + maxPlayer1Strategy |= symbolicPivotState && abstractionInformation.encodePlayer1Choice(player1Labeling[player2State], abstractionInformation.getPlayer1VariableCount()); + + if (minStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(player2State); + minPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(player2State)) { + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(player2State); + maxPlayer2Strategy |= maxPlayer1Strategy && abstractionInformation.encodePlayer2Choice(player2Labeling[player2Choice], 0, game.getPlayer2Variables().size()); + } + } + + boost::optional predicates; + if (useInterpolation) { + predicates = derivePredicatesFromInterpolation(game, pivotStateResult, odd); + } + if (!predicates) { + predicates = derivePredicatesFromPivotState(game, symbolicPivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + } + STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); + + std::vector preparedPredicates = preprocessPredicates(predicates.get().getPredicates(), predicates.get().getSource()); + performRefinement(createGlobalRefinement(preparedPredicates)); + return true; + } + + template + bool MenuGameRefiner::refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQuantitativeGameResultMinMax const& quantitativeResult) const { STORM_LOG_TRACE("Refining after quantitative check."); // Get all relevant strategies. storm::dd::Bdd minPlayer1Strategy = quantitativeResult.min.getPlayer1Strategy(); @@ -630,16 +1494,16 @@ namespace storm { STORM_LOG_ASSERT(!pivotStateCandidatesResult.pivotStates.isZero(), "Unable to refine without pivot state candidates."); // Now that we have the pivot state candidates, we need to pick one. - PivotStateResult pivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult); + SymbolicPivotStateResult symbolicPivotStateResult = pickPivotState(pivotSelectionHeuristic, game, pivotStateCandidatesResult, boost::none, quantitativeResult); boost::optional predicates; if (useInterpolation) { - predicates = derivePredicatesFromInterpolation(game, pivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromInterpolation(game, symbolicPivotStateResult, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } if (predicates) { STORM_LOG_TRACE("Obtained predicates by interpolation."); } else { - predicates = derivePredicatesFromPivotState(game, pivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); + predicates = derivePredicatesFromPivotState(game, symbolicPivotStateResult.pivotState, minPlayer1Strategy, minPlayer2Strategy, maxPlayer1Strategy, maxPlayer2Strategy); } STORM_LOG_THROW(static_cast(predicates), storm::exceptions::InvalidStateException, "Predicates needed to continue."); @@ -648,6 +1512,12 @@ namespace storm { return true; } + struct VariableSetHash { + std::size_t operator()(std::set const& set) const { + return set.size(); + } + }; + template std::vector MenuGameRefiner::preprocessPredicates(std::vector const& predicates, RefinementPredicates::Source const& source) const { bool split = source == RefinementPredicates::Source::WeakestPrecondition && splitPredicates; @@ -655,38 +1525,84 @@ namespace storm { split |= splitAll; if (split) { + auto start = std::chrono::high_resolution_clock::now(); AbstractionInformation const& abstractionInformation = abstractor.get().getAbstractionInformation(); std::vector cleanedAtoms; + std::unordered_map, std::vector, VariableSetHash> predicateClasses; + for (auto const& predicate : predicates) { - // Split the predicates. std::vector atoms = splitter.split(predicate); - // Check which of the atoms are redundant in the sense that they are equivalent to a predicate we already have. + // Put the atoms into the right class. for (auto const& atom : atoms) { - // Check whether the newly found atom is equivalent to an atom we already have in the predicate - // set or in the set that is to be added. - bool addAtom = true; - for (auto const& oldPredicate : abstractionInformation.getPredicates()) { - if (equivalenceChecker.areEquivalent(atom, oldPredicate)) { - addAtom = false; + std::set vars = atom.getVariables(); + predicateClasses[vars].push_back(atom); + } + } + + // Now clean the classes in the sense that redundant predicates are cleaned. + uint64_t checkCounter = 0; + for (auto& predicateClass : predicateClasses) { + std::vector cleanedAtomsOfClass; + + for (auto const& predicate : predicateClass.second) { + bool addPredicate = true; + for (auto const& atom : cleanedAtomsOfClass) { + if (predicate.areSame(atom)) { + addPredicate = false; break; } - } - for (auto const& addedAtom : cleanedAtoms) { - if (equivalenceChecker.areEquivalent(addedAtom, atom)) { - addAtom = false; + + ++checkCounter; + if (equivalenceChecker.areEquivalentModuloNegation(predicate, atom)) { + addPredicate = false; break; } } - - if (addAtom) { - cleanedAtoms.push_back(atom); + if (addPredicate) { + cleanedAtomsOfClass.push_back(predicate); } } + + predicateClass.second = std::move(cleanedAtomsOfClass); + } + + std::unordered_map, std::vector, VariableSetHash> oldPredicateClasses; + for (auto const& oldPredicate : abstractionInformation.getPredicates()) { + std::set vars = oldPredicate.getVariables(); + + oldPredicateClasses[vars].push_back(oldPredicate); } + for (auto const& predicateClass : predicateClasses) { + auto oldPredicateClassIt = oldPredicateClasses.find(predicateClass.first); + if (oldPredicateClassIt != oldPredicateClasses.end()) { + for (auto const& newAtom : predicateClass.second) { + bool addAtom = true; + for (auto const& oldPredicate : oldPredicateClassIt->second) { + if (newAtom.areSame(oldPredicate)) { + addAtom = false; + break; + } + ++checkCounter; + if (equivalenceChecker.areEquivalentModuloNegation(newAtom, oldPredicate)) { + addAtom = false; + break; + } + } + if (addAtom) { + cleanedAtoms.push_back(newAtom); + } + } + } else { + cleanedAtoms.insert(cleanedAtoms.end(), predicateClass.second.begin(), predicateClass.second.end()); + } + } + auto end = std::chrono::high_resolution_clock::now(); + STORM_LOG_TRACE("Preprocessing predicates took " << std::chrono::duration_cast(end - start).count() << "ms (" << checkCounter << " checks)."); + return cleanedAtoms; } else { // If no splitting of the predicates is required, just forward the refinement request to the abstractor. @@ -703,13 +1619,26 @@ namespace storm { } template - void MenuGameRefiner::performRefinement(std::vector const& refinementCommands) const { - for (auto const& command : refinementCommands) { - STORM_LOG_TRACE("Refining with " << command.getPredicates().size() << " predicates."); - for (auto const& predicate : command.getPredicates()) { - STORM_LOG_TRACE(predicate); + void MenuGameRefiner::performRefinement(std::vector const& refinementCommands, bool allowInjection) const { + if (!refinementPredicatesToInject.empty() && allowInjection) { + STORM_LOG_INFO("Refining with (injected) predicates."); + + for (auto const& predicate : refinementPredicatesToInject.back()) { + STORM_LOG_INFO(predicate); + } + + abstractor.get().refine(RefinementCommand(refinementPredicatesToInject.back())); + refinementPredicatesToInject.pop_back(); + } else { + for (auto const& command : refinementCommands) { + STORM_LOG_INFO("Refining with " << command.getPredicates().size() << " predicates."); + for (auto const& predicate : command.getPredicates()) { + STORM_LOG_INFO(predicate); + } + if (!command.getPredicates().empty()) { + abstractor.get().refine(command); + } } - abstractor.get().refine(command); } STORM_LOG_TRACE("Current set of predicates:"); @@ -725,6 +1654,7 @@ namespace storm { template class MenuGameRefiner; template class MenuGameRefiner; + template class MenuGameRefiner; #ifdef STORM_HAVE_CARL // Currently, this instantiation does not work. diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h index c0a4b8f8a..c8a384057 100644 --- a/src/storm/abstraction/MenuGameRefiner.h +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -7,8 +7,8 @@ #include #include "storm/abstraction/RefinementCommand.h" -#include "storm/abstraction/QualitativeGameResultMinMax.h" -#include "storm/abstraction/QuantitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQuantitativeGameResultMinMax.h" #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/FullPredicateSplitter.h" @@ -21,6 +21,14 @@ #include "storm/utility/solver.h" namespace storm { + namespace dd { + class Odd; + } + + namespace storage { + class BitVector; + } + namespace abstraction { template @@ -32,7 +40,7 @@ namespace storm { class RefinementPredicates { public: enum class Source { - WeakestPrecondition, InitialGuard, Guard, Interpolation, Manual + WeakestPrecondition, InitialGuard, InitialExpression, Guard, Interpolation, Manual }; RefinementPredicates() = default; @@ -48,21 +56,56 @@ namespace storm { }; template - struct MostProbablePathsResult { - MostProbablePathsResult() = default; - MostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree); + struct SymbolicMostProbablePathsResult { + SymbolicMostProbablePathsResult() = default; + SymbolicMostProbablePathsResult(storm::dd::Add const& maxProbabilities, storm::dd::Bdd const& spanningTree); storm::dd::Add maxProbabilities; storm::dd::Bdd spanningTree; }; template - struct PivotStateResult { - PivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& mostProbablePathsResult = boost::none); + struct SymbolicPivotStateResult { + SymbolicPivotStateResult(storm::dd::Bdd const& pivotState, storm::OptimizationDirection fromDirection, boost::optional> const& symbolicMostProbablePathsResult = boost::none); storm::dd::Bdd pivotState; storm::OptimizationDirection fromDirection; - boost::optional> mostProbablePathsResult; + boost::optional> symbolicMostProbablePathsResult; + }; + + template + struct ExplicitPivotStateResult { + ExplicitPivotStateResult() = default; + ExplicitPivotStateResult(uint64_t pivotState, ValueType distance, std::vector>&& predecessors) : pivotState(pivotState), distance(distance), predecessors(std::move(predecessors)) { + // Intentionally left empty. + } + + uint64_t pivotState; + + /// The distance with which the state in question is reached. + ValueType distance; + + /// The value filled in for states without predecessors in the search. + static const uint64_t NO_PREDECESSOR; + + /// The predecessors for the states to obtain the given distance. + std::vector> predecessors; + }; + + class ExplicitQualitativeGameResultMinMax; + class ExplicitGameStrategyPair; + + template + class ExplicitQuantitativeResultMinMax; + + struct MenuGameRefinerOptions { + MenuGameRefinerOptions() = default; + + MenuGameRefinerOptions(std::vector>&& refinementPredicates) : refinementPredicates(std::move(refinementPredicates)) { + // Intentionally left empty. + } + + std::vector> refinementPredicates; }; template @@ -71,28 +114,44 @@ namespace storm { /*! * Creates a refiner for the provided abstractor. */ - MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver); + MenuGameRefiner(MenuGameAbstractor& abstractor, std::unique_ptr&& smtSolver, MenuGameRefinerOptions const& options = MenuGameRefinerOptions()); /*! * Refines the abstractor with the given predicates. * * @param predicates The predicates to use for refinement. + * @param allowInjection If true, the refiner is free to inject manually-specified refinement predicates + * instead of the provided ones. */ - void refine(std::vector const& predicates) const; + void refine(std::vector const& predicates, bool allowInjection = true) const; /*! * Refines the abstractor based on the qualitative result by trying to derive suitable predicates. * * @param True if predicates for refinement could be derived, false otherwise. */ - bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QualitativeGameResultMinMax const& qualitativeResult) const; + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQualitativeGameResultMinMax const& qualitativeResult) const; + + /*! + * Refines the abstractor based on the qualitative result by trying to derive suitable predicates. + * + * @param True if predicates for refinement could be derived, false otherwise. + */ + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const; + + /*! + * Refines the abstractor based on the qualitative result by trying to derive suitable predicates. + * + * @param True if predicates for refinement could be derived, false otherwise. + */ + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& qualitativeResult, ExplicitGameStrategyPair const& minStrategyPair, ExplicitGameStrategyPair const& maxStrategyPair) const; /*! * Refines the abstractor based on the quantitative result by trying to derive suitable predicates. * * @param True if predicates for refinement could be derived, false otherwise. */ - bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, QuantitativeGameResultMinMax const& quantitativeResult) const; + bool refine(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& transitionMatrixBdd, SymbolicQuantitativeGameResultMinMax const& quantitativeResult) const; /*! * Retrieves whether all guards were added. @@ -101,6 +160,7 @@ namespace storm { private: RefinementPredicates derivePredicatesFromDifferingChoices(storm::dd::Bdd const& player1Choice, storm::dd::Bdd const& lowerChoice, storm::dd::Bdd const& upperChoice) const; + RefinementPredicates derivePredicatesFromChoice(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& pivotState, storm::dd::Bdd const& player1Choice, storm::dd::Bdd const& choice, storm::dd::Bdd const& choiceSuccessors) const; RefinementPredicates derivePredicatesFromPivotState(storm::abstraction::MenuGame const& game, storm::dd::Bdd const& pivotState, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; /*! @@ -113,10 +173,19 @@ namespace storm { */ std::vector createGlobalRefinement(std::vector const& predicates) const; - boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, PivotStateResult const& pivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; + boost::optional derivePredicatesFromInterpolationFromTrace(storm::expressions::ExpressionManager& interpolationManager, std::vector> const& trace, std::map const& variableSubstitution) const; + + boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, SymbolicPivotStateResult const& symbolicPivotStateResult, storm::dd::Bdd const& minPlayer1Strategy, storm::dd::Bdd const& minPlayer2Strategy, storm::dd::Bdd const& maxPlayer1Strategy, storm::dd::Bdd const& maxPlayer2Strategy) const; std::pair>, std::map> buildTrace(storm::expressions::ExpressionManager& expressionManager, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& spanningTree, storm::dd::Bdd const& pivotState) const; - void performRefinement(std::vector const& refinementCommands) const; + std::pair, std::vector> buildReversedLabeledPath(ExplicitPivotStateResult const& pivotStateResult) const; + std::pair>, std::map> buildTraceFromReversedLabeledPath(storm::expressions::ExpressionManager& expressionManager, std::vector const& reversedPath, std::vector const& reversedLabels, storm::dd::Odd const& odd, std::vector const* stateToOffset = nullptr) const; + boost::optional derivePredicatesFromInterpolation(storm::abstraction::MenuGame const& game, ExplicitPivotStateResult const& pivotStateResult, storm::dd::Odd const& odd) const; + + boost::optional derivePredicatesFromInterpolationKShortestPaths(storm::dd::Odd const& odd, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Grouping, std::vector const& player1Labeling, std::vector const& player2Labeling, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ValueType minProbability, ValueType maxProbability, ExplicitGameStrategyPair const& maxStrategyPair) const; + boost::optional derivePredicatesFromInterpolationReversedPath(storm::dd::Odd const& odd, storm::expressions::ExpressionManager& interpolationManager, std::vector const& reversedPath, std::vector const& stateToOffset, std::vector const& player1Labels) const; + + void performRefinement(std::vector const& refinementCommands, bool allowInjection = true) const; /// The underlying abstractor to refine. std::reference_wrapper> abstractor; @@ -130,9 +199,19 @@ namespace storm { /// A flag indicating whether predicates derived from weakest preconditions shall be split before using them for refinement. bool splitPredicates; + /// A flag indicating whether predicates are to be ranked. + bool rankPredicates; + + /// A flag indicating whether predicates are to be generated eagerly. + bool addPredicatesEagerly; + /// A flag indicating whether all guards have been used to refine the abstraction. bool addedAllGuardsFlag; + /// A vector of vectors of refinement predicates that are injected (starting with the *last* one in this + /// list). If empty, the predicates are derived as usual. + mutable std::vector> refinementPredicatesToInject; + /// The heuristic to use for pivot block selection. storm::settings::modules::AbstractionSettings::PivotSelectionHeuristic pivotSelectionHeuristic; diff --git a/src/storm/abstraction/QualitativeGameResult.h b/src/storm/abstraction/QualitativeGameResult.h deleted file mode 100644 index ff3c6e44c..000000000 --- a/src/storm/abstraction/QualitativeGameResult.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "storm/utility/graph.h" -#include "storm/abstraction/QualitativeResult.h" - -namespace storm { - namespace abstraction { - - template - struct QualitativeGameResult : public storm::utility::graph::GameProb01Result, public QualitativeResult { - QualitativeGameResult() = default; - - QualitativeGameResult(storm::utility::graph::GameProb01Result const& prob01Result) : storm::utility::graph::GameProb01Result(prob01Result) { - // Intentionally left empty. - } - - virtual storm::dd::Bdd const& getStates() const override { - return this->getPlayer1States(); - } - - }; - - } -} diff --git a/src/storm/abstraction/QualitativeGameResultMinMax.h b/src/storm/abstraction/QualitativeGameResultMinMax.h deleted file mode 100644 index c40338185..000000000 --- a/src/storm/abstraction/QualitativeGameResultMinMax.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "storm/storage/dd/DdType.h" - -#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" -#include "storm/abstraction/QualitativeGameResult.h" - -namespace storm { - namespace abstraction { - - template - class QualitativeGameResultMinMax : public SymbolicQualitativeResultMinMax { - public: - QualitativeGameResultMinMax() = default; - - virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob0Min; - } else { - return prob0Max; - } - } - - virtual QualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob1Min; - } else { - return prob1Max; - } - } - - QualitativeGameResult prob0Min; - QualitativeGameResult prob1Min; - QualitativeGameResult prob0Max; - QualitativeGameResult prob1Max; - }; - - } -} diff --git a/src/storm/abstraction/QualitativeMdpResult.h b/src/storm/abstraction/QualitativeMdpResult.h deleted file mode 100644 index 9fc1fcc0e..000000000 --- a/src/storm/abstraction/QualitativeMdpResult.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "storm/abstraction/QualitativeResult.h" - -namespace storm { - namespace abstraction { - - template - struct QualitativeMdpResult : public QualitativeResult { - QualitativeMdpResult() = default; - - QualitativeMdpResult(storm::dd::Bdd const& states) : states(states) { - // Intentionally left empty. - } - - virtual storm::dd::Bdd const& getStates() const override { - return states; - } - - storm::dd::Bdd states; - }; - - } -} - diff --git a/src/storm/abstraction/QualitativeMdpResultMinMax.h b/src/storm/abstraction/QualitativeMdpResultMinMax.h deleted file mode 100644 index 9f2a3c130..000000000 --- a/src/storm/abstraction/QualitativeMdpResultMinMax.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "storm/storage/dd/DdType.h" - -#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" -#include "storm/abstraction/QualitativeMdpResult.h" - -namespace storm { - namespace abstraction { - - template - class QualitativeMdpResultMinMax : public SymbolicQualitativeResultMinMax { - public: - QualitativeMdpResultMinMax() = default; - - virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob0Min; - } else { - return prob0Max; - } - } - - virtual QualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override { - if (dir == storm::OptimizationDirection::Minimize) { - return prob1Min; - } else { - return prob1Max; - } - } - - QualitativeMdpResult prob0Min; - QualitativeMdpResult prob1Min; - QualitativeMdpResult prob0Max; - QualitativeMdpResult prob1Max; - }; - - } -} - diff --git a/src/storm/abstraction/QualitativeResult.cpp b/src/storm/abstraction/QualitativeResult.cpp index 68a50d1e5..968b34894 100644 --- a/src/storm/abstraction/QualitativeResult.cpp +++ b/src/storm/abstraction/QualitativeResult.cpp @@ -1,3 +1,36 @@ #include "storm/abstraction/QualitativeResult.h" +#include "storm/abstraction/SymbolicQualitativeResult.h" +#include "storm/abstraction/ExplicitQualitativeResult.h" +namespace storm { + namespace abstraction { + + bool QualitativeResult::isSymbolic() const { + return false; + } + + bool QualitativeResult::isExplicit() const { + return false; + } + + template + SymbolicQualitativeResult& QualitativeResult::asSymbolicQualitativeResult() { + return static_cast&>(*this); + } + + template + SymbolicQualitativeResult const& QualitativeResult::asSymbolicQualitativeResult() const { + return static_cast const&>(*this); + } + + ExplicitQualitativeResult& QualitativeResult::asExplicitQualitativeResult() { + return static_cast(*this); + } + + ExplicitQualitativeResult const& QualitativeResult::asExplicitQualitativeResult() const { + return static_cast(*this); + } + + } +} diff --git a/src/storm/abstraction/QualitativeResult.h b/src/storm/abstraction/QualitativeResult.h index 0d027b3a7..c7eafdc01 100644 --- a/src/storm/abstraction/QualitativeResult.h +++ b/src/storm/abstraction/QualitativeResult.h @@ -3,22 +3,29 @@ #include "storm/storage/dd/DdType.h" namespace storm { - namespace dd { - template - class Bdd; - } - namespace abstraction { - template + template + class SymbolicQualitativeResult; + + class ExplicitQualitativeResult; + class QualitativeResult { public: virtual ~QualitativeResult() = default; + + virtual bool isSymbolic() const; + virtual bool isExplicit() const; + + template + SymbolicQualitativeResult& asSymbolicQualitativeResult(); + template + SymbolicQualitativeResult const& asSymbolicQualitativeResult() const; + + ExplicitQualitativeResult& asExplicitQualitativeResult(); + ExplicitQualitativeResult const& asExplicitQualitativeResult() const; - virtual storm::dd::Bdd const& getStates() const = 0; }; } } - - diff --git a/src/storm/abstraction/QualitativeResultMinMax.cpp b/src/storm/abstraction/QualitativeResultMinMax.cpp index 95465172c..28eee28b1 100644 --- a/src/storm/abstraction/QualitativeResultMinMax.cpp +++ b/src/storm/abstraction/QualitativeResultMinMax.cpp @@ -8,7 +8,11 @@ namespace storm { bool QualitativeResultMinMax::isSymbolic() const { return false; } - + + bool QualitativeResultMinMax::isExplicit() const { + return false; + } + template SymbolicQualitativeResultMinMax const& QualitativeResultMinMax::asSymbolicQualitativeResultMinMax() const { return static_cast const&>(*this); diff --git a/src/storm/abstraction/QualitativeResultMinMax.h b/src/storm/abstraction/QualitativeResultMinMax.h index b6aa96382..3f789eca7 100644 --- a/src/storm/abstraction/QualitativeResultMinMax.h +++ b/src/storm/abstraction/QualitativeResultMinMax.h @@ -13,7 +13,8 @@ namespace storm { virtual ~QualitativeResultMinMax() = default; virtual bool isSymbolic() const; - + virtual bool isExplicit() const; + template SymbolicQualitativeResultMinMax const& asSymbolicQualitativeResultMinMax() const; diff --git a/src/storm/abstraction/QuantitativeGameResult.h b/src/storm/abstraction/QuantitativeGameResult.h deleted file mode 100644 index 2d76a8618..000000000 --- a/src/storm/abstraction/QuantitativeGameResult.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include "storm/storage/dd/DdType.h" -#include "storm/storage/dd/Add.h" -#include "storm/storage/dd/Bdd.h" - -namespace storm { - namespace abstraction { - - template - struct QuantitativeGameResult { - QuantitativeGameResult() = default; - - QuantitativeGameResult(storm::dd::Add const& values) : values(values) { - // Intentionally left empty. - } - - QuantitativeGameResult(boost::optional> const& initialStatesRange, storm::dd::Add const& values, boost::optional> const& player1Strategy, boost::optional> const& player2Strategy) : initialStatesRange(initialStatesRange), values(values), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { - // Intentionally left empty. - } - - bool hasPlayer1Strategy() const { - return static_cast(player1Strategy); - } - - storm::dd::Bdd const& getPlayer1Strategy() const { - return player1Strategy.get(); - } - - storm::dd::Bdd& getPlayer1Strategy() { - return player1Strategy.get(); - } - - bool hasPlayer2Strategy() const { - return static_cast(player2Strategy); - } - - storm::dd::Bdd const& getPlayer2Strategy() const { - return player2Strategy.get(); - } - - storm::dd::Bdd& getPlayer2Strategy() { - return player2Strategy.get(); - } - - bool hasInitialStatesRange() const { - return static_cast(initialStatesRange); - } - - std::pair const& getInitialStatesRange() const { - return initialStatesRange.get(); - } - - boost::optional> initialStatesRange; - storm::dd::Add values; - boost::optional> player1Strategy; - boost::optional> player2Strategy; - }; - - } -} diff --git a/src/storm/abstraction/QuantitativeGameResultMinMax.h b/src/storm/abstraction/QuantitativeGameResultMinMax.h deleted file mode 100644 index c88c014f3..000000000 --- a/src/storm/abstraction/QuantitativeGameResultMinMax.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "storm/abstraction/QuantitativeGameResult.h" - -namespace storm { - namespace abstraction { - - template - class QuantitativeGameResultMinMax { - public: - QuantitativeGameResultMinMax() = default; - - QuantitativeGameResultMinMax(QuantitativeGameResult const& min, QuantitativeGameResult const& max) : min(min), max(max) { - // Intentionally left empty. - } - - QuantitativeGameResult min; - QuantitativeGameResult max; - }; - - } -} diff --git a/src/storm/abstraction/StateSetAbstractor.cpp b/src/storm/abstraction/StateSetAbstractor.cpp index 48e2042a9..21b03a476 100644 --- a/src/storm/abstraction/StateSetAbstractor.cpp +++ b/src/storm/abstraction/StateSetAbstractor.cpp @@ -16,6 +16,10 @@ namespace storm { template StateSetAbstractor::StateSetAbstractor(AbstractionInformation& abstractionInformation, std::vector const& statePredicates, std::shared_ptr const& smtSolverFactory) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), localExpressionInformation(abstractionInformation), relevantPredicatesAndVariables(), concretePredicateVariables(), forceRecomputation(true), cachedBdd(abstractionInformation.getDdManager().getBddOne()), constraint(abstractionInformation.getDdManager().getBddOne()) { + for (auto const& constraint : abstractionInformation.getConstraints()) { + smtSolver->add(constraint); + } + // Assert all state predicates. for (auto const& predicate : statePredicates) { smtSolver->add(predicate); @@ -23,8 +27,8 @@ namespace storm { // Extract the variables of the predicate, so we know which variables were used when abstracting. std::set usedVariables = predicate.getVariables(); concretePredicateVariables.insert(usedVariables.begin(), usedVariables.end()); - localExpressionInformation.relate(usedVariables); } + localExpressionInformation.relate(concretePredicateVariables); } template @@ -48,6 +52,7 @@ namespace storm { } std::set newRelevantPredicateIndices = localExpressionInformation.getRelatedExpressions(concretePredicateVariables); + // Since the number of relevant predicates is monotonic, we can simply check for the size here. STORM_LOG_ASSERT(newRelevantPredicateIndices.size() >= relevantPredicatesAndVariables.size(), "Illegal size of relevant predicates."); if (newRelevantPredicateIndices.size() > relevantPredicatesAndVariables.size()) { @@ -154,7 +159,7 @@ namespace storm { template class StateSetAbstractor; template class StateSetAbstractor; #ifdef STORM_HAVE_CARL - template class StateSetAbstractor; + template class StateSetAbstractor; #endif } } diff --git a/src/storm/abstraction/SymbolicQualitativeGameResult.cpp b/src/storm/abstraction/SymbolicQualitativeGameResult.cpp new file mode 100644 index 000000000..0dfae3145 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResult.cpp @@ -0,0 +1,19 @@ +#include "storm/abstraction/SymbolicQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeGameResult::SymbolicQualitativeGameResult(storm::utility::graph::SymbolicGameProb01Result const& prob01Result) : storm::utility::graph::SymbolicGameProb01Result(prob01Result) { + // Intentionally left empty. + } + + template + storm::dd::Bdd const& SymbolicQualitativeGameResult::getStates() const { + return this->getPlayer1States(); + } + + template class SymbolicQualitativeGameResult; + template class SymbolicQualitativeGameResult; + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeGameResult.h b/src/storm/abstraction/SymbolicQualitativeGameResult.h new file mode 100644 index 000000000..968e7d51d --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResult.h @@ -0,0 +1,20 @@ +#pragma once + +#include "storm/utility/graph.h" +#include "storm/abstraction/SymbolicQualitativeResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeGameResult : public storm::utility::graph::SymbolicGameProb01Result, public SymbolicQualitativeResult { + public: + SymbolicQualitativeGameResult() = default; + + SymbolicQualitativeGameResult(storm::utility::graph::SymbolicGameProb01Result const& prob01Result); + + virtual storm::dd::Bdd const& getStates() const override; + }; + + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp new file mode 100644 index 000000000..9768cab16 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.cpp @@ -0,0 +1,29 @@ +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeResult const& SymbolicQualitativeGameResultMinMax::getProb0(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + template + SymbolicQualitativeResult const& SymbolicQualitativeGameResultMinMax::getProb1(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + + template class SymbolicQualitativeGameResultMinMax; + template class SymbolicQualitativeGameResultMinMax; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h new file mode 100644 index 000000000..4f58660a9 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeGameResultMinMax.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeGameResultMinMax : public SymbolicQualitativeResultMinMax { + public: + SymbolicQualitativeGameResultMinMax() = default; + + virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override; + virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override; + + SymbolicQualitativeGameResult prob0Min; + SymbolicQualitativeGameResult prob1Min; + SymbolicQualitativeGameResult prob0Max; + SymbolicQualitativeGameResult prob1Max; + }; + + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResult.cpp b/src/storm/abstraction/SymbolicQualitativeMdpResult.cpp new file mode 100644 index 000000000..418047333 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResult.cpp @@ -0,0 +1,20 @@ +#include "storm/abstraction/SymbolicQualitativeMdpResult.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeMdpResult::SymbolicQualitativeMdpResult(storm::dd::Bdd const& states) : states(states) { + // Intentionally left empty. + } + + template + storm::dd::Bdd const& SymbolicQualitativeMdpResult::getStates() const { + return states; + } + + template class SymbolicQualitativeMdpResult; + template class SymbolicQualitativeMdpResult; + + } +} diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResult.h b/src/storm/abstraction/SymbolicQualitativeMdpResult.h new file mode 100644 index 000000000..ba854fff7 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResult.h @@ -0,0 +1,24 @@ +#pragma once + +#include "storm/abstraction/SymbolicQualitativeResult.h" + +#include "storm/storage/dd/Bdd.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeMdpResult : public SymbolicQualitativeResult { + public: + SymbolicQualitativeMdpResult() = default; + + SymbolicQualitativeMdpResult(storm::dd::Bdd const& states); + + virtual storm::dd::Bdd const& getStates() const override; + + storm::dd::Bdd states; + }; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp new file mode 100644 index 000000000..87b6f504f --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.cpp @@ -0,0 +1,29 @@ +#include "storm/abstraction/SymbolicQualitativeMdpResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQualitativeResult const& SymbolicQualitativeMdpResultMinMax::getProb0(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob0Min; + } else { + return prob0Max; + } + } + + template + SymbolicQualitativeResult const& SymbolicQualitativeMdpResultMinMax::getProb1(storm::OptimizationDirection const& dir) const { + if (dir == storm::OptimizationDirection::Minimize) { + return prob1Min; + } else { + return prob1Max; + } + } + + template class SymbolicQualitativeMdpResultMinMax; + template class SymbolicQualitativeMdpResultMinMax; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h new file mode 100644 index 000000000..554e0bd3d --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeMdpResultMinMax.h @@ -0,0 +1,27 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/SymbolicQualitativeResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeMdpResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQualitativeMdpResultMinMax : public SymbolicQualitativeResultMinMax { + public: + SymbolicQualitativeMdpResultMinMax() = default; + + virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const override; + virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const override; + + SymbolicQualitativeMdpResult prob0Min; + SymbolicQualitativeMdpResult prob1Min; + SymbolicQualitativeMdpResult prob0Max; + SymbolicQualitativeMdpResult prob1Max; + }; + + } +} + diff --git a/src/storm/abstraction/SymbolicQualitativeResult.h b/src/storm/abstraction/SymbolicQualitativeResult.h new file mode 100644 index 000000000..7703a1033 --- /dev/null +++ b/src/storm/abstraction/SymbolicQualitativeResult.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" + +#include "storm/abstraction/QualitativeResult.h" + +namespace storm { + namespace dd { + template + class Bdd; + } + + namespace abstraction { + + template + class SymbolicQualitativeResult : public QualitativeResult { + public: + virtual ~SymbolicQualitativeResult() = default; + + virtual storm::dd::Bdd const& getStates() const = 0; + }; + + } +} + + diff --git a/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp b/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp index 772ee645d..51dff167a 100644 --- a/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp +++ b/src/storm/abstraction/SymbolicQualitativeResultMinMax.cpp @@ -11,22 +11,22 @@ namespace storm { } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Min() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Min() const { return getProb0(storm::OptimizationDirection::Minimize); } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Min() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Min() const { return getProb1(storm::OptimizationDirection::Minimize); } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Max() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb0Max() const { return getProb0(storm::OptimizationDirection::Maximize); } template - QualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Max() const { + SymbolicQualitativeResult const& SymbolicQualitativeResultMinMax::getProb1Max() const { return getProb1(storm::OptimizationDirection::Maximize); } diff --git a/src/storm/abstraction/SymbolicQualitativeResultMinMax.h b/src/storm/abstraction/SymbolicQualitativeResultMinMax.h index 8b9be7e23..fe4d21bf2 100644 --- a/src/storm/abstraction/SymbolicQualitativeResultMinMax.h +++ b/src/storm/abstraction/SymbolicQualitativeResultMinMax.h @@ -14,7 +14,7 @@ namespace storm { namespace abstraction { template - class QualitativeResult; + class SymbolicQualitativeResult; template class SymbolicQualitativeResultMinMax : public QualitativeResultMinMax { @@ -23,13 +23,13 @@ namespace storm { virtual bool isSymbolic() const override; - QualitativeResult const& getProb0Min() const; - QualitativeResult const& getProb1Min() const; - QualitativeResult const& getProb0Max() const; - QualitativeResult const& getProb1Max() const; + SymbolicQualitativeResult const& getProb0Min() const; + SymbolicQualitativeResult const& getProb1Min() const; + SymbolicQualitativeResult const& getProb0Max() const; + SymbolicQualitativeResult const& getProb1Max() const; - virtual QualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; - virtual QualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; + virtual SymbolicQualitativeResult const& getProb0(storm::OptimizationDirection const& dir) const = 0; + virtual SymbolicQualitativeResult const& getProb1(storm::OptimizationDirection const& dir) const = 0; }; } } diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp b/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp new file mode 100644 index 000000000..839ba732e --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResult.cpp @@ -0,0 +1,62 @@ +#include "storm/abstraction/SymbolicQuantitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQuantitativeGameResult::SymbolicQuantitativeGameResult(storm::dd::Add const& values) : values(values) { + // Intentionally left empty. + } + + template + SymbolicQuantitativeGameResult::SymbolicQuantitativeGameResult(boost::optional> const& initialStatesRange, storm::dd::Add const& values, boost::optional> const& player1Strategy, boost::optional> const& player2Strategy) : initialStatesRange(initialStatesRange), values(values), player1Strategy(player1Strategy), player2Strategy(player2Strategy) { + // Intentionally left empty. + } + + template + bool SymbolicQuantitativeGameResult::hasPlayer1Strategy() const { + return static_cast(player1Strategy); + } + + template + storm::dd::Bdd const& SymbolicQuantitativeGameResult::getPlayer1Strategy() const { + return player1Strategy.get(); + } + + template + storm::dd::Bdd& SymbolicQuantitativeGameResult::getPlayer1Strategy() { + return player1Strategy.get(); + } + + template + bool SymbolicQuantitativeGameResult::hasPlayer2Strategy() const { + return static_cast(player2Strategy); + } + + template + storm::dd::Bdd const& SymbolicQuantitativeGameResult::getPlayer2Strategy() const { + return player2Strategy.get(); + } + + template + storm::dd::Bdd& SymbolicQuantitativeGameResult::getPlayer2Strategy() { + return player2Strategy.get(); + } + + template + bool SymbolicQuantitativeGameResult::hasInitialStatesRange() const { + return static_cast(initialStatesRange); + } + + template + std::pair const& SymbolicQuantitativeGameResult::getInitialStatesRange() const { + return initialStatesRange.get(); + } + + template class SymbolicQuantitativeGameResult; + template class SymbolicQuantitativeGameResult; + template class SymbolicQuantitativeGameResult; + + } +} + diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResult.h b/src/storm/abstraction/SymbolicQuantitativeGameResult.h new file mode 100644 index 000000000..b9dc7eaa2 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResult.h @@ -0,0 +1,41 @@ +#pragma once + +#include "storm/storage/dd/DdType.h" +#include "storm/storage/dd/Add.h" +#include "storm/storage/dd/Bdd.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQuantitativeGameResult { + public: + SymbolicQuantitativeGameResult() = default; + + SymbolicQuantitativeGameResult(storm::dd::Add const& values); + SymbolicQuantitativeGameResult(boost::optional> const& initialStatesRange, storm::dd::Add const& values, boost::optional> const& player1Strategy, boost::optional> const& player2Strategy); + + bool hasPlayer1Strategy() const; + + storm::dd::Bdd const& getPlayer1Strategy() const; + + storm::dd::Bdd& getPlayer1Strategy(); + + bool hasPlayer2Strategy() const; + + storm::dd::Bdd const& getPlayer2Strategy() const; + + storm::dd::Bdd& getPlayer2Strategy(); + + bool hasInitialStatesRange() const; + + std::pair const& getInitialStatesRange() const; + + boost::optional> initialStatesRange; + storm::dd::Add values; + boost::optional> player1Strategy; + boost::optional> player2Strategy; + }; + + } +} diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp new file mode 100644 index 000000000..9a58c2597 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.cpp @@ -0,0 +1,12 @@ +#include "storm/abstraction/SymbolicQuantitativeGameResultMinMax.h" + +namespace storm { + namespace abstraction { + + template + SymbolicQuantitativeGameResultMinMax::SymbolicQuantitativeGameResultMinMax(SymbolicQuantitativeGameResult const& min, SymbolicQuantitativeGameResult const& max) : min(min), max(max) { + // Intentionally left empty. + } + + } +} diff --git a/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h new file mode 100644 index 000000000..32ec71ce3 --- /dev/null +++ b/src/storm/abstraction/SymbolicQuantitativeGameResultMinMax.h @@ -0,0 +1,20 @@ +#pragma once + +#include "storm/abstraction/SymbolicQuantitativeGameResult.h" + +namespace storm { + namespace abstraction { + + template + class SymbolicQuantitativeGameResultMinMax { + public: + SymbolicQuantitativeGameResultMinMax() = default; + + SymbolicQuantitativeGameResultMinMax(SymbolicQuantitativeGameResult const& min, SymbolicQuantitativeGameResult const& max); + + SymbolicQuantitativeGameResult min; + SymbolicQuantitativeGameResult max; + }; + + } +} diff --git a/src/storm/abstraction/ValidBlockAbstractor.cpp b/src/storm/abstraction/ValidBlockAbstractor.cpp index dcfdcf20c..dbc84dd13 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.cpp +++ b/src/storm/abstraction/ValidBlockAbstractor.cpp @@ -5,6 +5,7 @@ #include "storm/storage/dd/DdManager.h" #include "storm/utility/solver.h" +#include "storm/utility/Stopwatch.h" namespace storm { namespace abstraction { @@ -34,6 +35,13 @@ namespace storm { return validBlocks; } + template + void ValidBlockAbstractor::constrain(storm::expressions::Expression const& constraint) { + for (uint64_t i = 0; i < smtSolvers.size(); ++i) { + smtSolvers[i]->add(constraint); + } + } + template void ValidBlockAbstractor::refine(std::vector const& predicates) { for (auto const& predicate : predicates) { @@ -61,13 +69,13 @@ namespace storm { template void ValidBlockAbstractor::recomputeValidBlocks() { storm::dd::Bdd newValidBlocks = abstractionInformation.get().getDdManager().getBddOne(); - + for (uint64_t blockIndex = 0; blockIndex < localExpressionInformation.getNumberOfBlocks(); ++blockIndex) { std::set const& predicateBlock = localExpressionInformation.getExpressionBlock(blockIndex); // If the size of the block changed, we need to add the appropriate variables and recompute the solution. if (relevantVariablesAndPredicates[blockIndex].size() < predicateBlock.size()) { - recomputeValidBlockForPredicateBlock(blockIndex); + recomputeValidBlocksForPredicateBlock(blockIndex); } newValidBlocks &= validBlocksForPredicateBlocks[blockIndex]; @@ -77,9 +85,8 @@ namespace storm { } template - void ValidBlockAbstractor::recomputeValidBlockForPredicateBlock(uint64_t blockIndex) { + void ValidBlockAbstractor::recomputeValidBlocksForPredicateBlock(uint64_t blockIndex) { std::set const& predicateBlock = localExpressionInformation.getExpressionBlock(blockIndex); - std::vector> newVariables = this->getAbstractionInformation().declareNewVariables(relevantVariablesAndPredicates[blockIndex], predicateBlock); for (auto const& element : newVariables) { smtSolvers[blockIndex]->add(storm::expressions::iff(element.first, this->getAbstractionInformation().getPredicateByIndex(element.second))); @@ -114,13 +121,11 @@ namespace storm { template storm::dd::Bdd ValidBlockAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, uint64_t blockIndex) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); -// std::cout << "new model ----------------" << std::endl; - for (auto const& variableIndexPair : relevantVariablesAndPredicates[blockIndex]) { + for (auto variableIndexPairIt = relevantVariablesAndPredicates[blockIndex].rbegin(), variableIndexPairIte = relevantVariablesAndPredicates[blockIndex].rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { -// std::cout << this->getAbstractionInformation().getPredicateByIndex(variableIndexPair.second) << " is true" << std::endl; result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { -// std::cout << this->getAbstractionInformation().getPredicateByIndex(variableIndexPair.second) << " is false" << std::endl; result &= !this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } } diff --git a/src/storm/abstraction/ValidBlockAbstractor.h b/src/storm/abstraction/ValidBlockAbstractor.h index 6e0b28ab4..145638def 100644 --- a/src/storm/abstraction/ValidBlockAbstractor.h +++ b/src/storm/abstraction/ValidBlockAbstractor.h @@ -33,6 +33,8 @@ namespace storm { void refine(std::vector const& predicates); + void constrain(storm::expressions::Expression const& constraint); + private: /*! * Checks which parts of the valid blocks need to be recomputed. @@ -42,7 +44,7 @@ namespace storm { /*! * Recomputed the valid blocks for the given predicate block. */ - void recomputeValidBlockForPredicateBlock(uint64_t blockIndex); + void recomputeValidBlocksForPredicateBlock(uint64_t blockIndex); /*! * Retrieves the abstraction information object. diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.cpp b/src/storm/abstraction/jani/AutomatonAbstractor.cpp index b97ad6002..5d399fc56 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.cpp +++ b/src/storm/abstraction/jani/AutomatonAbstractor.cpp @@ -1,8 +1,8 @@ #include "storm/abstraction/jani/AutomatonAbstractor.h" #include "storm/abstraction/BottomStateResult.h" -#include "storm/abstraction/GameBddResult.h" #include "storm/abstraction/AbstractionInformation.h" +#include "storm/abstraction/GameBddResult.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/Add.h" @@ -24,12 +24,12 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - AutomatonAbstractor::AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), edges(), automaton(automaton) { + AutomatonAbstractor::AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), edges(), automaton(automaton) { // For each concrete command, we create an abstract counterpart. uint64_t edgeId = 0; for (auto const& edge : automaton.getEdges()) { - edges.emplace_back(edgeId, edge, abstractionInformation, smtSolverFactory, useDecomposition); + edges.emplace_back(edgeId, edge, abstractionInformation, smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); ++edgeId; } @@ -51,11 +51,21 @@ namespace storm { return edges[player1Choice].getGuard(); } + template + uint64_t AutomatonAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return edges[player1Choice].getNumberOfUpdates(player1Choice); + } + template std::map AutomatonAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return edges[player1Choice].getVariableUpdates(auxiliaryChoice); } + template + std::set const& AutomatonAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return edges[player1Choice].getAssignedVariables(); + } + template GameBddResult AutomatonAbstractor::abstract() { // First, we retrieve the abstractions of all commands. @@ -131,10 +141,17 @@ namespace storm { return abstractionInformation.get(); } + template + void AutomatonAbstractor::notifyGuardsArePredicates() { + for (auto& edge : edges) { + edge.notifyGuardIsPredicate(); + } + } + template class AutomatonAbstractor; template class AutomatonAbstractor; #ifdef STORM_HAVE_CARL - template class AutomatonAbstractor; + template class AutomatonAbstractor; #endif } } diff --git a/src/storm/abstraction/jani/AutomatonAbstractor.h b/src/storm/abstraction/jani/AutomatonAbstractor.h index ac010a0d9..9b58ba9c1 100644 --- a/src/storm/abstraction/jani/AutomatonAbstractor.h +++ b/src/storm/abstraction/jani/AutomatonAbstractor.h @@ -35,7 +35,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use the decomposition during abstraction. */ - AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + AutomatonAbstractor(storm::jani::Automaton const& automaton, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); AutomatonAbstractor(AutomatonAbstractor const&) = default; AutomatonAbstractor& operator=(AutomatonAbstractor const&) = default; @@ -57,12 +57,22 @@ namespace storm { */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const; + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const; + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + std::set const& getAssignedVariables(uint64_t player1Choice) const; + /*! * Computes the abstraction of the module wrt. to the current set of predicates. * @@ -112,6 +122,8 @@ namespace storm { */ std::size_t getNumberOfEdges() const; + void notifyGuardsArePredicates(); + private: /*! * Retrieves the abstraction information. diff --git a/src/storm/abstraction/jani/EdgeAbstractor.cpp b/src/storm/abstraction/jani/EdgeAbstractor.cpp index eaaafe266..ee52cae71 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.cpp +++ b/src/storm/abstraction/jani/EdgeAbstractor.cpp @@ -23,7 +23,7 @@ namespace storm { namespace abstraction { namespace jani { template - EdgeAbstractor::EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), edgeId(edgeId), edge(edge), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!edge.getGuard()}, smtSolverFactory) { + EdgeAbstractor::EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), edgeId(edgeId), edge(edge), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), addPredicatesForValidBlocks(addPredicatesForValidBlocks), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!edge.getGuard()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(edge.getNumberOfDestinations()); @@ -36,6 +36,18 @@ namespace storm { // Assert the guard of the command. smtSolver->add(edge.getGuard()); + + // Construct assigned variables. + for (auto const& destination : edge.getDestinations()) { + for (auto const& assignment : destination.getOrderedAssignments()) { + assignedVariables.insert(assignment.getExpressionVariable()); + } + } + + // Log whether or not predicates are added to ensure valid blocks. + if (this->addPredicatesForValidBlocks) { + STORM_LOG_DEBUG("Adding more predicates to ensure valid blocks."); + } } template @@ -65,11 +77,21 @@ namespace storm { return edge.get().getGuard(); } + template + uint64_t EdgeAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return edge.get().getNumberOfDestinations(); + } + template std::map EdgeAbstractor::getVariableUpdates(uint64_t auxiliaryChoice) const { return edge.get().getDestination(auxiliaryChoice).getAsVariableToExpressionMap(); } + template + std::set const& EdgeAbstractor::getAssignedVariables() const { + return assignedVariables; + } + template void EdgeAbstractor::recomputeCachedBdd() { if (useDecomposition) { @@ -162,7 +184,6 @@ namespace storm { } relevantBlockPartition[representativeBlock].insert(relevantBlockPartition[assignmentVariableBlock].begin(), relevantBlockPartition[assignmentVariableBlock].end()); relevantBlockPartition[assignmentVariableBlock].clear(); - } } } @@ -171,200 +192,231 @@ namespace storm { // Now remove all blocks that are empty and obtain the partition. std::vector> cleanedRelevantBlockPartition; - for (auto& element : relevantBlockPartition) { - if (!element.empty()) { - cleanedRelevantBlockPartition.emplace_back(std::move(element)); + for (auto& outerBlock : relevantBlockPartition) { + if (!outerBlock.empty()) { + cleanedRelevantBlockPartition.emplace_back(); + + for (auto const& innerBlock : outerBlock) { + if (!localExpressionInformation.getExpressionBlock(innerBlock).empty()) { + cleanedRelevantBlockPartition.back().insert(innerBlock); + } + } + + if (cleanedRelevantBlockPartition.back().empty()) { + cleanedRelevantBlockPartition.pop_back(); + } } } relevantBlockPartition = std::move(cleanedRelevantBlockPartition); - // if the decomposition has size 1, use the plain technique from before - if (relevantBlockPartition.size() == 1) { - STORM_LOG_TRACE("Relevant block partition size is one, falling back to regular computation."); - recomputeCachedBddWithoutDecomposition(); - } else { - std::set variablesContainedInGuard = edge.get().getGuard().getVariables(); - - // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard - // are not contained within a single block of our decomposition. - bool enumerateAbstractGuard = true; - std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + STORM_LOG_TRACE("Decomposition into " << relevantBlockPartition.size() << " blocks."); + if (this->debug) { + uint64_t blockIndex = 0; for (auto const& block : relevantBlockPartition) { - bool allContained = true; - for (auto const& guardBlock : guardBlocks) { - if (block.find(guardBlock) == block.end()) { - allContained = false; - break; - } - } - if (allContained) { - enumerateAbstractGuard = false; - } - } - - uint64_t numberOfSolutions = 0; - - if (enumerateAbstractGuard) { - // otherwise, enumerate the abstract guard so we do this only once - std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); - std::vector guardDecisionVariables; - std::vector> guardVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { - guardDecisionVariables.push_back(element.first); - guardVariablesAndPredicates.push_back(element); - } + STORM_LOG_TRACE("Predicates of block " << blockIndex << ":"); + std::set blockPredicateIndices; + for (auto const& innerBlock : block) { + blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); } - abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); - smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { - abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " for abstract guard."); - - // now that we have the abstract guard, we can add it as an assertion to the solver before enumerating - // the other solutions. - // Create a new backtracking point before adding the guard. - smtSolver->push(); - - // Create the guard constraint. - std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); - - // Then add it to the solver. - for (auto const& expression : result.first) { - smtSolver->add(expression); + for (auto const& predicateIndex : blockPredicateIndices) { + STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); } - // Finally associate the level variables with the predicates. - for (auto const& indexVariablePair : result.second) { - smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + ++blockIndex; + } + } + + std::set variablesContainedInGuard = edge.get().getGuard().getVariables(); + + // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard + // are not contained within a single block of our decomposition. + bool enumerateAbstractGuard = true; + std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + for (auto const& block : relevantBlockPartition) { + bool allContained = true; + for (auto const& guardBlock : guardBlocks) { + if (block.find(guardBlock) == block.end()) { + allContained = false; + break; } } - - // then enumerate the solutions for each of the blocks of the decomposition - uint64_t usedNondeterminismVariables = 0; - uint64_t blockCounter = 0; - std::vector> blockBdds; - for (auto const& block : relevantBlockPartition) { - std::set relevantPredicates; - for (auto const& innerBlock : block) { - relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + if (allContained) { + enumerateAbstractGuard = false; + } + } + + uint64_t numberOfSolutions = 0; + uint64_t numberOfTotalSolutions = 0; + + // If we need to enumerate the guard, do it only once now. + if (enumerateAbstractGuard) { + std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); + std::vector guardDecisionVariables; + std::vector> guardVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { + guardDecisionVariables.push_back(element.first); + guardVariablesAndPredicates.push_back(element); } - - std::vector transitionDecisionVariables; - std::vector> sourceVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relevantPredicates.find(element.second) != relevantPredicates.end()) { - transitionDecisionVariables.push_back(element.first); - sourceVariablesAndPredicates.push_back(element); - } + } + abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); + smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { + abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for abstract guard."); + + // Now that we have the abstract guard, we can add it as an assertion to the solver before enumerating + // the other solutions. + + // Create a new backtracking point before adding the guard. + smtSolver->push(); + + // Create the guard constraint. + std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); + + // Then add it to the solver. + for (auto const& expression : result.first) { + smtSolver->add(expression); + } + + // Finally associate the level variables with the predicates. + for (auto const& indexVariablePair : result.second) { + smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + } + } + + // Then enumerate the solutions for each of the blocks of the decomposition + uint64_t usedNondeterminismVariables = 0; + uint64_t blockCounter = 0; + std::vector> blockBdds; + for (auto const& block : relevantBlockPartition) { + std::set relevantPredicates; + for (auto const& innerBlock : block) { + relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + } + + if (relevantPredicates.empty()) { + STORM_LOG_TRACE("Block does not contain relevant predicates, skipping it."); + continue; + } + + std::vector transitionDecisionVariables; + std::vector> sourceVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relevantPredicates.find(element.second) != relevantPredicates.end()) { + transitionDecisionVariables.push_back(element.first); + sourceVariablesAndPredicates.push_back(element); } - - std::vector>> destinationVariablesAndPredicates; - for (uint64_t destinationIndex = 0; destinationIndex < edge.get().getNumberOfDestinations(); ++destinationIndex) { - destinationVariablesAndPredicates.emplace_back(); - for (auto const& assignment : edge.get().getDestination(destinationIndex).getOrderedAssignments().getAllAssignments()) { - uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getExpressionVariable()); + } + + std::vector>> destinationVariablesAndPredicates; + for (uint64_t destinationIndex = 0; destinationIndex < edge.get().getNumberOfDestinations(); ++destinationIndex) { + destinationVariablesAndPredicates.emplace_back(); + for (auto const& assignment : edge.get().getDestination(destinationIndex).getOrderedAssignments().getAllAssignments()) { + uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable().getExpressionVariable()); + + if (block.find(assignmentVariableBlockIndex) != block.end()) { std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); - if (block.find(assignmentVariableBlockIndex) != block.end()) { - for (auto const& element : relevantPredicatesAndVariables.second[destinationIndex]) { - if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { - destinationVariablesAndPredicates.back().push_back(element); - transitionDecisionVariables.push_back(element.first); - } + for (auto const& element : relevantPredicatesAndVariables.second[destinationIndex]) { + if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { + destinationVariablesAndPredicates.back().push_back(element); + transitionDecisionVariables.push_back(element.first); } } } } - - std::unordered_map, std::vector>> sourceToDistributionsMap; - numberOfSolutions = 0; - smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { - sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); - numberOfSolutions = 0; - - // Now we search for the maximal number of choices of player 2 to determine how many DD variables we - // need to encode the nondeterminism. - uint_fast64_t maximalNumberOfChoices = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); - } - - // We now compute how many variables we need to encode the choices. We add one to the maximal number of - // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + 1))); - - // Finally, build overall result. - storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); - - uint_fast64_t sourceStateIndex = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); - STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - // We start with the distribution index of 1, becase 0 is reserved for a potential bottom choice. - uint_fast64_t distributionIndex = 1; - storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); - for (auto const& distribution : sourceDistributionsPair.second) { - allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); - ++distributionIndex; - STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); - } - resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; - STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); - } - usedNondeterminismVariables += numberOfVariablesNeeded; - - blockBdds.push_back(resultBdd); - ++blockCounter; } - if (enumerateAbstractGuard) { - smtSolver->pop(); - } + std::unordered_map, std::vector>> sourceToDistributionsMap; + numberOfSolutions = 0; + smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { + sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); + numberOfTotalSolutions += numberOfSolutions; - // multiply the results - storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& blockBdd : blockBdds) { - resultBdd &= blockBdd; + // Now we search for the maximal number of choices of player 2 to determine how many DD variables we + // need to encode the nondeterminism. + uint_fast64_t maximalNumberOfChoices = 0; + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); } - // if we did not explicitly enumerate the guard, we can construct it from the result BDD. - if (!enumerateAbstractGuard) { - std::set allVariables(this->getAbstractionInformation().getSuccessorVariables()); - auto player2Variables = this->getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); - allVariables.insert(player2Variables.begin(), player2Variables.end()); - auto auxVariables = this->getAbstractionInformation().getAuxVariableSet(0, this->getAbstractionInformation().getAuxVariableCount()); - allVariables.insert(auxVariables.begin(), auxVariables.end()); - - std::set variablesToAbstract; - std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); + // We now compute how many variables we need to encode the choices. We add one to the maximal number of + // choices to account for a possible transition to a bottom state. + uint_fast64_t numberOfVariablesNeeded = (maximalNumberOfChoices > 1) ? (static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0))))) : (blockCounter == 0 ? 1 : 0); + + // Finally, build overall result. + storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); + + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); + STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - abstractGuard = resultBdd.existsAbstract(variablesToAbstract); - } else { - // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. - resultBdd &= abstractGuard; + // We start with the distribution index of 1, because 0 is reserved for a potential bottom choice. + uint_fast64_t distributionIndex = blockCounter == 0 ? 1 : 0; + storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); + for (auto const& distribution : sourceDistributionsPair.second) { + allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); + ++distributionIndex; + STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); + } + resultBdd |= sourceDistributionsPair.first && allDistributions; + STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } + usedNondeterminismVariables += numberOfVariablesNeeded; - // multiply with missing identities - resultBdd &= computeMissingIdentities(); - - // cache and return result - resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()); + blockBdds.push_back(resultBdd); + ++blockCounter; + } + + if (enumerateAbstractGuard) { + smtSolver->pop(); + } + + // multiply the results + storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); + uint64_t blockIndex = 0; + for (auto const& blockBdd : blockBdds) { + resultBdd &= blockBdd; + ++blockIndex; + } + + // If we did not explicitly enumerate the guard, we can construct it from the result BDD. + if (!enumerateAbstractGuard) { + std::set allVariables(getAbstractionInformation().getSuccessorVariables()); + auto player2Variables = getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); + allVariables.insert(player2Variables.begin(), player2Variables.end()); + auto auxVariables = getAbstractionInformation().getAuxVariableSet(0, getAbstractionInformation().getAuxVariableCount()); + allVariables.insert(auxVariables.begin(), auxVariables.end()); - // Cache the result. - cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + std::set variablesToAbstract; + std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); - auto end = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); - forceRecomputation = false; + abstractGuard = resultBdd.existsAbstract(variablesToAbstract); + } else { + // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. + resultBdd &= abstractGuard; } + + // multiply with missing identities + resultBdd &= computeMissingDestinationIdentities(); + + // cache and return result + resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()); + + // Cache the result. + cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + + auto end = std::chrono::high_resolution_clock::now(); + + STORM_LOG_TRACE("Enumerated " << numberOfTotalSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); + forceRecomputation = false; } template @@ -397,7 +449,6 @@ namespace storm { if (!skipBottomStates) { abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); } - uint_fast64_t sourceStateIndex = 0; for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { if (!skipBottomStates) { abstractGuard |= sourceDistributionsPair.first; @@ -414,11 +465,10 @@ namespace storm { STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); } resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } - resultBdd &= computeMissingIdentities(); + resultBdd &= computeMissingDestinationIdentities(); resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()); STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); @@ -445,13 +495,13 @@ namespace storm { auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); - // Keep track of all assigned variables, so we can find the related predicates later. - assignedVariables.insert(assignedVariable); + // Predicates that are indirectly related to the assigned variables are relevant for the source state (if requested). + if (this->addPredicatesForValidBlocks) { + auto const& assignedVariableBlock = localExpressionInformation.getRelatedExpressions(assignedVariable); + result.first.insert(assignedVariableBlock.begin(), assignedVariableBlock.end()); + } } - auto const& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables); - result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); - return result; } @@ -518,7 +568,8 @@ namespace storm { template storm::dd::Bdd EdgeAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, std::vector> const& variablePredicates) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& variableIndexPair : variablePredicates) { + for (auto variableIndexPairIt = variablePredicates.rbegin(), variableIndexPairIte = variablePredicates.rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { @@ -538,15 +589,16 @@ namespace storm { storm::dd::Bdd updateBdd = this->getAbstractionInformation().getDdManager().getBddOne(); // Translate block variables for this update into a successor block. - for (auto const& variableIndexPair : variablePredicates[destinationIndex]) { + for (auto variableIndexPairIt = variablePredicates[destinationIndex].rbegin(), variableIndexPairIte = variablePredicates[destinationIndex].rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { updateBdd &= this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } else { updateBdd &= !this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } - updateBdd &= this->getAbstractionInformation().encodeAux(destinationIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } + updateBdd &= this->getAbstractionInformation().encodeAux(destinationIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); result |= updateBdd; } @@ -555,56 +607,29 @@ namespace storm { } template - storm::dd::Bdd EdgeAbstractor::computeMissingIdentities() const { - storm::dd::Bdd identities = computeMissingGlobalIdentities(); - identities &= computeMissingUpdateIdentities(); - return identities; - } - - template - storm::dd::Bdd EdgeAbstractor::computeMissingUpdateIdentities() const { + storm::dd::Bdd EdgeAbstractor::computeMissingDestinationIdentities() const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddZero(); - for (uint_fast64_t updateIndex = 0; updateIndex < edge.get().getNumberOfDestinations(); ++updateIndex) { + for (uint_fast64_t destinationIndex = 0; destinationIndex < edge.get().getNumberOfDestinations(); ++destinationIndex) { // Compute the identities that are missing for this update. - auto updateRelevantIt = relevantPredicatesAndVariables.second[updateIndex].begin(); - auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].end(); + auto updateRelevantIt = relevantPredicatesAndVariables.second[destinationIndex].rbegin(); + auto updateRelevantIte = relevantPredicatesAndVariables.second[destinationIndex].rend(); storm::dd::Bdd updateIdentity = this->getAbstractionInformation().getDdManager().getBddOne(); - auto sourceRelevantIt = relevantPredicatesAndVariables.first.begin(); - auto sourceRelevantIte = relevantPredicatesAndVariables.first.end(); - - // Go through all relevant source predicates. This is guaranteed to be a superset of the set of - // relevant successor predicates for any update. - for (; sourceRelevantIt != sourceRelevantIte; ++sourceRelevantIt) { - // If the predicates do not match, there is a predicate missing, so we need to add its identity. - if (updateRelevantIt == updateRelevantIte || sourceRelevantIt->second != updateRelevantIt->second) { - updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(sourceRelevantIt->second); + for (uint_fast64_t predicateIndex = this->getAbstractionInformation().getNumberOfPredicates() - 1;; --predicateIndex) { + if (updateRelevantIt == updateRelevantIte || updateRelevantIt->second != predicateIndex) { + updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); } else { ++updateRelevantIt; } + + if (predicateIndex == 0) { + break; + } } - result |= updateIdentity && this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); - } - return result; - } - - template - storm::dd::Bdd EdgeAbstractor::computeMissingGlobalIdentities() const { - storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - - auto relevantIt = relevantPredicatesAndVariables.first.begin(); - auto relevantIte = relevantPredicatesAndVariables.first.end(); - - for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { - if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { - result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); - } else { - ++relevantIt; - } + result |= updateIdentity && this->getAbstractionInformation().encodeAux(destinationIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } - return result; } @@ -613,31 +638,44 @@ namespace storm { if (forceRecomputation) { this->recomputeCachedBdd(); } else { - cachedDd.bdd &= computeMissingGlobalIdentities(); + cachedDd.bdd &= computeMissingDestinationIdentities(); } + STORM_LOG_TRACE("Edge produces " << cachedDd.bdd.getNonZeroCount() << " transitions."); + return cachedDd; } template BottomStateResult EdgeAbstractor::getBottomStateTransitions(storm::dd::Bdd const& reachableStates, uint_fast64_t numberOfPlayer2Variables, boost::optional> const& locationVariables) { - // Compute the reachable states that have this edge enabled. - storm::dd::Bdd reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); - STORM_LOG_TRACE("Computing bottom state transitions of edge with guard " << edge.get().getGuard()); + STORM_LOG_TRACE("Computing bottom state transitions of edge with index " << edgeId << "."); BottomStateResult result(this->getAbstractionInformation().getDdManager().getBddZero(), this->getAbstractionInformation().getDdManager().getBddZero()); - // If the guard of this edge is a predicate, there are not bottom states/transitions. + // If the guard of this command is a predicate, there are not bottom states/transitions. if (skipBottomStates) { STORM_LOG_TRACE("Skipping bottom state computation for this edge."); return result; } - // Use the state abstractor to compute the set of abstract states that has this edge enabled but still - // has a transition to a bottom state. - bottomStateAbstractor.constrain(reachableStatesWithEdge); - result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex()); + storm::dd::Bdd reachableStatesWithEdge = reachableStates && abstractGuard; + // needed? +// if (locationVariables) { +// reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); +// } else { +// reachableStatesWithEdge = (reachableStates && abstractGuard).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables()); +// } + + // Use the state abstractor to compute the set of abstract states that has this command enabled but + // still has a transition to a bottom state. + bottomStateAbstractor.constrain(reachableStatesWithEdge); + if (locationVariables) { + result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex()); + } else { + result.states = bottomStateAbstractor.getAbstractStates() && reachableStatesWithEdge; + } + // If the result is empty one time, we can skip the bottom state computation from now on. if (result.states.isZero()) { skipBottomStates = true; @@ -646,14 +684,11 @@ namespace storm { // Now equip all these states with an actual transition to a bottom state. result.transitions = result.states && this->getAbstractionInformation().getAllPredicateIdentities() && this->getAbstractionInformation().getBottomStateBdd(false, false); - // Mark the states as bottom states and add source location information. + // Mark the states as bottom states. result.states &= this->getAbstractionInformation().getBottomStateBdd(true, false); - // Add the edge encoding. - result.transitions &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()) && this->getAbstractionInformation().encodePlayer2Choice(0, 0,numberOfPlayer2Variables) && this->getAbstractionInformation().encodeAux(0, 0, this->getAbstractionInformation().getAuxVariableCount()); - - // Add the location identity to the transitions. - result.transitions &= this->getAbstractionInformation().getAllLocationIdentities(); + // Add the command encoding and the next free player 2 encoding. + result.transitions &= this->getAbstractionInformation().encodePlayer1Choice(edgeId, this->getAbstractionInformation().getPlayer1VariableCount()) && this->getAbstractionInformation().encodePlayer2Choice(0, 0, numberOfPlayer2Variables) && this->getAbstractionInformation().encodeAux(0, 0, this->getAbstractionInformation().getAuxVariableCount()); return result; } @@ -695,10 +730,15 @@ namespace storm { return abstractionInformation.get(); } + template + void EdgeAbstractor::notifyGuardIsPredicate() { + skipBottomStates = true; + } + template class EdgeAbstractor; template class EdgeAbstractor; #ifdef STORM_HAVE_CARL - template class EdgeAbstractor; + template class EdgeAbstractor; #endif } } diff --git a/src/storm/abstraction/jani/EdgeAbstractor.h b/src/storm/abstraction/jani/EdgeAbstractor.h index ac88b6b04..8c02e8b76 100644 --- a/src/storm/abstraction/jani/EdgeAbstractor.h +++ b/src/storm/abstraction/jani/EdgeAbstractor.h @@ -58,7 +58,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use an edge decomposition during abstraction. */ - EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + EdgeAbstractor(uint64_t edgeId, storm::jani::Edge const& edge, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); /*! * Refines the abstract edge with the given predicates. @@ -72,12 +72,22 @@ namespace storm { */ storm::expressions::Expression const& getGuard() const; + /*! + * Retrieves the number of updates of this edge. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given * auxiliary choice. */ std::map getVariableUpdates(uint64_t auxiliaryChoice) const; + /*! + * Retrieves the assigned variables. + */ + std::set const& getAssignedVariables() const; + /*! * Computes the abstraction of the edge wrt. to the current set of predicates. * @@ -111,6 +121,8 @@ namespace storm { */ storm::jani::Edge const& getConcreteEdge() const; + void notifyGuardIsPredicate(); + private: /*! * Determines the relevant predicates for source as well as successor states wrt. to the given assignments @@ -175,21 +187,14 @@ namespace storm { * Recomputes the cached BDD using the decomposition. */ void recomputeCachedBddWithDecomposition(); - - /*! - * Computes the missing state identities. - * - * @return A BDD that represents the all missing state identities. - */ - storm::dd::Bdd computeMissingIdentities() const; /*! - * Computes the missing state identities for the updates. + * Computes the missing state identities for the destinations. * * @return A BDD that represents the state identities for predicates that are irrelevant for the * successor states. */ - storm::dd::Bdd computeMissingUpdateIdentities() const; + storm::dd::Bdd computeMissingDestinationIdentities() const; /*! * Retrieves the abstraction information object. @@ -204,15 +209,7 @@ namespace storm { * @return The abstraction information object. */ AbstractionInformation& getAbstractionInformation(); - - /*! - * Computes the globally missing state identities. - * - * @return A BDD that represents the global state identities for predicates that are irrelevant for the - * source and successor states. - */ - storm::dd::Bdd computeMissingGlobalIdentities() const; - + // An SMT responsible for this abstract command. std::unique_ptr smtSolver; @@ -225,6 +222,9 @@ namespace storm { // The concrete edge this abstract command refers to. std::reference_wrapper edge; + // The variables to which this edge assigns expressions. + std::set assignedVariables; + // The local expression-related information. LocalExpressionInformation localExpressionInformation; @@ -246,6 +246,9 @@ namespace storm { // A flag indicating whether to use the decomposition when abstracting. bool useDecomposition; + + // Whether or not to add predicates indirectly related to assignment variables to relevant source predicates. + bool addPredicatesForValidBlocks; // A flag indicating whether the computation of bottom states can be skipped (for example, if the bottom // states become empty at some point). @@ -260,6 +263,9 @@ namespace storm { // A state-set abstractor used to determine the bottom states if not all guards were added. StateSetAbstractor bottomStateAbstractor; + + // A flag that indicates whether or not debug mode is enabled. + bool debug; }; } } diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp index b3c7a755a..991870ede 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.cpp @@ -17,6 +17,7 @@ #include "storm/settings/SettingsManager.h" +#include "storm/utility/Stopwatch.h" #include "storm/utility/dd.h" #include "storm/utility/macros.h" #include "storm/utility/solver.h" @@ -34,10 +35,10 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager())), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { + JaniMenuGameAbstractor::JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options) : model(model), smtSolverFactory(smtSolverFactory), abstractionInformation(model.getManager(), model.getAllExpressionVariables(), smtSolverFactory->create(model.getManager()), AbstractionInformationOptions(options.constraints)), automata(), initialStateAbstractor(abstractionInformation, {model.getInitialStatesExpression()}, this->smtSolverFactory), restrictToValidBlocks(false), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(true) { // Check whether the model is linear as the abstraction requires this. - STORM_LOG_THROW(model.isLinear(), storm::exceptions::WrongFormatException, "Cannot create abstract model from non-linear model."); + STORM_LOG_WARN_COND(model.isLinear(), "The model appears to contain non-linear expressions, which may cause malfunctioning of the abstraction."); // For now, we assume that there is a single module. If the program has more than one module, it needs // to be flattened before the procedure. @@ -47,28 +48,33 @@ namespace storm { for (auto const& range : this->model.get().getAllRangeExpressions()) { abstractionInformation.addConstraint(range); initialStateAbstractor.constrain(range); + validBlockAbstractor.constrain(range); } - uint_fast64_t totalNumberOfCommands = 0; - uint_fast64_t maximalUpdateCount = 0; + uint_fast64_t totalNumberOfEdges = 0; + uint_fast64_t maximalDestinationCount = 0; std::vector allGuards; for (auto const& automaton : model.getAutomata()) { for (auto const& edge : automaton.getEdges()) { - maximalUpdateCount = std::max(maximalUpdateCount, static_cast(edge.getNumberOfDestinations())); + maximalDestinationCount = std::max(maximalDestinationCount, static_cast(edge.getNumberOfDestinations())); } - totalNumberOfCommands += automaton.getNumberOfEdges(); + totalNumberOfEdges += automaton.getNumberOfEdges(); } - // NOTE: currently we assume that 100 player 2 variables suffice, which corresponds to 2^100 possible + // NOTE: currently we assume that 64 player 2 variables suffice, which corresponds to 2^64 possible // choices. If for some reason this should not be enough, we could grow this vector dynamically, but // odds are that it's impossible to treat such models in any event. - abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 100, static_cast(std::ceil(std::log2(maximalUpdateCount)))); + abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfEdges))), 64, static_cast(std::ceil(std::log2(maximalDestinationCount)))); // For each module of the concrete program, we create an abstract counterpart. - bool useDecomposition = storm::settings::getModule().isUseDecompositionSet(); + auto const& settings = storm::settings::getModule(); + bool useDecomposition = settings.isUseDecompositionSet(); + restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration; + bool addPredicatesForValidBlocks = !restrictToValidBlocks; + bool debug = settings.isDebugSet(); for (auto const& automaton : model.getAutomata()) { - automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition); + automata.emplace_back(automaton, abstractionInformation, this->smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); } // Retrieve global BDDs/ADDs so we can multiply them in the abstraction process. @@ -93,8 +99,10 @@ namespace storm { // Refine initial state abstractor. initialStateAbstractor.refine(predicateIndices); - // Refine the valid blocks. - validBlockAbstractor.refine(predicateIndices); + if (this->restrictToValidBlocks) { + // Refine the valid blocks. + validBlockAbstractor.refine(predicateIndices); + } refinementPerformed |= !command.getPredicates().empty(); } @@ -103,7 +111,7 @@ namespace storm { MenuGame JaniMenuGameAbstractor::abstract() { if (refinementPerformed) { currentGame = buildGame(); - refinementPerformed = true; + refinementPerformed = false; } return *currentGame; } @@ -118,11 +126,21 @@ namespace storm { return automata.front().getGuard(player1Choice); } + template + uint64_t JaniMenuGameAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return automata.front().getNumberOfUpdates(player1Choice); + } + template std::map JaniMenuGameAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return automata.front().getVariableUpdates(player1Choice, auxiliaryChoice); } + template + std::set const& JaniMenuGameAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return automata.front().getAssignedVariables(player1Choice); + } + template std::pair JaniMenuGameAbstractor::getPlayer1ChoiceRange() const { return std::make_pair(0, automata.front().getNumberOfEdges()); @@ -141,7 +159,7 @@ namespace storm { template std::unique_ptr> JaniMenuGameAbstractor::buildGame() { - // As long as there is only one module, we only build its game representation. + // As long as there is only one automaton, we only build its game representation. GameBddResult game = automata.front().abstract(); // Add the locations to the transitions. @@ -149,17 +167,64 @@ namespace storm { // Construct a set of all unnecessary variables, so we can abstract from it. std::set variablesToAbstract(abstractionInformation.getPlayer1VariableSet(abstractionInformation.getPlayer1VariableCount())); + std::set successorAndAuxVariables(abstractionInformation.getSuccessorVariables()); auto player2Variables = abstractionInformation.getPlayer2VariableSet(game.numberOfPlayer2Variables); variablesToAbstract.insert(player2Variables.begin(), player2Variables.end()); auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); + successorAndAuxVariables.insert(auxVariables.begin(), auxVariables.end()); - // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd transitionRelation = game.bdd.existsAbstract(variablesToAbstract); + storm::utility::Stopwatch relevantStatesWatch(true); + storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); + if (this->isRestrictToRelevantStatesSet()) { + // Compute which states are non-terminal. + for (auto const& expression : this->terminalStateExpressions) { + nonTerminalStates &= !this->getStates(expression); + } + if (this->hasTargetStateExpression()) { + nonTerminalStates &= !this->getStates(this->getTargetStateExpression()); + } + } + relevantStatesWatch.stop(); + + storm::dd::Bdd extendedTransitionRelation = nonTerminalStates && game.bdd; storm::dd::Bdd initialStates = initialLocationsBdd && initialStateAbstractor.getAbstractStates(); + if (this->restrictToValidBlocks) { + STORM_LOG_DEBUG("Restricting to valid blocks."); + storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + + // Compute the choices with only valid successors so we can restrict the game to these. + auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + + // Restrict the proper parts. + extendedTransitionRelation &= validBlocks && choicesWithOnlyValidSuccessors; + initialStates &= validBlocks; + } + + // Do a reachability analysis on the raw transition relation. + storm::dd::Bdd transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract); initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + relevantStatesWatch.start(); + if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { + // Get the target state BDD. + storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); + + // In the presence of target states, we keep only states that can reach the target states. + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + + // Include all successors of reachable states, because the backward search otherwise potentially + // cuts probability 0 choices of these states. + reachableStates |= (reachableStates && !targetStates).relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + + // Restrict transition relation to relevant fragment for computation of deadlock states. + transitionRelation &= reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs()); + + relevantStatesWatch.stop(); + STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); + } + // Find the deadlock states in the model. Note that this does not find the 'deadlocks' in bottom states, // as the bottom states are not contained in the reachable states. storm::dd::Bdd deadlockStates = transitionRelation.existsAbstract(abstractionInformation.getSuccessorVariables()); @@ -177,7 +242,9 @@ namespace storm { bool hasBottomStates = !bottomStateResult.states.isZero(); // Construct the transition matrix by cutting away the transitions of unreachable states. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates).template toAdd(); + // Note that we also restrict the successor states of transitions, because there might be successors + // that are not in the set of relevant states we restrict to. + storm::dd::Add transitionMatrix = (extendedTransitionRelation && reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= edgeDecoratorAdd; transitionMatrix += deadlockTransitions; @@ -208,11 +275,28 @@ namespace storm { this->exportToDot(*currentGame, filename, highlightStates, filter); } + template + uint64_t JaniMenuGameAbstractor::getNumberOfPredicates() const { + return abstractionInformation.getNumberOfPredicates(); + } + + template + void JaniMenuGameAbstractor::addTerminalStates(storm::expressions::Expression const& expression) { + terminalStateExpressions.emplace_back(expression); + } + + template + void JaniMenuGameAbstractor::notifyGuardsArePredicates() { + for (auto& automaton : automata) { + automaton.notifyGuardsArePredicates(); + } + } + // Explicitly instantiate the class. template class JaniMenuGameAbstractor; template class JaniMenuGameAbstractor; #ifdef STORM_HAVE_CARL - template class JaniMenuGameAbstractor; + template class JaniMenuGameAbstractor; #endif } } diff --git a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h index 3a478fcb0..2017b2c17 100644 --- a/src/storm/abstraction/jani/JaniMenuGameAbstractor.h +++ b/src/storm/abstraction/jani/JaniMenuGameAbstractor.h @@ -46,7 +46,7 @@ namespace storm { * @param model The concrete model for which to build the abstraction. * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. */ - JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory); + JaniMenuGameAbstractor(storm::jani::Model const& model, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options = MenuGameAbstractorOptions()); JaniMenuGameAbstractor(JaniMenuGameAbstractor const&) = default; JaniMenuGameAbstractor& operator=(JaniMenuGameAbstractor const&) = default; @@ -75,12 +75,22 @@ namespace storm { */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const override; + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const override; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const override; + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + virtual std::set const& getAssignedVariables(uint64_t player1Choice) const override; + /*! * Retrieves the range of player 1 choices. */ @@ -107,8 +117,14 @@ namespace storm { * @param highlightStates A BDD characterizing states that will be highlighted. * @param filter A filter that is applied to select which part of the game to export. */ - void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; + virtual void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; + virtual uint64_t getNumberOfPredicates() const override; + + virtual void addTerminalStates(storm::expressions::Expression const& expression) override; + + virtual void notifyGuardsArePredicates() override; + protected: using MenuGameAbstractor::exportToDot; @@ -143,6 +159,9 @@ namespace storm { // A state-set abstractor used to determine the initial states of the abstraction. StateSetAbstractor initialStateAbstractor; + // A flag indicating whether the valid blocks need to be computed and the game restricted to these. + bool restrictToValidBlocks; + // An object that is used to compute the valid blocks. ValidBlockAbstractor validBlockAbstractor; @@ -157,6 +176,9 @@ namespace storm { // A flag storing whether a refinement was performed. bool refinementPerformed; + + // A list of terminal state expressions. + std::vector terminalStateExpressions; }; } } diff --git a/src/storm/abstraction/prism/CommandAbstractor.cpp b/src/storm/abstraction/prism/CommandAbstractor.cpp index afc859e01..ecb415655 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.cpp +++ b/src/storm/abstraction/prism/CommandAbstractor.cpp @@ -23,7 +23,7 @@ namespace storm { namespace abstraction { namespace prism { template - CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory) { + CommandAbstractor::CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), useDecomposition(useDecomposition), addPredicatesForValidBlocks(addPredicatesForValidBlocks), skipBottomStates(false), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, {!command.getGuardExpression()}, smtSolverFactory), debug(debug) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates()); @@ -36,6 +36,18 @@ namespace storm { // Assert the guard of the command. smtSolver->add(command.getGuardExpression()); + + // Construct assigned variables. + for (auto const& update : command.getUpdates()) { + for (auto const& assignment : update.getAssignments()) { + assignedVariables.insert(assignment.getVariable()); + } + } + + // Log whether or not predicates are added to ensure valid blocks. + if (this->addPredicatesForValidBlocks) { + STORM_LOG_DEBUG("Adding more predicates to ensure valid blocks."); + } } template @@ -65,11 +77,21 @@ namespace storm { return command.get().getGuardExpression(); } + template + uint64_t CommandAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return command.get().getNumberOfUpdates(); + } + template std::map CommandAbstractor::getVariableUpdates(uint64_t auxiliaryChoice) const { return command.get().getUpdate(auxiliaryChoice).getAsVariableToExpressionMap(); } + template + std::set const& CommandAbstractor::getAssignedVariables() const { + return assignedVariables; + } + template void CommandAbstractor::recomputeCachedBdd() { if (useDecomposition) { @@ -81,7 +103,7 @@ namespace storm { template void CommandAbstractor::recomputeCachedBddWithDecomposition() { - STORM_LOG_TRACE("Recomputing BDD for command " << command.get() << " using the decomposition."); + STORM_LOG_TRACE("Recomputing BDD for command " << command.get() << " [with index " << command.get().getGlobalIndex() << "] using the decomposition."); auto start = std::chrono::high_resolution_clock::now(); // compute a decomposition of the command @@ -162,7 +184,6 @@ namespace storm { } relevantBlockPartition[representativeBlock].insert(relevantBlockPartition[assignmentVariableBlock].begin(), relevantBlockPartition[assignmentVariableBlock].end()); relevantBlockPartition[assignmentVariableBlock].clear(); - } } } @@ -171,200 +192,231 @@ namespace storm { // Now remove all blocks that are empty and obtain the partition. std::vector> cleanedRelevantBlockPartition; - for (auto& element : relevantBlockPartition) { - if (!element.empty()) { - cleanedRelevantBlockPartition.emplace_back(std::move(element)); + for (auto& outerBlock : relevantBlockPartition) { + if (!outerBlock.empty()) { + cleanedRelevantBlockPartition.emplace_back(); + + for (auto const& innerBlock : outerBlock) { + if (!localExpressionInformation.getExpressionBlock(innerBlock).empty()) { + cleanedRelevantBlockPartition.back().insert(innerBlock); + } + } + + if (cleanedRelevantBlockPartition.back().empty()) { + cleanedRelevantBlockPartition.pop_back(); + } } } relevantBlockPartition = std::move(cleanedRelevantBlockPartition); - // if the decomposition has size 1, use the plain technique from before - if (relevantBlockPartition.size() == 1) { - STORM_LOG_TRACE("Relevant block partition size is one, falling back to regular computation."); - recomputeCachedBddWithoutDecomposition(); - } else { - std::set variablesContainedInGuard = command.get().getGuardExpression().getVariables(); - - // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard - // are not contained within a single block of our decomposition. - bool enumerateAbstractGuard = true; - std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + STORM_LOG_TRACE("Decomposition into " << relevantBlockPartition.size() << " blocks."); + if (this->debug) { + uint64_t blockIndex = 0; for (auto const& block : relevantBlockPartition) { - bool allContained = true; - for (auto const& guardBlock : guardBlocks) { - if (block.find(guardBlock) == block.end()) { - allContained = false; - break; - } - } - if (allContained) { - enumerateAbstractGuard = false; - } - } - - uint64_t numberOfSolutions = 0; - - if (enumerateAbstractGuard) { - // otherwise, enumerate the abstract guard so we do this only once - std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); - std::vector guardDecisionVariables; - std::vector> guardVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { - guardDecisionVariables.push_back(element.first); - guardVariablesAndPredicates.push_back(element); - } + STORM_LOG_TRACE("Predicates of block " << blockIndex << ":"); + std::set blockPredicateIndices; + for (auto const& innerBlock : block) { + blockPredicateIndices.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); } - abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); - smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { - abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " for abstract guard."); - - // now that we have the abstract guard, we can add it as an assertion to the solver before enumerating - // the other solutions. - - // Create a new backtracking point before adding the guard. - smtSolver->push(); - - // Create the guard constraint. - std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); - // Then add it to the solver. - for (auto const& expression : result.first) { - smtSolver->add(expression); + for (auto const& predicateIndex : blockPredicateIndices) { + STORM_LOG_TRACE(abstractionInformation.get().getPredicateByIndex(predicateIndex)); } - // Finally associate the level variables with the predicates. - for (auto const& indexVariablePair : result.second) { - smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + ++blockIndex; + } + } + + std::set variablesContainedInGuard = command.get().getGuardExpression().getVariables(); + + // Check whether we need to enumerate the guard. This is the case if the blocks related by the guard + // are not contained within a single block of our decomposition. + bool enumerateAbstractGuard = true; + std::set guardBlocks = localExpressionInformation.getBlockIndicesOfVariables(variablesContainedInGuard); + for (auto const& block : relevantBlockPartition) { + bool allContained = true; + for (auto const& guardBlock : guardBlocks) { + if (block.find(guardBlock) == block.end()) { + allContained = false; + break; } } - - // then enumerate the solutions for each of the blocks of the decomposition - uint64_t usedNondeterminismVariables = 0; - uint64_t blockCounter = 0; - std::vector> blockBdds; - for (auto const& block : relevantBlockPartition) { - std::set relevantPredicates; - for (auto const& innerBlock : block) { - relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + if (allContained) { + enumerateAbstractGuard = false; + } + } + + uint64_t numberOfSolutions = 0; + uint64_t numberOfTotalSolutions = 0; + + // If we need to enumerate the guard, do it only once now. + if (enumerateAbstractGuard) { + std::set relatedGuardPredicates = localExpressionInformation.getRelatedExpressions(variablesContainedInGuard); + std::vector guardDecisionVariables; + std::vector> guardVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relatedGuardPredicates.find(element.second) != relatedGuardPredicates.end()) { + guardDecisionVariables.push_back(element.first); + guardVariablesAndPredicates.push_back(element); } - - std::vector transitionDecisionVariables; - std::vector> sourceVariablesAndPredicates; - for (auto const& element : relevantPredicatesAndVariables.first) { - if (relevantPredicates.find(element.second) != relevantPredicates.end()) { - transitionDecisionVariables.push_back(element.first); - sourceVariablesAndPredicates.push_back(element); - } + } + abstractGuard = this->getAbstractionInformation().getDdManager().getBddZero(); + smtSolver->allSat(guardDecisionVariables, [this,&guardVariablesAndPredicates,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) { + abstractGuard |= getSourceStateBdd(model, guardVariablesAndPredicates); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for abstract guard."); + + // Now that we have the abstract guard, we can add it as an assertion to the solver before enumerating + // the other solutions. + + // Create a new backtracking point before adding the guard. + smtSolver->push(); + + // Create the guard constraint. + std::pair, std::unordered_map> result = abstractGuard.toExpression(this->getAbstractionInformation().getExpressionManager()); + + // Then add it to the solver. + for (auto const& expression : result.first) { + smtSolver->add(expression); + } + + // Finally associate the level variables with the predicates. + for (auto const& indexVariablePair : result.second) { + smtSolver->add(storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first))); + } + } + + // Then enumerate the solutions for each of the blocks of the decomposition. + uint64_t usedNondeterminismVariables = 0; + uint64_t blockCounter = 0; + std::vector> blockBdds; + for (auto const& block : relevantBlockPartition) { + std::set relevantPredicates; + for (auto const& innerBlock : block) { + relevantPredicates.insert(localExpressionInformation.getExpressionBlock(innerBlock).begin(), localExpressionInformation.getExpressionBlock(innerBlock).end()); + } + + if (relevantPredicates.empty()) { + STORM_LOG_TRACE("Block does not contain relevant predicates, skipping it."); + continue; + } + + std::vector transitionDecisionVariables; + std::vector> sourceVariablesAndPredicates; + for (auto const& element : relevantPredicatesAndVariables.first) { + if (relevantPredicates.find(element.second) != relevantPredicates.end()) { + transitionDecisionVariables.push_back(element.first); + sourceVariablesAndPredicates.push_back(element); } - - std::vector>> destinationVariablesAndPredicates; - for (uint64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { - destinationVariablesAndPredicates.emplace_back(); - for (auto const& assignment : command.get().getUpdate(updateIndex).getAssignments()) { - uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable()); + } + + std::vector>> destinationVariablesAndPredicates; + for (uint64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { + destinationVariablesAndPredicates.emplace_back(); + for (auto const& assignment : command.get().getUpdate(updateIndex).getAssignments()) { + uint64_t assignmentVariableBlockIndex = localExpressionInformation.getBlockIndexOfVariable(assignment.getVariable()); + + if (block.find(assignmentVariableBlockIndex) != block.end()) { std::set const& assignmentVariableBlock = localExpressionInformation.getExpressionBlock(assignmentVariableBlockIndex); - if (block.find(assignmentVariableBlockIndex) != block.end()) { - for (auto const& element : relevantPredicatesAndVariables.second[updateIndex]) { - if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { - destinationVariablesAndPredicates.back().push_back(element); - transitionDecisionVariables.push_back(element.first); - } + for (auto const& element : relevantPredicatesAndVariables.second[updateIndex]) { + if (assignmentVariableBlock.find(element.second) != assignmentVariableBlock.end()) { + destinationVariablesAndPredicates.back().push_back(element); + transitionDecisionVariables.push_back(element.first); } } } } - - std::unordered_map, std::vector>> sourceToDistributionsMap; - numberOfSolutions = 0; - smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { - sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); - ++numberOfSolutions; - return true; - }); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); - numberOfSolutions = 0; - - // Now we search for the maximal number of choices of player 2 to determine how many DD variables we - // need to encode the nondeterminism. - uint_fast64_t maximalNumberOfChoices = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); - } - - // We now compute how many variables we need to encode the choices. We add one to the maximal number of - // choices to account for a possible transition to a bottom state. - uint_fast64_t numberOfVariablesNeeded = static_cast(std::ceil(std::log2(maximalNumberOfChoices + 1))); - - // Finally, build overall result. - storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); - - uint_fast64_t sourceStateIndex = 0; - for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { - STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); - STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - // We start with the distribution index of 1, becase 0 is reserved for a potential bottom choice. - uint_fast64_t distributionIndex = 1; - storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); - for (auto const& distribution : sourceDistributionsPair.second) { - allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); - ++distributionIndex; - STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); - } - resultBdd |= sourceDistributionsPair.first && allDistributions; - ++sourceStateIndex; - STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); - } - usedNondeterminismVariables += numberOfVariablesNeeded; - - blockBdds.push_back(resultBdd); - ++blockCounter; } - if (enumerateAbstractGuard) { - smtSolver->pop(); - } + std::unordered_map, std::vector>> sourceToDistributionsMap; + numberOfSolutions = 0; + smtSolver->allSat(transitionDecisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions,&sourceVariablesAndPredicates,&destinationVariablesAndPredicates] (storm::solver::SmtSolver::ModelReference const& model) { + sourceToDistributionsMap[getSourceStateBdd(model, sourceVariablesAndPredicates)].push_back(getDistributionBdd(model, destinationVariablesAndPredicates)); + ++numberOfSolutions; + return true; + }); + STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions for block " << blockCounter << "."); + numberOfTotalSolutions += numberOfSolutions; - // multiply the results - storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& blockBdd : blockBdds) { - resultBdd &= blockBdd; + // Now we search for the maximal number of choices of player 2 to determine how many DD variables we + // need to encode the nondeterminism. + uint_fast64_t maximalNumberOfChoices = 0; + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast(sourceDistributionsPair.second.size())); } - // if we did not explicitly enumerate the guard, we can construct it from the result BDD. - if (!enumerateAbstractGuard) { - std::set allVariables(getAbstractionInformation().getSuccessorVariables()); - auto player2Variables = getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); - allVariables.insert(player2Variables.begin(), player2Variables.end()); - auto auxVariables = getAbstractionInformation().getAuxVariableSet(0, getAbstractionInformation().getAuxVariableCount()); - allVariables.insert(auxVariables.begin(), auxVariables.end()); - - std::set variablesToAbstract; - std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); + // We now compute how many variables we need to encode the choices. We add one to the maximal number of + // choices to account for a possible transition to a bottom state. + uint_fast64_t numberOfVariablesNeeded = (maximalNumberOfChoices > 1) ? (static_cast(std::ceil(std::log2(maximalNumberOfChoices + (blockCounter == 0 ? 1 : 0))))) : (blockCounter == 0 ? 1 : 0); + + // Finally, build overall result. + storm::dd::Bdd resultBdd = this->getAbstractionInformation().getDdManager().getBddZero(); + + for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { + STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty."); + STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty."); - abstractGuard = resultBdd.existsAbstract(variablesToAbstract); - } else { - // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. - resultBdd &= abstractGuard; + // We start with the distribution index of 1, because 0 is reserved for a potential bottom choice. + uint_fast64_t distributionIndex = blockCounter == 0 ? 1 : 0; + storm::dd::Bdd allDistributions = this->getAbstractionInformation().getDdManager().getBddZero(); + for (auto const& distribution : sourceDistributionsPair.second) { + allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, usedNondeterminismVariables, usedNondeterminismVariables + numberOfVariablesNeeded); + ++distributionIndex; + STORM_LOG_ASSERT(!allDistributions.isZero(), "The BDD must not be empty."); + } + resultBdd |= sourceDistributionsPair.first && allDistributions; + STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } + usedNondeterminismVariables += numberOfVariablesNeeded; - // multiply with missing identities - resultBdd &= computeMissingIdentities(); - - // cache and return result - resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); + blockBdds.push_back(resultBdd); + ++blockCounter; + } + + if (enumerateAbstractGuard) { + smtSolver->pop(); + } + + // multiply the results + storm::dd::Bdd resultBdd = getAbstractionInformation().getDdManager().getBddOne(); + uint64_t blockIndex = 0; + for (auto const& blockBdd : blockBdds) { + resultBdd &= blockBdd; + ++blockIndex; + } + + // If we did not explicitly enumerate the guard, we can construct it from the result BDD. + if (!enumerateAbstractGuard) { + std::set allVariables(getAbstractionInformation().getSuccessorVariables()); + auto player2Variables = getAbstractionInformation().getPlayer2VariableSet(usedNondeterminismVariables); + allVariables.insert(player2Variables.begin(), player2Variables.end()); + auto auxVariables = getAbstractionInformation().getAuxVariableSet(0, getAbstractionInformation().getAuxVariableCount()); + allVariables.insert(auxVariables.begin(), auxVariables.end()); - // Cache the result. - cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + std::set variablesToAbstract; + std::set_intersection(allVariables.begin(), allVariables.end(), resultBdd.getContainedMetaVariables().begin(), resultBdd.getContainedMetaVariables().end(), std::inserter(variablesToAbstract, variablesToAbstract.begin())); - auto end = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); - forceRecomputation = false; + abstractGuard = resultBdd.existsAbstract(variablesToAbstract); + } else { + // Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks. + resultBdd &= abstractGuard; } + + // multiply with missing identities + resultBdd &= computeMissingUpdateIdentities(); + + // cache and return result + resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); + + // Cache the result. + cachedDd = GameBddResult(resultBdd, usedNondeterminismVariables); + + auto end = std::chrono::high_resolution_clock::now(); + + STORM_LOG_TRACE("Enumerated " << numberOfTotalSolutions << " solutions in " << std::chrono::duration_cast(end - start).count() << "ms."); + forceRecomputation = false; } template @@ -416,7 +468,7 @@ namespace storm { STORM_LOG_ASSERT(!resultBdd.isZero(), "The BDD must not be empty."); } - resultBdd &= computeMissingIdentities(); + resultBdd &= computeMissingUpdateIdentities(); resultBdd &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()); STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions."); @@ -435,21 +487,21 @@ namespace storm { std::set assignedVariables; for (auto const& assignment : assignments) { // Also, variables appearing on the right-hand side of an assignment are relevant for source state. - auto const& rightHandSidePredicates = localExpressionInformation.getRelatedExpressions(assignment.getExpression().getVariables()); + auto const& rightHandSidePredicates = localExpressionInformation.getExpressionsUsingVariables(assignment.getExpression().getVariables()); result.first.insert(rightHandSidePredicates.begin(), rightHandSidePredicates.end()); // Variables that are being assigned are relevant for the successor state. storm::expressions::Variable const& assignedVariable = assignment.getVariable(); - auto const& leftHandSidePredicates = localExpressionInformation.getRelatedExpressions(assignedVariable); + auto const& leftHandSidePredicates = localExpressionInformation.getExpressionsUsingVariable(assignedVariable); result.second.insert(leftHandSidePredicates.begin(), leftHandSidePredicates.end()); - // Keep track of all assigned variables, so we can find the related predicates later. - assignedVariables.insert(assignedVariable); + // Predicates that are indirectly related to the assigned variables are relevant for the source state (if requested). + if (this->addPredicatesForValidBlocks) { + auto const& assignedVariableBlock = localExpressionInformation.getRelatedExpressions(assignedVariable); + result.first.insert(assignedVariableBlock.begin(), assignedVariableBlock.end()); + } } - auto const& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables); - result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end()); - return result; } @@ -458,7 +510,7 @@ namespace storm { std::pair, std::vector>> result; // To start with, all predicates related to the guard are relevant source predicates. - result.first = localExpressionInformation.getRelatedExpressions(command.get().getGuardExpression().getVariables()); + result.first = localExpressionInformation.getExpressionsUsingVariables(command.get().getGuardExpression().getVariables()); // Then, we add the predicates that become relevant, because of some update. for (auto const& update : command.get().getUpdates()) { @@ -467,6 +519,18 @@ namespace storm { result.second.push_back(relevantUpdatePredicates.second); } +// std::cout << "relevant predicates for command " << command.get().getGlobalIndex() << std::endl; +// std::cout << "source predicates" << std::endl; +// for (auto const& i : result.first) { +// std::cout << this->getAbstractionInformation().getPredicateByIndex(i) << std::endl; +// } +// for (uint64_t i = 0; i < result.second.size(); ++i) { +// std::cout << "destination " << i << std::endl; +// for (auto const& j : result.second[i]) { +// std::cout << this->getAbstractionInformation().getPredicateByIndex(j) << std::endl; +// } +// } + return result; } @@ -516,7 +580,8 @@ namespace storm { template storm::dd::Bdd CommandAbstractor::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model, std::vector> const& variablePredicates) const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - for (auto const& variableIndexPair : variablePredicates) { + for (auto variableIndexPairIt = variablePredicates.rbegin(), variableIndexPairIte = variablePredicates.rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second); } else { @@ -536,15 +601,16 @@ namespace storm { storm::dd::Bdd updateBdd = this->getAbstractionInformation().getDdManager().getBddOne(); // Translate block variables for this update into a successor block. - for (auto const& variableIndexPair : variablePredicates[updateIndex]) { + for (auto variableIndexPairIt = variablePredicates[updateIndex].rbegin(), variableIndexPairIte = variablePredicates[updateIndex].rend(); variableIndexPairIt != variableIndexPairIte; ++variableIndexPairIt) { + auto const& variableIndexPair = *variableIndexPairIt; if (model.getBooleanValue(variableIndexPair.first)) { updateBdd &= this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } else { updateBdd &= !this->getAbstractionInformation().encodePredicateAsSuccessor(variableIndexPair.second); } - updateBdd &= this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } - + + updateBdd &= this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); result |= updateBdd; } @@ -552,66 +618,39 @@ namespace storm { return result; } - template - storm::dd::Bdd CommandAbstractor::computeMissingIdentities() const { - storm::dd::Bdd identities = computeMissingGlobalIdentities(); - identities &= computeMissingUpdateIdentities(); - return identities; - } - template storm::dd::Bdd CommandAbstractor::computeMissingUpdateIdentities() const { storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddZero(); for (uint_fast64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { // Compute the identities that are missing for this update. - auto updateRelevantIt = relevantPredicatesAndVariables.second[updateIndex].begin(); - auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].end(); + auto updateRelevantIt = relevantPredicatesAndVariables.second[updateIndex].rbegin(); + auto updateRelevantIte = relevantPredicatesAndVariables.second[updateIndex].rend(); storm::dd::Bdd updateIdentity = this->getAbstractionInformation().getDdManager().getBddOne(); - auto sourceRelevantIt = relevantPredicatesAndVariables.first.begin(); - auto sourceRelevantIte = relevantPredicatesAndVariables.first.end(); - - // Go through all relevant source predicates. This is guaranteed to be a superset of the set of - // relevant successor predicates for any update. - for (; sourceRelevantIt != sourceRelevantIte; ++sourceRelevantIt) { - // If the predicates do not match, there is a predicate missing, so we need to add its identity. - if (updateRelevantIt == updateRelevantIte || sourceRelevantIt->second != updateRelevantIt->second) { - updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(sourceRelevantIt->second); + for (uint_fast64_t predicateIndex = this->getAbstractionInformation().getNumberOfPredicates() - 1;; --predicateIndex) { + if (updateRelevantIt == updateRelevantIte || updateRelevantIt->second != predicateIndex) { + updateIdentity &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); } else { ++updateRelevantIt; } + + if (predicateIndex == 0) { + break; + } } - + result |= updateIdentity && this->getAbstractionInformation().encodeAux(updateIndex, 0, this->getAbstractionInformation().getAuxVariableCount()); } return result; } - template - storm::dd::Bdd CommandAbstractor::computeMissingGlobalIdentities() const { - storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddOne(); - - auto relevantIt = relevantPredicatesAndVariables.first.begin(); - auto relevantIte = relevantPredicatesAndVariables.first.end(); - - for (uint_fast64_t predicateIndex = 0; predicateIndex < this->getAbstractionInformation().getNumberOfPredicates(); ++predicateIndex) { - if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { - result &= this->getAbstractionInformation().getPredicateIdentity(predicateIndex); - } else { - ++relevantIt; - } - } - - return result; - } - template GameBddResult CommandAbstractor::abstract() { if (forceRecomputation) { this->recomputeCachedBdd(); } else { - cachedDd.bdd &= computeMissingGlobalIdentities(); + cachedDd.bdd &= computeMissingUpdateIdentities(); } STORM_LOG_TRACE("Command produces " << cachedDd.bdd.getNonZeroCount() << " transitions."); @@ -679,10 +718,15 @@ namespace storm { return abstractionInformation.get(); } + template + void CommandAbstractor::notifyGuardIsPredicate() { + skipBottomStates = true; + } + template class CommandAbstractor; template class CommandAbstractor; #ifdef STORM_HAVE_CARL - template class CommandAbstractor; + template class CommandAbstractor; #endif } } diff --git a/src/storm/abstraction/prism/CommandAbstractor.h b/src/storm/abstraction/prism/CommandAbstractor.h index b26492125..e6f8f6a6f 100644 --- a/src/storm/abstraction/prism/CommandAbstractor.h +++ b/src/storm/abstraction/prism/CommandAbstractor.h @@ -56,7 +56,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag indicating whether to use the decomposition during abstraction. */ - CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + CommandAbstractor(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); /*! * Refines the abstract command with the given predicates. @@ -70,12 +70,22 @@ namespace storm { */ storm::expressions::Expression const& getGuard() const; + /*! + * Retrieves the number of updates of this command. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given * auxiliary choice. */ std::map getVariableUpdates(uint64_t auxiliaryChoice) const; + /*! + * Retrieves the assigned variables. + */ + std::set const& getAssignedVariables() const; + /*! * Computes the abstraction of the command wrt. to the current set of predicates. * @@ -107,6 +117,8 @@ namespace storm { */ storm::prism::Command const& getConcreteCommand() const; + void notifyGuardIsPredicate(); + private: /*! * Determines the relevant predicates for source as well as successor states wrt. to the given assignments @@ -201,14 +213,6 @@ namespace storm { */ AbstractionInformation& getAbstractionInformation(); - /*! - * Computes the globally missing state identities. - * - * @return A BDD that represents the global state identities for predicates that are irrelevant for the - * source and successor states. - */ - storm::dd::Bdd computeMissingGlobalIdentities() const; - // An SMT responsible for this abstract command. std::unique_ptr smtSolver; @@ -218,6 +222,9 @@ namespace storm { // The concrete command this abstract command refers to. std::reference_wrapper command; + // The variables to which this command assigns expressions. + std::set assignedVariables; + // The local expression-related information. LocalExpressionInformation localExpressionInformation; @@ -240,6 +247,9 @@ namespace storm { // A flag indicating whether to use the decomposition when abstracting. bool useDecomposition; + // Whether or not to add predicates indirectly related to assignment variables to relevant source predicates. + bool addPredicatesForValidBlocks; + // A flag indicating whether the guard of the command was added as a predicate. If this is true, there // is no need to compute bottom states. bool skipBottomStates; @@ -253,6 +263,9 @@ namespace storm { // A state-set abstractor used to determine the bottom states if not all guards were added. StateSetAbstractor bottomStateAbstractor; + + // A flag that indicates whether or not debug mode is enabled. + bool debug; }; } } diff --git a/src/storm/abstraction/prism/ModuleAbstractor.cpp b/src/storm/abstraction/prism/ModuleAbstractor.cpp index 6ba51b062..f17d47df3 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.cpp +++ b/src/storm/abstraction/prism/ModuleAbstractor.cpp @@ -1,7 +1,7 @@ #include "storm/abstraction/prism/ModuleAbstractor.h" -#include "storm/abstraction/AbstractionInformation.h" #include "storm/abstraction/BottomStateResult.h" +#include "storm/abstraction/AbstractionInformation.h" #include "storm/abstraction/GameBddResult.h" #include "storm/storage/dd/DdManager.h" @@ -23,11 +23,11 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { + ModuleAbstractor::ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug) : smtSolverFactory(smtSolverFactory), abstractionInformation(abstractionInformation), commands(), module(module) { // For each concrete command, we create an abstract counterpart. for (auto const& command : module.getCommands()) { - commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition); + commands.emplace_back(command, abstractionInformation, smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); } } @@ -35,8 +35,7 @@ namespace storm { void ModuleAbstractor::refine(std::vector const& predicates) { for (uint_fast64_t index = 0; index < commands.size(); ++index) { STORM_LOG_TRACE("Refining command with index " << index << "."); - CommandAbstractor& command = commands[index]; - command.refine(predicates); + commands[index].refine(predicates); } } @@ -45,11 +44,21 @@ namespace storm { return commands[player1Choice].getGuard(); } + template + uint64_t ModuleAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return commands[player1Choice].getNumberOfUpdates(player1Choice); + } + template std::map ModuleAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return commands[player1Choice].getVariableUpdates(auxiliaryChoice); } + template + std::set const& ModuleAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return commands[player1Choice].getAssignedVariables(); + } + template GameBddResult ModuleAbstractor::abstract() { // First, we retrieve the abstractions of all commands. @@ -106,10 +115,17 @@ namespace storm { return abstractionInformation.get(); } + template + void ModuleAbstractor::notifyGuardsArePredicates() { + for (auto& command : commands) { + command.notifyGuardIsPredicate(); + } + } + template class ModuleAbstractor; template class ModuleAbstractor; #ifdef STORM_HAVE_CARL - template class ModuleAbstractor; + template class ModuleAbstractor; #endif } } diff --git a/src/storm/abstraction/prism/ModuleAbstractor.h b/src/storm/abstraction/prism/ModuleAbstractor.h index 3cfb21ca7..72a7bb492 100644 --- a/src/storm/abstraction/prism/ModuleAbstractor.h +++ b/src/storm/abstraction/prism/ModuleAbstractor.h @@ -38,7 +38,7 @@ namespace storm { * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param useDecomposition A flag that governs whether to use the decomposition in the abstraction. */ - ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition); + ModuleAbstractor(storm::prism::Module const& module, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool useDecomposition, bool addPredicatesForValidBlocks, bool debug); ModuleAbstractor(ModuleAbstractor const&) = default; ModuleAbstractor& operator=(ModuleAbstractor const&) = default; @@ -60,12 +60,22 @@ namespace storm { */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const; + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + uint64_t getNumberOfUpdates(uint64_t player1Choice) const; + /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const; + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + std::set const& getAssignedVariables(uint64_t player1Choice) const; + /*! * Computes the abstraction of the module wrt. to the current set of predicates. * @@ -103,6 +113,8 @@ namespace storm { */ std::vector>& getCommands(); + void notifyGuardsArePredicates(); + private: /*! * Retrieves the abstraction information. diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index 4cb3d46eb..9e018ce3e 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -15,6 +15,7 @@ #include "storm/settings/SettingsManager.h" +#include "storm/utility/Stopwatch.h" #include "storm/utility/dd.h" #include "storm/utility/macros.h" #include "storm/utility/solver.h" @@ -32,9 +33,8 @@ namespace storm { using storm::settings::modules::AbstractionSettings; template - PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, - std::shared_ptr const& smtSolverFactory) - : program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager(), program.getAllExpressionVariables(), smtSolverFactory->create(program.getManager())), modules(), initialStateAbstractor(abstractionInformation, {program.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(false) { + PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options) + : program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager(), program.getAllExpressionVariables(), smtSolverFactory->create(program.getManager()), AbstractionInformationOptions(options.constraints)), modules(), initialStateAbstractor(abstractionInformation, {program.getInitialStatesExpression()}, this->smtSolverFactory), validBlockAbstractor(abstractionInformation, smtSolverFactory), currentGame(nullptr), refinementPerformed(false) { // For now, we assume that there is a single module. If the program has more than one module, it needs // to be flattened before the procedure. @@ -44,6 +44,7 @@ namespace storm { for (auto const& range : this->program.get().getAllRangeExpressions()) { abstractionInformation.addConstraint(range); initialStateAbstractor.constrain(range); + validBlockAbstractor.constrain(range); } uint_fast64_t totalNumberOfCommands = 0; @@ -57,15 +58,19 @@ namespace storm { totalNumberOfCommands += module.getNumberOfCommands(); } - // NOTE: currently we assume that 100 player 2 variables suffice, which corresponds to 2^100 possible + // NOTE: currently we assume that 64 player 2 variables suffice, which corresponds to 2^64 possible // choices. If for some reason this should not be enough, we could grow this vector dynamically, but // odds are that it's impossible to treat such models in any event. - abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 100, static_cast(std::ceil(std::log2(maximalUpdateCount)))); + abstractionInformation.createEncodingVariables(static_cast(std::ceil(std::log2(totalNumberOfCommands))), 64, static_cast(std::ceil(std::log2(maximalUpdateCount)))); // For each module of the concrete program, we create an abstract counterpart. - bool useDecomposition = storm::settings::getModule().isUseDecompositionSet(); + auto const& settings = storm::settings::getModule(); + bool useDecomposition = settings.isUseDecompositionSet(); + restrictToValidBlocks = settings.getValidBlockMode() == storm::settings::modules::AbstractionSettings::ValidBlockMode::BlockEnumeration; + bool addPredicatesForValidBlocks = !restrictToValidBlocks; + bool debug = settings.isDebugSet(); for (auto const& module : program.getModules()) { - this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition); + this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, useDecomposition, addPredicatesForValidBlocks, debug); } // Retrieve the command-update probability ADD, so we can multiply it with the abstraction BDD later. @@ -80,7 +85,7 @@ namespace storm { STORM_LOG_THROW(predicate.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expecting a predicate of type bool."); predicateIndices.push_back(abstractionInformation.getOrAddPredicate(predicate)); } - + // Refine all abstract modules. for (auto& module : modules) { module.refine(predicateIndices); @@ -89,8 +94,10 @@ namespace storm { // Refine initial state abstractor. initialStateAbstractor.refine(predicateIndices); - // Refine the valid blocks. - validBlockAbstractor.refine(predicateIndices); + if (restrictToValidBlocks) { + // Refine the valid blocks. + validBlockAbstractor.refine(predicateIndices); + } refinementPerformed |= !command.getPredicates().empty(); } @@ -99,7 +106,7 @@ namespace storm { MenuGame PrismMenuGameAbstractor::abstract() { if (refinementPerformed) { currentGame = buildGame(); - refinementPerformed = true; + refinementPerformed = false; } return *currentGame; } @@ -114,11 +121,21 @@ namespace storm { return modules.front().getGuard(player1Choice); } + template + uint64_t PrismMenuGameAbstractor::getNumberOfUpdates(uint64_t player1Choice) const { + return modules.front().getNumberOfUpdates(player1Choice); + } + template std::map PrismMenuGameAbstractor::getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const { return modules.front().getVariableUpdates(player1Choice, auxiliaryChoice); } + template + std::set const& PrismMenuGameAbstractor::getAssignedVariables(uint64_t player1Choice) const { + return modules.front().getAssignedVariables(player1Choice); + } + template std::pair PrismMenuGameAbstractor::getPlayer1ChoiceRange() const { return std::make_pair(0, modules.front().getCommands().size()); @@ -142,16 +159,63 @@ namespace storm { // Construct a set of all unnecessary variables, so we can abstract from it. std::set variablesToAbstract(abstractionInformation.getPlayer1VariableSet(abstractionInformation.getPlayer1VariableCount())); + std::set successorAndAuxVariables(abstractionInformation.getSuccessorVariables()); auto player2Variables = abstractionInformation.getPlayer2VariableSet(game.numberOfPlayer2Variables); variablesToAbstract.insert(player2Variables.begin(), player2Variables.end()); auto auxVariables = abstractionInformation.getAuxVariableSet(0, abstractionInformation.getAuxVariableCount()); variablesToAbstract.insert(auxVariables.begin(), auxVariables.end()); + successorAndAuxVariables.insert(auxVariables.begin(), auxVariables.end()); - // Do a reachability analysis on the raw transition relation. - storm::dd::Bdd transitionRelation = game.bdd.existsAbstract(variablesToAbstract); + storm::utility::Stopwatch relevantStatesWatch(true); + storm::dd::Bdd nonTerminalStates = this->abstractionInformation.getDdManager().getBddOne(); + if (this->isRestrictToRelevantStatesSet()) { + // Compute which states are non-terminal. + for (auto const& expression : this->terminalStateExpressions) { + nonTerminalStates &= !this->getStates(expression); + } + if (this->hasTargetStateExpression()) { + nonTerminalStates &= !this->getStates(this->getTargetStateExpression()); + } + } + relevantStatesWatch.stop(); + + storm::dd::Bdd extendedTransitionRelation = nonTerminalStates && game.bdd; storm::dd::Bdd initialStates = initialStateAbstractor.getAbstractStates(); + if (restrictToValidBlocks) { + STORM_LOG_DEBUG("Restricting to valid blocks."); + storm::dd::Bdd validBlocks = validBlockAbstractor.getValidBlocks(); + + // Compute the choices with only valid successors so we can restrict the game to these. + auto choicesWithOnlyValidSuccessors = !game.bdd.andExists(!validBlocks.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs()), successorAndAuxVariables) && game.bdd.existsAbstract(successorAndAuxVariables); + + // Restrict the proper parts. + extendedTransitionRelation &= validBlocks && choicesWithOnlyValidSuccessors; + initialStates &= validBlocks; + } + + // Do a reachability analysis on the raw transition relation. + storm::dd::Bdd transitionRelation = extendedTransitionRelation.existsAbstract(variablesToAbstract); initialStates.addMetaVariables(abstractionInformation.getSourcePredicateVariables()); storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + + relevantStatesWatch.start(); + if (this->isRestrictToRelevantStatesSet() && this->hasTargetStateExpression()) { + // Get the target state BDD. + storm::dd::Bdd targetStates = reachableStates && this->getStates(this->getTargetStateExpression()); + + // In the presence of target states, we keep only states that can reach the target states. + reachableStates = storm::utility::dd::computeBackwardsReachableStates(targetStates, reachableStates, transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + + // Include all successors of reachable states, because the backward search otherwise potentially + // cuts probability 0 choices of these states. + reachableStates |= (reachableStates && !targetStates).relationalProduct(transitionRelation, abstractionInformation.getSourceVariables(), abstractionInformation.getSuccessorVariables()); + + // Restrict transition relation to relevant fragment for computation of deadlock states. + transitionRelation &= reachableStates && reachableStates.swapVariables(abstractionInformation.getExtendedSourceSuccessorVariablePairs()); + + relevantStatesWatch.stop(); + STORM_LOG_TRACE("Restricting to relevant states took " << relevantStatesWatch.getTimeInMilliseconds() << "ms."); + } // Find the deadlock states in the model. Note that this does not find the 'deadlocks' in bottom states, // as the bottom states are not contained in the reachable states. @@ -170,7 +234,9 @@ namespace storm { bool hasBottomStates = !bottomStateResult.states.isZero(); // Construct the transition matrix by cutting away the transitions of unreachable states. - storm::dd::Add transitionMatrix = (game.bdd && reachableStates).template toAdd(); + // Note that we also restrict the successor states of transitions, because there might be successors + // that are not in the set of relevant states we restrict to. + storm::dd::Add transitionMatrix = (extendedTransitionRelation && reachableStates && reachableStates.swapVariables(abstractionInformation.getSourceSuccessorVariablePairs())).template toAdd(); transitionMatrix *= commandUpdateProbabilitiesAdd; transitionMatrix += deadlockTransitions; @@ -185,9 +251,7 @@ namespace storm { reachableStates |= bottomStateResult.states; } - std::set usedPlayer2Variables(abstractionInformation.getPlayer2Variables().begin(), abstractionInformation.getPlayer2Variables().begin() + game.numberOfPlayer2Variables); - - std::set allNondeterminismVariables = usedPlayer2Variables; + std::set allNondeterminismVariables = player2Variables; allNondeterminismVariables.insert(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()); std::set allSourceVariables(abstractionInformation.getSourceVariables()); @@ -195,7 +259,7 @@ namespace storm { std::set allSuccessorVariables(abstractionInformation.getSuccessorVariables()); allSuccessorVariables.insert(abstractionInformation.getBottomStateVariable(false)); - return std::make_unique>(abstractionInformation.getDdManagerAsSharedPointer(), reachableStates, initialStates, abstractionInformation.getDdManager().getBddZero(), transitionMatrix, bottomStateResult.states, allSourceVariables, allSuccessorVariables, abstractionInformation.getExtendedSourceSuccessorVariablePairs(), std::set(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()), usedPlayer2Variables, allNondeterminismVariables, auxVariables, abstractionInformation.getPredicateToBddMap()); + return std::make_unique>(abstractionInformation.getDdManagerAsSharedPointer(), reachableStates, initialStates, abstractionInformation.getDdManager().getBddZero(), transitionMatrix, bottomStateResult.states, allSourceVariables, allSuccessorVariables, abstractionInformation.getExtendedSourceSuccessorVariablePairs(), std::set(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()), player2Variables, allNondeterminismVariables, auxVariables, abstractionInformation.getPredicateToBddMap()); } template @@ -203,11 +267,28 @@ namespace storm { this->exportToDot(*currentGame, filename, highlightStates, filter); } + template + uint64_t PrismMenuGameAbstractor::getNumberOfPredicates() const { + return abstractionInformation.getNumberOfPredicates(); + } + + template + void PrismMenuGameAbstractor::addTerminalStates(storm::expressions::Expression const& expression) { + terminalStateExpressions.emplace_back(expression); + } + + template + void PrismMenuGameAbstractor::notifyGuardsArePredicates() { + for (auto& module : modules) { + module.notifyGuardsArePredicates(); + } + } + // Explicitly instantiate the class. template class PrismMenuGameAbstractor; template class PrismMenuGameAbstractor; #ifdef STORM_HAVE_CARL - template class PrismMenuGameAbstractor; + template class PrismMenuGameAbstractor; #endif } } diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 49dc8e9dc..9e829726e 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -46,7 +46,7 @@ namespace storm { * @param program The concrete program for which to build the abstraction. * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. */ - PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory); + PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory, MenuGameAbstractorOptions const& options = MenuGameAbstractorOptions()); PrismMenuGameAbstractor(PrismMenuGameAbstractor const&) = default; PrismMenuGameAbstractor& operator=(PrismMenuGameAbstractor const&) = default; @@ -74,12 +74,22 @@ namespace storm { * @return The guard of the player 1 choice. */ storm::expressions::Expression const& getGuard(uint64_t player1Choice) const override; + + /*! + * Retrieves the number of updates of the specified player 1 choice. + */ + virtual uint64_t getNumberOfUpdates(uint64_t player1Choice) const override; /*! * Retrieves a mapping from variables to expressions that define their updates wrt. to the given player * 1 choice and auxiliary choice. */ std::map getVariableUpdates(uint64_t player1Choice, uint64_t auxiliaryChoice) const override; + + /*! + * Retrieves the variables assigned by the given player 1 choice. + */ + virtual std::set const& getAssignedVariables(uint64_t player1Choice) const override; /*! * Retrieves the range of player 1 choices. @@ -109,6 +119,12 @@ namespace storm { */ virtual void exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStates, storm::dd::Bdd const& filter) const override; + virtual uint64_t getNumberOfPredicates() const override; + + virtual void addTerminalStates(storm::expressions::Expression const& expression) override; + + virtual void notifyGuardsArePredicates() override; + protected: using MenuGameAbstractor::exportToDot; @@ -143,6 +159,9 @@ namespace storm { // A state-set abstractor used to determine the initial states of the abstraction. StateSetAbstractor initialStateAbstractor; + // A flag indicating whether the valid blocks need to be computed and the game restricted to these. + bool restrictToValidBlocks; + // An object that is used to compute the valid blocks. ValidBlockAbstractor validBlockAbstractor; @@ -154,6 +173,9 @@ namespace storm { // A flag storing whether a refinement was performed. bool refinementPerformed; + + // A list of terminal state expressions. + std::vector terminalStateExpressions; }; } } diff --git a/src/storm/adapters/AddExpressionAdapter.cpp b/src/storm/adapters/AddExpressionAdapter.cpp index f792584a8..c713cae38 100644 --- a/src/storm/adapters/AddExpressionAdapter.cpp +++ b/src/storm/adapters/AddExpressionAdapter.cpp @@ -111,6 +111,9 @@ namespace storm { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power: result = leftResult.pow(rightResult); break; + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Modulo: + result = leftResult.mod(rightResult); + break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate expression containing power operator."); } diff --git a/src/storm/adapters/GmmxxAdapter.cpp b/src/storm/adapters/GmmxxAdapter.cpp index 4210a00ee..ee5873eea 100644 --- a/src/storm/adapters/GmmxxAdapter.cpp +++ b/src/storm/adapters/GmmxxAdapter.cpp @@ -13,7 +13,7 @@ namespace storm { template std::unique_ptr> GmmxxAdapter::toGmmxxSparseMatrix(storm::storage::SparseMatrix const& matrix) { uint_fast64_t realNonZeros = matrix.getEntryCount(); - STORM_LOG_DEBUG("Converting " << matrix.getRowCount() << "x" << matrix.getColumnCount() << " matrix with " << realNonZeros << " non-zeros to gmm++ format."); + STORM_LOG_TRACE("Converting " << matrix.getRowCount() << "x" << matrix.getColumnCount() << " matrix with " << realNonZeros << " non-zeros to gmm++ format."); // Prepare the resulting matrix. std::unique_ptr> result(new gmm::csr_matrix(matrix.getRowCount(), matrix.getColumnCount())); @@ -37,7 +37,7 @@ namespace storm { std::swap(result->ir, columns); std::swap(result->pr, values); - STORM_LOG_DEBUG("Done converting matrix to gmm++ format."); + STORM_LOG_TRACE("Done converting matrix to gmm++ format."); return result; } diff --git a/src/storm/adapters/MathsatExpressionAdapter.h b/src/storm/adapters/MathsatExpressionAdapter.h index 357c482b3..e99c7d0c5 100644 --- a/src/storm/adapters/MathsatExpressionAdapter.h +++ b/src/storm/adapters/MathsatExpressionAdapter.h @@ -58,11 +58,13 @@ namespace storm { * @return An equivalent term for MathSAT. */ msat_term translateExpression(storm::expressions::Expression const& expression) { + additionalConstraints.clear(); msat_term result = boost::any_cast(expression.getBaseExpression().accept(*this, boost::none)); if (MSAT_ERROR_TERM(result)) { std::string errorMessage(msat_last_error_message(env)); STORM_LOG_THROW(!MSAT_ERROR_TERM(result), storm::exceptions::ExpressionEvaluationException, "Could not translate expression to MathSAT's format. (Message: " << errorMessage << ")"); } + return result; } @@ -82,6 +84,17 @@ namespace storm { return msat_make_constant(env, variableExpressionPair->second); } + bool hasAdditionalConstraints() const { + return !additionalConstraints.empty(); + } + + /*! + * Retrieves additional constraints that were created because of encodings using auxiliary variables. + */ + std::vector const& getAdditionalConstraints() const { + return additionalConstraints; + } + /*! * Retrieves the variable that is associated with the given MathSAT variable declaration. * @@ -116,6 +129,14 @@ namespace storm { msat_term leftResult = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); msat_term rightResult = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + msat_term result = leftResult; + int_fast64_t exponent; + int_fast64_t modulus; + storm::expressions::Variable freshAuxiliaryVariable; + msat_term modVariable; + msat_term lower; + msat_term upper; + typename storm::NumberTraits::IntegerType gmpModulus; switch (expression.getOperatorType()) { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Plus: return msat_make_plus(env, leftResult, rightResult); @@ -124,11 +145,38 @@ namespace storm { case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Times: return msat_make_times(env, leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Divide: - STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unsupported numerical binary operator: '/' (division) in expression."); + return msat_make_divide(env, leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Min: return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), leftResult, rightResult); case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Max: return msat_make_term_ite(env, msat_make_leq(env, leftResult, rightResult), rightResult, leftResult); + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Power: + exponent = expression.getSecondOperand()->evaluateAsInt(); + STORM_LOG_THROW(exponent >= 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative exponent."); + --exponent; + if (exponent > 0) { + for (; exponent > 0; --exponent) { + result = msat_make_times(env, result, leftResult); + } + } + return result; + case storm::expressions::BinaryNumericalFunctionExpression::OperatorType::Modulo: + modulus = expression.getSecondOperand()->evaluateAsInt(); + STORM_LOG_THROW(modulus > 0, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression with negative modulus."); + + freshAuxiliaryVariable = manager.declareFreshVariable(manager.getIntegerType(), true); + modVariable = msat_make_constant(env, createVariable(freshAuxiliaryVariable)); + + gmpModulus = typename storm::NumberTraits::IntegerType(static_cast(modulus)); + + // Create the constraint that fixes the value of the fresh variable. + additionalConstraints.push_back(msat_make_int_modular_congruence(env, gmpModulus.get_mpz_t(), modVariable, leftResult)); + + // Create the constraint that limits the value of the modulo operation to 0 <= val <= modulus-1. + lower = msat_make_number(env, "-1"); + upper = msat_make_number(env, std::to_string(modulus - 1).c_str()); + additionalConstraints.push_back(msat_make_and(env, msat_make_not(env, msat_make_leq(env, modVariable, lower)), msat_make_leq(env, modVariable, upper))); + return modVariable; default: STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Cannot evaluate expression: unknown numerical binary operator '" << static_cast(expression.getOperatorType()) << "' in expression " << expression << "."); } @@ -261,7 +309,9 @@ namespace storm { } else if (msat_is_rational_type(env, msat_term_get_type(term))) { return manager.rational(storm::utility::convertNumber(termString)); } - } + } else if (msat_term_is_term_ite(env, term)) { + return storm::expressions::ite(translateExpression(msat_term_get_arg(term, 0)), translateExpression(msat_term_get_arg(term, 1)), translateExpression(msat_term_get_arg(term, 2))); + } // If all other cases did not apply, we cannot represent the term in our expression framework. char* termAsCString = msat_term_repr(term); @@ -299,11 +349,15 @@ namespace storm { // The MathSAT environment used. msat_env& env; + + // A vector of constraints that need to be kept separate, because they were only implicitly part of an + // assertion that was added. + std::vector additionalConstraints; // A mapping of variable names to their declaration in the MathSAT environment. std::unordered_map variableToDeclarationMapping; - // A mapping from MathSAT variable declaration to our variables. + // A mapping from MathSAT variable declarations to our variables. std::unordered_map declarationToVariableMapping; }; #endif diff --git a/src/storm/adapters/Z3ExpressionAdapter.cpp b/src/storm/adapters/Z3ExpressionAdapter.cpp index c7e27756d..8a7f55bf5 100644 --- a/src/storm/adapters/Z3ExpressionAdapter.cpp +++ b/src/storm/adapters/Z3ExpressionAdapter.cpp @@ -1,5 +1,7 @@ #include "storm/adapters/Z3ExpressionAdapter.h" +#include + #include "storm/storage/expressions/Expressions.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/utility/macros.h" @@ -12,6 +14,15 @@ namespace storm { namespace adapters { #ifdef STORM_HAVE_Z3 + +#ifdef STORM_Z3_API_USES_STANDARD_INTEGERS + typedef int64_t Z3_SIGNED_INTEGER; + typedef uint64_t Z3_UNSIGNED_INTEGER; +#else + typedef long long Z3_SIGNED_INTEGER; + typedef unsigned long long Z3_UNSIGNED_INTEGER; +#endif + Z3ExpressionAdapter::Z3ExpressionAdapter(storm::expressions::ExpressionManager& manager, z3::context& context) : manager(manager), context(context), additionalAssertions(), variableToExpressionMapping() { // Intentionally left empty. } @@ -133,17 +144,17 @@ namespace storm { case Z3_OP_ANUM: // Arithmetic numeral. if (expr.is_int() && expr.is_const()) { - long long value; + Z3_SIGNED_INTEGER value; if (Z3_get_numeral_int64(expr.ctx(), expr, &value)) { return manager.integer(value); } else { STORM_LOG_THROW(false, storm::exceptions::ExpressionEvaluationException, "Failed to convert Z3 expression. Expression is constant integer and value does not fit into 64-bit integer."); } } else if (expr.is_real() && expr.is_const()) { - long long num; - long long den; + Z3_SIGNED_INTEGER num; + Z3_SIGNED_INTEGER den; if (Z3_get_numeral_rational_int64(expr.ctx(), expr, &num, &den)) { - return manager.rational(storm::utility::convertNumber((int_fast64_t) num) / storm::utility::convertNumber((int_fast64_t) den)); + return manager.rational(storm::utility::convertNumber(static_cast(num)) / storm::utility::convertNumber(static_cast(den))); } else { return manager.rational(storm::utility::convertNumber(std::string(Z3_get_numeral_string(expr.ctx(), expr)))); } @@ -304,7 +315,7 @@ namespace storm { return cacheIt->second; } - z3::expr result = context.int_val(static_cast(expression.getValue())); + z3::expr result = context.int_val(static_cast(expression.getValue())); expressionCache.emplace(&expression, result); return result; diff --git a/src/storm/api/bisimulation.h b/src/storm/api/bisimulation.h index 9ad43f9bd..dc7181e87 100644 --- a/src/storm/api/bisimulation.h +++ b/src/storm/api/bisimulation.h @@ -55,8 +55,8 @@ namespace storm { } } - template - typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { + template + typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::Mdp) || model->isOfType(storm::models::ModelType::MarkovAutomaton), storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is currently only available for DTMCs, CTMCs, MDPs and MAs."); STORM_LOG_THROW(bisimulationType == storm::storage::BisimulationType::Strong, storm::exceptions::NotSupportedException, "Currently only strong bisimulation is supported."); @@ -64,13 +64,13 @@ namespace storm { // Try to get rid of non state-rewards to easy bisimulation computation. model->reduceToStateBasedRewards(); - storm::dd::BisimulationDecomposition decomposition(*model, formulas, bisimulationType); + storm::dd::BisimulationDecomposition decomposition(*model, formulas, bisimulationType); decomposition.compute(mode); return decomposition.getQuotient(); } - template - typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { + template + typename std::enable_if::value, std::shared_ptr>>::type performBisimulationMinimization(std::shared_ptr> const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is not supported for this combination of DD library and value type."); return nullptr; } diff --git a/src/storm/api/builder.h b/src/storm/api/builder.h index e3e9c0672..ad39362df 100644 --- a/src/storm/api/builder.h +++ b/src/storm/api/builder.h @@ -1,10 +1,11 @@ #pragma once -#include "storm/parser/AutoParser.h" -#include "storm/parser/DirectEncodingParser.h" -#include "storm/parser/ImcaMarkovAutomatonParser.h" +#include "storm-parsers/parser/AutoParser.h" +#include "storm-parsers/parser/DirectEncodingParser.h" +#include "storm-parsers/parser/ImcaMarkovAutomatonParser.h" #include "storm/storage/SymbolicModelDescription.h" +#include "storm/storage/jani/ModelFeatures.h" #include "storm/storage/sparse/ModelComponents.h" #include "storm/models/sparse/Dtmc.h" @@ -17,6 +18,7 @@ #include "storm/builder/DdPrismModelBuilder.h" #include "storm/builder/DdJaniModelBuilder.h" +#include "storm/builder/BuilderType.h" #include "storm/generator/PrismNextStateGenerator.h" #include "storm/generator/JaniNextStateGenerator.h" @@ -30,6 +32,16 @@ namespace storm { namespace api { + inline storm::jani::ModelFeatures getSupportedJaniFeatures(storm::builder::BuilderType const& builderType) { + storm::jani::ModelFeatures features; + features.add(storm::jani::ModelFeature::DerivedOperators); + features.add(storm::jani::ModelFeature::StateExitRewards); + if (builderType == storm::builder::BuilderType::Explicit) { + features.add(storm::jani::ModelFeature::Arrays); + } + return features; + } + template std::shared_ptr> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector> const& formulas, bool buildFullModel = false) { if (model.isPrismProgram()) { diff --git a/src/storm/api/export.cpp b/src/storm/api/export.cpp index 193ec0668..80d45ed2c 100644 --- a/src/storm/api/export.cpp +++ b/src/storm/api/export.cpp @@ -1,20 +1,9 @@ #include "storm/api/export.h" +#include "storm/storage/jani/JaniLocationExpander.h" namespace storm { namespace api { - void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filename) { - auto janiSettings = storm::settings::getModule(); - - if (janiSettings.isExportAsStandardJaniSet()) { - storm::jani::Model normalisedModel = model; - normalisedModel.makeStandardJaniCompliant(); - storm::jani::JsonExporter::toFile(normalisedModel, properties, filename); - } else { - storm::jani::JsonExporter::toFile(model, properties, filename); - } - } - void exportJaniModelAsDot(storm::jani::Model const& model, std::string const& filename) { std::ofstream out; storm::utility::openFile(filename, out); diff --git a/src/storm/api/export.h b/src/storm/api/export.h index 3ba81525d..39a3ba1b3 100644 --- a/src/storm/api/export.h +++ b/src/storm/api/export.h @@ -1,20 +1,19 @@ #pragma once -#include "storm/storage/jani/JSONExporter.h" - - #include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/utility/DirectEncodingExporter.h" #include "storm/utility/file.h" #include "storm/utility/macros.h" namespace storm { + + namespace jani { + class Model; + } + namespace api { - void exportJaniModel(storm::jani::Model const& model, std::vector const& properties, std::string const& filename); - void exportJaniModelAsDot(storm::jani::Model const& model, std::string const& filename); template diff --git a/src/storm/api/model_descriptions.cpp b/src/storm/api/model_descriptions.cpp deleted file mode 100644 index 76ce24116..000000000 --- a/src/storm/api/model_descriptions.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "storm/api/model_descriptions.h" - -#include "storm/parser/PrismParser.h" -#include "storm/parser/JaniParser.h" - -#include "storm/storage/jani/Model.h" -#include "storm/storage/jani/Property.h" - - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/BuildSettings.h" - -namespace storm { - namespace api { - - storm::prism::Program parseProgram(std::string const& filename, bool prismCompatibility) { - storm::prism::Program program = storm::parser::PrismParser::parse(filename, prismCompatibility).simplify().simplify(); - program.checkValidity(); - return program; - } - - std::pair> parseJaniModel(std::string const& filename) { - std::pair> modelAndFormulae = storm::parser::JaniParser::parse(filename); - modelAndFormulae.first.checkValid(); - return modelAndFormulae; - } - - } -} diff --git a/src/storm/api/properties.cpp b/src/storm/api/properties.cpp index f6a2d00e3..b1e36af86 100644 --- a/src/storm/api/properties.cpp +++ b/src/storm/api/properties.cpp @@ -1,6 +1,5 @@ #include "storm/api/properties.h" -#include "storm/parser/FormulaParser.h" #include "storm/storage/SymbolicModelDescription.h" #include "storm/storage/prism/Program.h" @@ -13,58 +12,7 @@ namespace storm { namespace api { - - boost::optional> parsePropertyFilter(std::string const& propertyFilter) { - if (propertyFilter == "all") { - return boost::none; - } - std::vector propertyNames = storm::utility::cli::parseCommaSeparatedStrings(propertyFilter); - std::set propertyNameSet(propertyNames.begin(), propertyNames.end()); - return propertyNameSet; - } - std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter) { - // If the given property looks like a file (containing a dot and there exists a file with that name), - // we try to parse it as a file, otherwise we assume it's a property. - std::vector properties; - if (inputString.find(".") != std::string::npos && std::ifstream(inputString).good()) { - properties = formulaParser.parseFromFile(inputString); - } else { - properties = formulaParser.parseFromString(inputString); - } - - return filterProperties(properties, propertyFilter); - } - - std::vector parseProperties(std::string const& inputString, boost::optional> const& propertyFilter) { - auto exprManager = std::make_shared(); - storm::parser::FormulaParser formulaParser(exprManager); - return parseProperties(formulaParser, inputString, propertyFilter); - } - - std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter) { - storm::parser::FormulaParser formulaParser(model.getManager().getSharedPointer()); - auto formulas = parseProperties(formulaParser, inputString, propertyFilter); - return substituteConstantsInProperties(formulas, model.getConstantsSubstitution()); - } - - std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter) { - storm::parser::FormulaParser formulaParser(program); - auto formulas = parseProperties(formulaParser, inputString, propertyFilter); - return substituteConstantsInProperties(formulas, program.getConstantsSubstitution()); - } - - std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional> const& propertyFilter) { - std::vector result; - if (modelDescription.isPrismProgram()) { - result = storm::api::parsePropertiesForPrismProgram(inputString, modelDescription.asPrismProgram(), propertyFilter); - } else { - STORM_LOG_ASSERT(modelDescription.isJaniModel(), "Unknown model description type."); - result = storm::api::parsePropertiesForJaniModel(inputString, modelDescription.asJaniModel(), propertyFilter); - } - return result; - } - std::vector substituteConstantsInProperties(std::vector const& properties, std::map const& substitution) { std::vector preprocessedProperties; for (auto const& property : properties) { @@ -78,6 +26,11 @@ namespace storm { std::set const& propertyNameSet = propertyFilter.get(); std::vector result; std::set reducedPropertyNames; + + if (propertyNameSet.empty()) { + STORM_LOG_WARN("Filtering all properties."); + } + for (auto const& property : properties) { if (propertyNameSet.find(property.getName()) != propertyNameSet.end()) { result.push_back(property); @@ -104,5 +57,6 @@ namespace storm { } return formulas; } + } } diff --git a/src/storm/api/properties.h b/src/storm/api/properties.h index c52073105..c0c878f48 100644 --- a/src/storm/api/properties.h +++ b/src/storm/api/properties.h @@ -8,9 +8,7 @@ #include namespace storm { - namespace parser { - class FormulaParser; - } + namespace jani { class Property; class Model; @@ -30,14 +28,6 @@ namespace storm { } namespace api { - boost::optional> parsePropertyFilter(std::string const& propertyFilter); - - // Parsing properties. - std::vector parseProperties(storm::parser::FormulaParser& formulaParser, std::string const& inputString, boost::optional> const& propertyFilter = boost::none); - std::vector parseProperties(std::string const& inputString, boost::optional> const& propertyFilter = boost::none); - std::vector parsePropertiesForPrismProgram(std::string const& inputString, storm::prism::Program const& program, boost::optional> const& propertyFilter = boost::none); - std::vector parsePropertiesForJaniModel(std::string const& inputString, storm::jani::Model const& model, boost::optional> const& propertyFilter = boost::none); - std::vector parsePropertiesForSymbolicModelDescription(std::string const& inputString, storm::storage::SymbolicModelDescription const& modelDescription, boost::optional> const& propertyFilter = boost::none); // Process properties. std::vector substituteConstantsInProperties(std::vector const& properties, std::map const& substitution); diff --git a/src/storm/api/storm.h b/src/storm/api/storm.h index ffc4c75a6..0048bc315 100644 --- a/src/storm/api/storm.h +++ b/src/storm/api/storm.h @@ -1,10 +1,8 @@ #pragma once -#include "storm/api/model_descriptions.h" #include "storm/api/properties.h" #include "storm/api/builder.h" #include "storm/api/bisimulation.h" #include "storm/api/transformation.h" #include "storm/api/verification.h" -#include "storm/api/counterexamples.h" #include "storm/api/export.h" diff --git a/src/storm/api/transformation.h b/src/storm/api/transformation.h index 204e283db..d26f32ea1 100644 --- a/src/storm/api/transformation.h +++ b/src/storm/api/transformation.h @@ -62,14 +62,14 @@ namespace storm { * Transforms the given symbolic model to a sparse model. */ template - std::shared_ptr> transformSymbolicToSparseModel(std::shared_ptr> const& symbolicModel) { + std::shared_ptr> transformSymbolicToSparseModel(std::shared_ptr> const& symbolicModel, std::vector> const& formulas = std::vector>()) { switch (symbolicModel->getType()) { case storm::models::ModelType::Dtmc: - return storm::transformer::SymbolicDtmcToSparseDtmcTransformer().translate(*symbolicModel->template as>()); + return storm::transformer::SymbolicDtmcToSparseDtmcTransformer().translate(*symbolicModel->template as>(), formulas); case storm::models::ModelType::Mdp: - return storm::transformer::SymbolicMdpToSparseMdpTransformer::translate(*symbolicModel->template as>()); + return storm::transformer::SymbolicMdpToSparseMdpTransformer::translate(*symbolicModel->template as>(), formulas); case storm::models::ModelType::Ctmc: - return storm::transformer::SymbolicCtmcToSparseCtmcTransformer::translate(*symbolicModel->template as>()); + return storm::transformer::SymbolicCtmcToSparseCtmcTransformer::translate(*symbolicModel->template as>(), formulas); default: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Transformation of symbolic " << symbolicModel->getType() << " to sparse model is not supported."); } diff --git a/src/storm/api/verification.h b/src/storm/api/verification.h index 5d07f9f51..27392b81e 100644 --- a/src/storm/api/verification.h +++ b/src/storm/api/verification.h @@ -24,6 +24,7 @@ #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/EliminationSettings.h" +#include "storm/settings/modules/AbstractionSettings.h" #include "storm/utility/macros.h" #include "storm/exceptions/NotSupportedException.h" @@ -37,19 +38,31 @@ namespace storm { return storm::modelchecker::CheckTask(*formula, onlyInitialStatesRelevant); } + struct AbstractionRefinementOptions { + AbstractionRefinementOptions() = default; + AbstractionRefinementOptions(std::vector&& constraints, std::vector>&& injectedRefinementPredicates) : constraints(std::move(constraints)), injectedRefinementPredicates(std::move(injectedRefinementPredicates)) { + // Intentionally left empty. + } + + std::vector constraints; + std::vector> injectedRefinementPredicates; + }; + template - typename std::enable_if::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask const& task) { + typename std::enable_if::value || std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const& model, storm::modelchecker::CheckTask const& task, AbstractionRefinementOptions const& options = AbstractionRefinementOptions()) { STORM_LOG_THROW(model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC || model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP, storm::exceptions::NotSupportedException, "Can only treat DTMCs/MDPs using the abstraction refinement engine."); std::unique_ptr result; + storm::modelchecker::GameBasedMdpModelCheckerOptions modelCheckerOptions(options.constraints, options.injectedRefinementPredicates); + if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) { - storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model); + storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model, modelCheckerOptions); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } } else if (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MDP) { - storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model); + storm::modelchecker::GameBasedMdpModelChecker> modelchecker(model, modelCheckerOptions); if (modelchecker.canHandle(task)) { result = modelchecker.check(task); } @@ -60,7 +73,7 @@ namespace storm { } template - typename std::enable_if::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask const&) { + typename std::enable_if::value && !std::is_same::value, std::unique_ptr>::type verifyWithAbstractionRefinementEngine(storm::storage::SymbolicModelDescription const&, storm::modelchecker::CheckTask const&, AbstractionRefinementOptions const& = AbstractionRefinementOptions()) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Abstraction-refinement engine does not support data type."); } diff --git a/src/storm/builder/BuilderOptions.cpp b/src/storm/builder/BuilderOptions.cpp index 7a9978b98..8d2202dbf 100644 --- a/src/storm/builder/BuilderOptions.cpp +++ b/src/storm/builder/BuilderOptions.cpp @@ -1,6 +1,7 @@ #include "storm/builder/BuilderOptions.h" #include "storm/logic/Formulas.h" +#include "storm/logic/FragmentSpecification.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/BuildSettings.h" @@ -37,7 +38,7 @@ namespace storm { } - BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), explorationChecks(false), showProgress(false), inferObservationsFromActions(false), showProgressDelay(0) { + BuilderOptions::BuilderOptions(bool buildAllRewardModels, bool buildAllLabels) : buildAllRewardModels(buildAllRewardModels), buildAllLabels(buildAllLabels), buildChoiceLabels(false), buildStateValuations(false), buildChoiceOrigins(false), scaleAndLiftTransitionRewards(true), explorationChecks(false), addOverlappingGuardsLabel(false), addOutOfBoundsState(false), reservedBitsForUnboundedVariables(32), showProgress(false), inferObservationsFromActions(false), showProgressDelay(0) { // Intentionally left empty. } @@ -59,6 +60,7 @@ namespace storm { auto const& buildSettings = storm::settings::getModule(); auto const& generalSettings = storm::settings::getModule(); explorationChecks = buildSettings.isExplorationChecksSet(); + reservedBitsForUnboundedVariables = buildSettings.getBitsForUnboundedVariables(); showProgress = generalSettings.isVerboseSet(); showProgressDelay = generalSettings.getShowProgressDelay(); } @@ -86,6 +88,10 @@ namespace storm { for (auto const& formula : atomicExpressionFormulas) { addLabel(formula->getExpression()); } + + storm::logic::FragmentSpecification transitionRewardScalingFragment = storm::logic::csl().setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setLongRunAverageOperatorsAllowed(true).setMultiObjectiveFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setStepBoundedCumulativeRewardFormulasAllowed(true).setTimeBoundedCumulativeRewardFormulasAllowed(true); + scaleAndLiftTransitionRewards = scaleAndLiftTransitionRewards && formula.isInFragment(transitionRewardScalingFragment); + } void BuilderOptions::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { @@ -125,7 +131,7 @@ namespace storm { return labelNames; } - std::vector const& BuilderOptions::getExpressionLabels() const { + std::vector> const& BuilderOptions::getExpressionLabels() const { return expressionLabels; } @@ -164,7 +170,23 @@ namespace storm { bool BuilderOptions::isInferObservationsFromActionsSet() const { return inferObservationsFromActions; } + + bool BuilderOptions::isScaleAndLiftTransitionRewardsSet() const { + return scaleAndLiftTransitionRewards; + } + + bool BuilderOptions::isAddOutOfBoundsStateSet() const { + return addOutOfBoundsState; + } + uint64_t BuilderOptions::getReservedBitsForUnboundedVariables() const { + return reservedBitsForUnboundedVariables; + } + + bool BuilderOptions::isAddOverlappingGuardLabelSet() const { + return addOverlappingGuardsLabel; + } + BuilderOptions& BuilderOptions::setBuildAllRewardModels(bool newValue) { buildAllRewardModels = newValue; return *this; @@ -199,7 +221,9 @@ namespace storm { } BuilderOptions& BuilderOptions::addLabel(storm::expressions::Expression const& expression) { - expressionLabels.emplace_back(expression); + std::stringstream stream; + stream << expression; + expressionLabels.emplace_back(stream.str(), expression); return *this; } @@ -234,5 +258,39 @@ namespace storm { return *this; } + BuilderOptions& BuilderOptions::setScaleAndLiftTransitionRewards(bool newValue) { + scaleAndLiftTransitionRewards = newValue; + return *this; + } + + BuilderOptions& BuilderOptions::setAddOutOfBoundsState(bool newValue) { + addOutOfBoundsState = newValue; + return *this; + } + + BuilderOptions& BuilderOptions::setReservedBitsForUnboundedVariables(uint64_t newValue) { + reservedBitsForUnboundedVariables = newValue; + return *this; + } + + BuilderOptions& BuilderOptions::setAddOverlappingGuardsLabel(bool newValue) { + addOverlappingGuardsLabel = newValue; + return *this; + } + + BuilderOptions& BuilderOptions::substituteExpressions(std::function const& substitutionFunction) { + for (auto& e : expressionLabels) { + e.second = substitutionFunction(e.second); + } + + for (auto& t : terminalStates) { + if (t.first.isExpression()) { + t.first = LabelOrExpression(substitutionFunction(t.first.getExpression())); + } + } + return *this; + } + + } } diff --git a/src/storm/builder/BuilderOptions.h b/src/storm/builder/BuilderOptions.h index 703ff0e95..b718a7f82 100644 --- a/src/storm/builder/BuilderOptions.h +++ b/src/storm/builder/BuilderOptions.h @@ -97,7 +97,7 @@ namespace storm { * Which expression labels are built * @return */ - std::vector const& getExpressionLabels() const; + std::vector> const& getExpressionLabels() const; std::vector> const& getTerminalStates() const; bool hasTerminalStates() const; void clearTerminalStates(); @@ -109,6 +109,10 @@ namespace storm { bool isExplorationChecksSet() const; bool isInferObservationsFromActionsSet() const; bool isShowProgressSet() const; + bool isScaleAndLiftTransitionRewardsSet() const; + bool isAddOutOfBoundsStateSet() const; + uint64_t getReservedBitsForUnboundedVariables() const; + bool isAddOverlappingGuardLabelSet() const; uint64_t getShowProgressDelay() const; /** @@ -159,9 +163,40 @@ namespace storm { BuilderOptions& setExplorationChecks(bool newValue = true); + BuilderOptions& setInferObservationsFromActions(bool newValue = true); + /** + * Should extra checks be performed during exploration + * @param newValue The new value (default true) + * @return this + */ + BuilderOptions& setScaleAndLiftTransitionRewards(bool newValue = true); + + /** + * Should a state for out of bounds be constructed + * @param newValue The new value (default true) + * @return this + */ + BuilderOptions& setAddOutOfBoundsState(bool newValue = true); + + /** + * Should a state be labelled for overlapping guards + * @param newValue the new value (default true) + */ + BuilderOptions& setAddOverlappingGuardsLabel(bool newValue = true); + + /** + * Sets the number of bits that will be reserved for unbounded integer variables. + */ + BuilderOptions& setReservedBitsForUnboundedVariables(uint64_t value); + + /** + * Substitutes all expressions occurring in these options. + */ + BuilderOptions& substituteExpressions(std::function const& substitutionFunction); + private: /// A flag that indicates whether all reward models are to be built. In this case, the reward model names are /// to be ignored. @@ -177,14 +212,14 @@ namespace storm { std::set labelNames; /// The expression that are to be used for creating the state labeling. - std::vector expressionLabels; + std::vector> expressionLabels; /// If one of these labels/expressions evaluates to the given bool, the builder can abort the exploration. std::vector> terminalStates; - + /// A flag indicating whether or not to build choice labels. bool buildChoiceLabels; - + /// A flag indicating whether or not to build for each state the variable valuation from which it originates. bool buildStateValuations; @@ -192,17 +227,30 @@ namespace storm { // each choice originates. bool buildChoiceOrigins; + /// A flag that stores whether potentially occurring transition rewards should be scaled and lifted to the edge + bool scaleAndLiftTransitionRewards; + /// A flag that stores whether exploration checks are to be performed. bool explorationChecks; /// For POMDPs, should we allow inference of observation classes from different enabled actions. bool inferObservationsFromActions; + /// A flag for states with overlapping guards + bool addOverlappingGuardsLabel; + + /// A flag indicating that the an additional state for out of bounds should be created. + bool addOutOfBoundsState; + + /// Indicates the number of bits that are reserved for the storage of unbounded integer variables. + uint64_t reservedBitsForUnboundedVariables; + /// A flag that stores whether the progress of exploration is to be printed. bool showProgress; - + /// The delay for printing progress information. uint64_t showProgressDelay; + }; } diff --git a/src/storm/builder/BuilderType.h b/src/storm/builder/BuilderType.h new file mode 100644 index 000000000..8e5e86ad0 --- /dev/null +++ b/src/storm/builder/BuilderType.h @@ -0,0 +1,11 @@ +#pragma once + +namespace storm { + namespace builder { + enum class BuilderType { + Explicit, + Dd, + Jit + }; + } +} \ No newline at end of file diff --git a/src/storm/builder/DdJaniModelBuilder.cpp b/src/storm/builder/DdJaniModelBuilder.cpp index a6620492e..e2667cf93 100644 --- a/src/storm/builder/DdJaniModelBuilder.cpp +++ b/src/storm/builder/DdJaniModelBuilder.cpp @@ -653,6 +653,40 @@ namespace storm { ActionDd multiplyTransitions(storm::dd::Add const& factor) const { return ActionDd(guard, transitions * factor, transientEdgeAssignments, localNondeterminismVariables, variableToWritingFragment, illegalFragment); } + + ActionDd add(ActionDd const& other) const { + storm::dd::Bdd newGuard = this->guard || other.guard; + storm::dd::Add newTransitions = this->transitions + other.transitions; + + // Join the transient edge assignments. + std::map> newTransientEdgeAssignments(this->transientEdgeAssignments); + for (auto const& entry : other.transientEdgeAssignments) { + auto it = newTransientEdgeAssignments.find(entry.first); + if (it == newTransientEdgeAssignments.end()) { + newTransientEdgeAssignments[entry.first] = entry.second; + } else { + it->second += entry.second; + } + } + + std::pair newLocalNondeterminismVariables = std::make_pair(std::min(this->localNondeterminismVariables.first, other.localNondeterminismVariables.first), std::max(this->localNondeterminismVariables.second, other.localNondeterminismVariables.second)); + + // Join variable-to-writing-fragment maps. + std::map> newVariableToWritingFragment(this->variableToWritingFragment); + for (auto const& entry : other.variableToWritingFragment) { + auto it = newVariableToWritingFragment.find(entry.first); + if (it == newVariableToWritingFragment.end()) { + newVariableToWritingFragment[entry.first] = entry.second; + } else { + it->second |= entry.second; + } + } + + // Join illegal fragments. + storm::dd::Bdd newIllegalFragment = this->illegalFragment || other.illegalFragment; + + return ActionDd(newGuard, newTransitions, newTransientEdgeAssignments, newLocalNondeterminismVariables, newVariableToWritingFragment, newIllegalFragment); + } bool isInputEnabled() const { return inputEnabled; @@ -975,7 +1009,16 @@ namespace storm { // Finally, combine (potentially) multiple action DDs. for (auto const& actionDds : actions) { - ActionDd combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front(); + ActionDd combinedAction; + if (actionDds.first == silentMarkovianActionIdentification) { + // For the Markovian transitions, we can simply add the actions. + combinedAction = actionDds.second.front(); + for (uint64_t i = 1; i < actionDds.second.size(); ++i) { + combinedAction = combinedAction.add(actionDds.second[i]); + } + } else { + combinedAction = actionDds.second.size() > 1 ? combineUnsynchronizedActions(actionDds.second) : actionDds.second.front(); + } result.actions[actionDds.first] = combinedAction; result.extendLocalNondeterminismVariables(combinedAction.getLocalNondeterminismVariables()); } @@ -1275,7 +1318,7 @@ namespace storm { // Finally treat the transient assignments. std::map> transientEdgeAssignments; if (!this->transientVariables.empty()) { - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &guard, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) { + performTransientAssignments(edge.getAssignments().getTransientAssignments(), [this, &transientEdgeAssignments, &sourceLocationAndGuard] (storm::jani::Assignment const& assignment) { transientEdgeAssignments[assignment.getExpressionVariable()] = sourceLocationAndGuard * this->variables.rowExpressionAdapter->translateExpression(assignment.getAssignedExpression()); } ); } @@ -1333,7 +1376,7 @@ namespace storm { } else if (modelType == storm::jani::ModelType::MDP || modelType == storm::jani::ModelType::LTS) { return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset); } else if (modelType == storm::jani::ModelType::MA) { - if (instantiation.isMarkovian()){ + if (instantiation.isMarkovian()) { return combineEdgesToActionDeterministic(edgeDds); } else { return combineEdgesToActionNondeterministic(edgeDds, localNondeterminismVariableOffset); @@ -1667,7 +1710,7 @@ namespace storm { result += extendedTransitions; } - + return ComposerResult(result, automaton.transientLocationAssignments, transientEdgeAssignments, illegalFragment, numberOfUsedNondeterminismVariables); } else if (modelType == storm::jani::ModelType::DTMC || modelType == storm::jani::ModelType::CTMC) { // Simply add all actions, but make sure to include the missing global variable identities. @@ -1830,7 +1873,7 @@ namespace storm { // For DTMCs, we can simply add the identity of the global module for all deadlock states. transitionMatrix += deadlockStatesAdd * globalIdentity; } else if (modelType == storm::jani::ModelType::MDP || modelType == storm::jani::ModelType::LTS || modelType == storm::jani::ModelType::MA) { - // For MDPs, however, we need to select an action associated with the self-loop, if we do not + // For nondeterministic models, however, we need to select an action associated with the self-loop, if we do not // want to attach a lot of self-loops to the deadlock states. storm::dd::Add action = encodeAction(boost::none, modelType == storm::jani::ModelType::MA ? boost::make_optional(true) : boost::none, variables); @@ -1849,38 +1892,23 @@ namespace storm { template std::vector selectRewardVariables(storm::jani::Model const& model, typename DdJaniModelBuilder::Options const& options) { - std::vector result; + std::vector rewardVariables; if (options.isBuildAllRewardModelsSet()) { - for (auto const& variable : model.getGlobalVariables()) { - if (variable.isTransient() && (variable.isRealVariable() || variable.isUnboundedIntegerVariable())) { - result.push_back(variable.getExpressionVariable()); - } + for (auto const& rewExpr : model.getAllRewardModelExpressions()) { + STORM_LOG_ERROR_COND(rewExpr.second.isVariable(), "The jit builder can not build the non-trivial reward expression '" << rewExpr.second << "'."); + rewardVariables.push_back(rewExpr.second.getBaseExpression().asVariableExpression().getVariable()); } } else { - auto const& globalVariables = model.getGlobalVariables(); - for (auto const& rewardModelName : options.getRewardModelNames()) { - if (globalVariables.hasVariable(rewardModelName)) { - result.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); - } else { - STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); - STORM_LOG_THROW(globalVariables.getNumberOfRealTransientVariables() + globalVariables.getNumberOfUnboundedIntegerTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); - } - } - - // If no reward model was yet added, but there was one that was given in the options, we try to build the - // standard reward model. - if (result.empty() && !options.getRewardModelNames().empty()) { - for (auto const& variable : globalVariables.getTransientVariables()) { - if (variable.isRealVariable() || variable.isUnboundedIntegerVariable()) { - result.push_back(variable.getExpressionVariable()); - break; - } - } + auto const& rewExpr = model.getRewardModelExpression(rewardModelName); + STORM_LOG_ERROR_COND(rewExpr.isVariable(), "The jit builder can not build the non-trivial reward expression '" << rewExpr << "'."); + rewardVariables.push_back(rewExpr.getBaseExpression().asVariableExpression().getVariable()); } } + // Sort the reward variables to match the order in the ordered assignments + std::sort(rewardVariables.begin(), rewardVariables.end()); - return result; + return rewardVariables; } template @@ -1943,8 +1971,13 @@ namespace storm { } STORM_LOG_THROW(!model.usesAssignmentLevels(), storm::exceptions::WrongFormatException, "The symbolic JANI model builder currently does not support assignment levels."); + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + features.remove(storm::jani::ModelFeature::StateExitRewards); + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidSettingsException, "The dd jani model builder does not support the following model feature(s): " << features.toString() << "."); storm::jani::Model preparedModel = model; + preparedModel.substituteFunctions(); // 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()) { @@ -1967,10 +2000,10 @@ namespace storm { // Create a builder to compose and build the model. CombinedEdgesSystemComposer composer(preparedModel, actionInformation, variables, rewardVariables); ComposerResult system = composer.compose(); - + // Postprocess the variables in place. postprocessVariables(preparedModel.getModelType(), system, variables); - + // Postprocess the system in place and get the states that were terminal (i.e. whose transitions were cut off). storm::dd::Bdd terminalStates = postprocessSystem(preparedModel, system, variables, options); diff --git a/src/storm/builder/DdPrismModelBuilder.cp b/src/storm/builder/DdPrismModelBuilder.cp deleted file mode 100644 index 26308f45b..000000000 --- a/src/storm/builder/DdPrismModelBuilder.cp +++ /dev/null @@ -1,1429 +0,0 @@ -#include "storm/builder/DdPrismModelBuilder.h" - -#include - -#include "storm/models/symbolic/Dtmc.h" -#include "storm/models/symbolic/Ctmc.h" -#include "storm/models/symbolic/Mdp.h" -#include "storm/models/symbolic/StandardRewardModel.h" - -#include "storm/settings/SettingsManager.h" - -#include "storm/exceptions/InvalidStateException.h" -#include "storm/exceptions/NotSupportedException.h" -#include "storm/exceptions/InvalidArgumentException.h" - -#include "storm/utility/prism.h" -#include "storm/utility/math.h" -#include "storm/utility/dd.h" - -#include "storm/storage/dd/DdManager.h" -#include "storm/storage/prism/Program.h" -#include "storm/storage/prism/Compositions.h" -#include "storm/storage/dd/Add.h" -#include "storm/storage/dd/cudd/CuddAddIterator.h" -#include "storm/storage/dd/Bdd.h" - -#include "storm/settings/modules/CoreSettings.h" - -namespace storm { - namespace builder { - - template - class DdPrismModelBuilder::GenerationInformation { - public: - GenerationInformation(storm::prism::Program const& program) : program(program), manager(std::make_shared>()), rowMetaVariables(), variableToRowMetaVariableMap(std::make_shared>()), rowExpressionAdapter(std::make_shared>(manager, variableToRowMetaVariableMap)), columnMetaVariables(), variableToColumnMetaVariableMap((std::make_shared>())), columnExpressionAdapter(std::make_shared>(manager, variableToColumnMetaVariableMap)), rowColumnMetaVariablePairs(), nondeterminismMetaVariables(), variableToIdentityMap(), allGlobalVariables(), moduleToIdentityMap() { - // Initializes variables and identity DDs. - createMetaVariablesAndIdentities(); - } - - // The program that is currently translated. - storm::prism::Program const& program; - - // The manager used to build the decision diagrams. - std::shared_ptr> manager; - - // The meta variables for the row encoding. - std::set rowMetaVariables; - std::shared_ptr> variableToRowMetaVariableMap; - std::shared_ptr> rowExpressionAdapter; - - // The meta variables for the column encoding. - std::set columnMetaVariables; - std::shared_ptr> variableToColumnMetaVariableMap; - std::shared_ptr> columnExpressionAdapter; - - // All pairs of row/column meta variables. - std::vector> rowColumnMetaVariablePairs; - - // The meta variables used to encode the nondeterminism. - std::vector nondeterminismMetaVariables; - - // The meta variables used to encode the synchronization. - std::vector synchronizationMetaVariables; - - // A set of all variables used for encoding the nondeterminism (i.e. nondetermism + synchronization - // variables). This is handy to abstract from this variable set. - std::set allNondeterminismVariables; - - // As set of all variables used for encoding the synchronization. - std::set allSynchronizationMetaVariables; - - // DDs representing the identity for each variable. - std::map> variableToIdentityMap; - - // A set of all meta variables that correspond to global variables. - std::set allGlobalVariables; - - // DDs representing the identity for each module. - std::map> moduleToIdentityMap; - - // DDs representing the valid ranges of the variables of each module. - std::map> moduleToRangeMap; - - private: - /*! - * Creates the required meta variables and variable/module identities. - */ - void createMetaVariablesAndIdentities() { - // Add synchronization variables. - for (auto const& actionIndex : program.getSynchronizingActionIndices()) { - std::pair variablePair = manager->addMetaVariable(program.getActionName(actionIndex)); - synchronizationMetaVariables.push_back(variablePair.first); - allSynchronizationMetaVariables.insert(variablePair.first); - allNondeterminismVariables.insert(variablePair.first); - } - - // Add nondeterminism variables (number of modules + number of commands). - uint_fast64_t numberOfNondeterminismVariables = program.getModules().size(); - for (auto const& module : program.getModules()) { - numberOfNondeterminismVariables += module.getNumberOfCommands(); - } - for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) { - std::pair variablePair = manager->addMetaVariable("nondet" + std::to_string(i)); - nondeterminismMetaVariables.push_back(variablePair.first); - allNondeterminismVariables.insert(variablePair.first); - } - - // Create meta variables for global program variables. - for (storm::prism::IntegerVariable const& integerVariable : program.getGlobalIntegerVariables()) { - int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt(); - int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt(); - std::pair variablePair = manager->addMetaVariable(integerVariable.getName(), low, high); - - STORM_LOG_TRACE("Created meta variables for global integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Add variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)).template toAdd() * manager->getRange(variablePair.first).template toAdd() * manager->getRange(variablePair.second).template toAdd(); - variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity); - rowColumnMetaVariablePairs.push_back(variablePair); - - allGlobalVariables.insert(integerVariable.getExpressionVariable()); - } - for (storm::prism::BooleanVariable const& booleanVariable : program.getGlobalBooleanVariables()) { - std::pair variablePair = manager->addMetaVariable(booleanVariable.getName()); - - STORM_LOG_TRACE("Created meta variables for global boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Add variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)).template toAdd(); - variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity); - - rowColumnMetaVariablePairs.push_back(variablePair); - allGlobalVariables.insert(booleanVariable.getExpressionVariable()); - } - - // Create meta variables for each of the modules' variables. - for (storm::prism::Module const& module : program.getModules()) { - storm::dd::Bdd moduleIdentity = manager->getBddOne(); - storm::dd::Bdd moduleRange = manager->getBddOne(); - - for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) { - int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt(); - int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt(); - std::pair variablePair = manager->addMetaVariable(integerVariable.getName(), low, high); - STORM_LOG_TRACE("Created meta variables for integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Bdd variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second); - variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity.template toAdd()); - moduleIdentity &= variableIdentity; - moduleRange &= manager->getRange(variablePair.first); - - rowColumnMetaVariablePairs.push_back(variablePair); - } - for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) { - std::pair variablePair = manager->addMetaVariable(booleanVariable.getName()); - STORM_LOG_TRACE("Created meta variables for boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]"); - - rowMetaVariables.insert(variablePair.first); - variableToRowMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.first); - - columnMetaVariables.insert(variablePair.second); - variableToColumnMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.second); - - storm::dd::Bdd variableIdentity = manager->template getIdentity(variablePair.first).equals(manager->template getIdentity(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second); - variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity.template toAdd()); - moduleIdentity &= variableIdentity; - moduleRange &= manager->getRange(variablePair.first); - - rowColumnMetaVariablePairs.push_back(variablePair); - } - moduleToIdentityMap[module.getName()] = moduleIdentity.template toAdd(); - moduleToRangeMap[module.getName()] = moduleRange.template toAdd(); - } - } - }; - - template - class ModuleComposer : public storm::prism::CompositionVisitor { - public: - ModuleComposer(typename DdPrismModelBuilder::GenerationInformation& generationInfo) : generationInfo(generationInfo) { - // Intentionally left empty. - } - - typename DdPrismModelBuilder::ModuleDecisionDiagram compose(storm::prism::Composition const& composition) { - return boost::any_cast::ModuleDecisionDiagram>(composition.accept(*this, newSynchronizingActionToOffsetMap())); - } - - std::map newSynchronizingActionToOffsetMap() const { - std::map result; - for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) { - result[actionIndex] = 0; - } - return result; - } - - std::map updateSynchronizingActionToOffsetMap(typename DdPrismModelBuilder::ModuleDecisionDiagram const& sub, std::map const& oldMapping) const { - std::map result = oldMapping; - for (auto const& action : sub.synchronizingActionToDecisionDiagramMap) { - result[action.first] = action.second.numberOfUsedNondeterminismVariables; - } - return result; - } - - virtual boost::any visit(storm::prism::ModuleComposition const& composition, boost::any const& data) override { - STORM_LOG_TRACE("Translating module '" << composition.getModuleName() << "'."); - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - - typename DdPrismModelBuilder::ModuleDecisionDiagram result = DdPrismModelBuilder::createModuleDecisionDiagram(generationInfo, generationInfo.program.getModule(composition.getModuleName()), synchronizingActionToOffsetMap); - - return result; - } - - virtual boost::any visit(storm::prism::RenamingComposition const& composition, boost::any const& data) override { - // Create the mapping from action indices to action indices. - std::map renaming; - for (auto const& namePair : composition.getActionRenaming()) { - STORM_LOG_THROW(generationInfo.program.hasAction(namePair.first), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << namePair.first << "'."); - STORM_LOG_THROW(generationInfo.program.hasAction(namePair.second), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << namePair.second << "'."); - renaming.emplace(generationInfo.program.getActionIndex(namePair.first), generationInfo.program.getActionIndex(namePair.second)); - } - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& indexPair : renaming) { - auto it = synchronizingActionToOffsetMap.find(indexPair.second); - STORM_LOG_THROW(it != synchronizingActionToOffsetMap.end(), storm::exceptions::InvalidArgumentException, "Invalid action index " << indexPair.second << "."); - newSynchronizingActionToOffsetMap[indexPair.first] = it->second; - } - - // Then, we translate the subcomposition. - typename DdPrismModelBuilder::ModuleDecisionDiagram sub = boost::any_cast::ModuleDecisionDiagram>(composition.getSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - // Perform the renaming and return result. - return rename(sub, renaming); - } - - virtual boost::any visit(storm::prism::HidingComposition const& composition, boost::any const& data) override { - // Create the mapping from action indices to action indices. - std::set actionIndicesToHide; - for (auto const& action : composition.getActionsToHide()) { - STORM_LOG_THROW(generationInfo.program.hasAction(action), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << action << "'."); - actionIndicesToHide.insert(generationInfo.program.getActionIndex(action)); - } - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& index : actionIndicesToHide) { - newSynchronizingActionToOffsetMap[index] = 0; - } - - // Then, we translate the subcomposition. - typename DdPrismModelBuilder::ModuleDecisionDiagram sub = boost::any_cast::ModuleDecisionDiagram>(composition.getSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - // Perform the hiding and return result. - hide(sub, actionIndicesToHide); - return sub; - } - - virtual boost::any visit(storm::prism::SynchronizingParallelComposition const& composition, boost::any const& data) override { - // First, we translate the subcompositions. - typename DdPrismModelBuilder::ModuleDecisionDiagram left = boost::any_cast::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data)); - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& action : left.synchronizingActionToDecisionDiagramMap) { - newSynchronizingActionToOffsetMap[action.first] = action.second.numberOfUsedNondeterminismVariables; - } - - typename DdPrismModelBuilder::ModuleDecisionDiagram right = boost::any_cast::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - // Then, determine the action indices on which we need to synchronize. - std::set leftSynchronizationActionIndices = left.getSynchronizingActionIndices(); - std::set rightSynchronizationActionIndices = right.getSynchronizingActionIndices(); - std::set synchronizationActionIndices; - std::set_intersection(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(), rightSynchronizationActionIndices.begin(), rightSynchronizationActionIndices.end(), std::inserter(synchronizationActionIndices, synchronizationActionIndices.begin())); - - // Finally, we compose the subcompositions to create the result. - composeInParallel(left, right, synchronizationActionIndices); - return left; - } - - virtual boost::any visit(storm::prism::InterleavingParallelComposition const& composition, boost::any const& data) override { - // First, we translate the subcompositions. - typename DdPrismModelBuilder::ModuleDecisionDiagram left = boost::any_cast::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data)); - - typename DdPrismModelBuilder::ModuleDecisionDiagram right = boost::any_cast::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, data)); - - // Finally, we compose the subcompositions to create the result. - composeInParallel(left, right, std::set()); - return left; - } - - virtual boost::any visit(storm::prism::RestrictedParallelComposition const& composition, boost::any const& data) override { - // Construct the synchronizing action indices from the synchronizing action names. - std::set synchronizingActionIndices; - for (auto const& action : composition.getSynchronizingActions()) { - synchronizingActionIndices.insert(generationInfo.program.getActionIndex(action)); - } - - // Then, we translate the subcompositions. - typename DdPrismModelBuilder::ModuleDecisionDiagram left = boost::any_cast::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data)); - - // Prepare the new offset mapping. - std::map const& synchronizingActionToOffsetMap = boost::any_cast const&>(data); - std::map newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap; - for (auto const& actionIndex : synchronizingActionIndices) { - auto it = left.synchronizingActionToDecisionDiagramMap.find(actionIndex); - if (it != left.synchronizingActionToDecisionDiagramMap.end()) { - newSynchronizingActionToOffsetMap[actionIndex] = it->second.numberOfUsedNondeterminismVariables; - } - } - - typename DdPrismModelBuilder::ModuleDecisionDiagram right = boost::any_cast::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, newSynchronizingActionToOffsetMap)); - - std::set leftSynchronizationActionIndices = left.getSynchronizingActionIndices(); - bool isContainedInLeft = std::includes(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(), synchronizingActionIndices.begin(), synchronizingActionIndices.end()); - STORM_LOG_WARN_COND(isContainedInLeft, "Left subcomposition of composition '" << composition << "' does not include all actions over which to synchronize."); - - std::set rightSynchronizationActionIndices = right.getSynchronizingActionIndices(); - bool isContainedInRight = std::includes(rightSynchronizationActionIndices.begin(), rightSynchronizationActionIndices.end(), synchronizingActionIndices.begin(), synchronizingActionIndices.end()); - STORM_LOG_WARN_COND(isContainedInRight, "Right subcomposition of composition '" << composition << "' does not include all actions over which to synchronize."); - - // Finally, we compose the subcompositions to create the result. - composeInParallel(left, right, synchronizingActionIndices); - return left; - } - - private: - /*! - * Hides the actions of the given module according to the given set. As a result, the module is modified in - * place. - */ - void hide(typename DdPrismModelBuilder::ModuleDecisionDiagram& sub, std::set const& actionIndicesToHide) const { - STORM_LOG_TRACE("Hiding actions."); - - for (auto const& actionIndex : actionIndicesToHide) { - auto it = sub.synchronizingActionToDecisionDiagramMap.find(actionIndex); - if (it != sub.synchronizingActionToDecisionDiagramMap.end()) { - sub.independentAction = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, sub.independentAction, it->second); - sub.numberOfUsedNondeterminismVariables = std::max(sub.numberOfUsedNondeterminismVariables, sub.independentAction.numberOfUsedNondeterminismVariables); - sub.synchronizingActionToDecisionDiagramMap.erase(it); - } - } - } - - /*! - * Renames the actions of the given module according to the given renaming. - */ - typename DdPrismModelBuilder::ModuleDecisionDiagram rename(typename DdPrismModelBuilder::ModuleDecisionDiagram& sub, std::map const& renaming) const { - STORM_LOG_TRACE("Renaming actions."); - std::map::ActionDecisionDiagram> actionIndexToDdMap; - - // Go through all action DDs with a synchronizing label and rename them if they appear in the renaming. - for (auto& action : sub.synchronizingActionToDecisionDiagramMap) { - auto renamingIt = renaming.find(action.first); - if (renamingIt != renaming.end()) { - // If the action is to be renamed and an action with the target index already exists, we need - // to combine the action DDs. - auto itNewActions = actionIndexToDdMap.find(renamingIt->second); - if (itNewActions != actionIndexToDdMap.end()) { - actionIndexToDdMap[renamingIt->second] = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second); - - } else { - // In this case, we can simply copy the action over. - actionIndexToDdMap[renamingIt->second] = action.second; - } - } else { - // If the action is not to be renamed, we need to copy it over. However, if some other action - // was renamed to the very same action name before, we need to combine the transitions. - auto itNewActions = actionIndexToDdMap.find(action.first); - if (itNewActions != actionIndexToDdMap.end()) { - actionIndexToDdMap[action.first] = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second); - } else { - // In this case, we can simply copy the action over. - actionIndexToDdMap[action.first] = action.second; - } - } - } - - return typename DdPrismModelBuilder::ModuleDecisionDiagram(sub.independentAction, actionIndexToDdMap, sub.identity, sub.numberOfUsedNondeterminismVariables); - } - - /*! - * Composes the given modules while synchronizing over the provided action indices. As a result, the first - * module is modified in place and will contain the composition after a call to this method. - */ - void composeInParallel(typename DdPrismModelBuilder::ModuleDecisionDiagram& left, typename DdPrismModelBuilder::ModuleDecisionDiagram& right, std::set const& synchronizationActionIndices) const { - STORM_LOG_TRACE("Composing two modules."); - - // Combine the tau action. - uint_fast64_t numberOfUsedNondeterminismVariables = right.independentAction.numberOfUsedNondeterminismVariables; - left.independentAction = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, left.independentAction, right.independentAction, left.identity, right.identity); - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.independentAction.numberOfUsedNondeterminismVariables); - - // Create an empty action for the case where one of the modules does not have a certain action. - typename DdPrismModelBuilder::ActionDecisionDiagram emptyAction(*generationInfo.manager); - - // Treat all non-tau actions of the left module. - for (auto& action : left.synchronizingActionToDecisionDiagramMap) { - // If we need to synchronize over this action index, we try to do so now. - if (synchronizationActionIndices.find(action.first) != synchronizationActionIndices.end()) { - // If we are to synchronize over an action that does not exist in the second module, the result - // is that the synchronization is the empty action. - if (!right.hasSynchronizingAction(action.first)) { - action.second = emptyAction; - } else { - // Otherwise, the actions of the modules are synchronized. - action.second = DdPrismModelBuilder::combineSynchronizingActions(action.second, right.synchronizingActionToDecisionDiagramMap[action.first]); - } - } else { - // If we don't synchronize over this action, we need to construct the interleaving. - - // If both modules contain the action, we need to mutually multiply the other identity. - if (right.hasSynchronizingAction(action.first)) { - action.second = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, right.synchronizingActionToDecisionDiagramMap[action.first], left.identity, right.identity); - } else { - // If only the first module has this action, we need to use a dummy action decision diagram - // for the second module. - action.second = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, action.second, emptyAction, left.identity, right.identity); - } - } - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, action.second.numberOfUsedNondeterminismVariables); - } - - // Treat all non-tau actions of the right module. - for (auto const& actionIndex : right.getSynchronizingActionIndices()) { - // Here, we only need to treat actions that the first module does not have, because we have handled - // this case earlier. - if (!left.hasSynchronizingAction(actionIndex)) { - if (synchronizationActionIndices.find(actionIndex) != synchronizationActionIndices.end()) { - // If we are to synchronize over this action that does not exist in the first module, the - // result is that the synchronization is the empty action. - left.synchronizingActionToDecisionDiagramMap[actionIndex] = emptyAction; - } else { - // If only the second module has this action, we need to use a dummy action decision diagram - // for the first module. - left.synchronizingActionToDecisionDiagramMap[actionIndex] = DdPrismModelBuilder::combineUnsynchronizedActions(generationInfo, emptyAction, right.synchronizingActionToDecisionDiagramMap[actionIndex], left.identity, right.identity); - } - } - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables); - } - - // Combine identity matrices. - left.identity = left.identity * right.identity; - - // Keep track of the number of nondeterminism variables used. - left.numberOfUsedNondeterminismVariables = std::max(left.numberOfUsedNondeterminismVariables, numberOfUsedNondeterminismVariables); - } - - typename DdPrismModelBuilder::GenerationInformation& generationInfo; - }; - - template - DdPrismModelBuilder::Options::Options() : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() { - // Intentionally left empty. - } - - template - DdPrismModelBuilder::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(std::set()), terminalStates(), negatedTerminalStates() { - this->preserveFormula(formula); - this->setTerminalStatesFromFormula(formula); - } - - template - DdPrismModelBuilder::Options::Options(std::vector> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() { - if (formulas.empty()) { - this->buildAllRewardModels = true; - this->buildAllLabels = true; - } else { - for (auto const& formula : formulas) { - this->preserveFormula(*formula); - } - if (formulas.size() == 1) { - this->setTerminalStatesFromFormula(*formulas.front()); - } - } - } - - template - void DdPrismModelBuilder::Options::preserveFormula(storm::logic::Formula const& formula) { - // If we already had terminal states, we need to erase them. - if (terminalStates) { - terminalStates.reset(); - } - if (negatedTerminalStates) { - negatedTerminalStates.reset(); - } - - // If we are not required to build all reward models, we determine the reward models we need to build. - if (!buildAllRewardModels) { - std::set referencedRewardModels = formula.getReferencedRewardModels(); - rewardModelsToBuild.insert(referencedRewardModels.begin(), referencedRewardModels.end()); - } - - // Extract all the labels used in the formula. - std::vector> atomicLabelFormulas = formula.getAtomicLabelFormulas(); - for (auto const& formula : atomicLabelFormulas) { - if (!labelsToBuild) { - labelsToBuild = std::set(); - } - labelsToBuild.get().insert(formula.get()->getLabel()); - } - } - - template - void DdPrismModelBuilder::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) { - if (formula.isAtomicExpressionFormula()) { - terminalStates = formula.asAtomicExpressionFormula().getExpression(); - } else if (formula.isAtomicLabelFormula()) { - terminalStates = formula.asAtomicLabelFormula().getLabel(); - } else if (formula.isEventuallyFormula()) { - storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula(); - if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) { - this->setTerminalStatesFromFormula(sub); - } - } else if (formula.isUntilFormula()) { - storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula(); - if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) { - this->setTerminalStatesFromFormula(right); - } - storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula(); - if (left.isAtomicExpressionFormula()) { - negatedTerminalStates = left.asAtomicExpressionFormula().getExpression(); - } else if (left.isAtomicLabelFormula()) { - negatedTerminalStates = left.asAtomicLabelFormula().getLabel(); - } - } else if (formula.isProbabilityOperatorFormula()) { - storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula(); - if (sub.isEventuallyFormula() || sub.isUntilFormula()) { - this->setTerminalStatesFromFormula(sub); - } - } - } - - template - struct DdPrismModelBuilder::SystemResult { - SystemResult(storm::dd::Add const& allTransitionsDd, DdPrismModelBuilder::ModuleDecisionDiagram const& globalModule, storm::dd::Add const& stateActionDd) : allTransitionsDd(allTransitionsDd), globalModule(globalModule), stateActionDd(stateActionDd) { - // Intentionally left empty. - } - - storm::dd::Add allTransitionsDd; - typename DdPrismModelBuilder::ModuleDecisionDiagram globalModule; - storm::dd::Add stateActionDd; - }; - - template - typename DdPrismModelBuilder::UpdateDecisionDiagram DdPrismModelBuilder::createUpdateDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, storm::dd::Add const& guard, storm::prism::Update const& update) { - storm::dd::Add updateDd = generationInfo.manager->template getAddOne(); - - STORM_LOG_TRACE("Translating update " << update); - - // Iterate over all assignments (boolean and integer) and build the DD for it. - std::vector assignments = update.getAssignments(); - std::set assignedVariables; - for (auto const& assignment : assignments) { - // Record the variable as being written. - STORM_LOG_TRACE("Assigning to variable " << generationInfo.variableToRowMetaVariableMap->at(assignment.getVariable()).getName()); - assignedVariables.insert(assignment.getVariable()); - - // Translate the written variable. - auto const& primedMetaVariable = generationInfo.variableToColumnMetaVariableMap->at(assignment.getVariable()); - storm::dd::Add writtenVariable = generationInfo.manager->template getIdentity(primedMetaVariable); - - // Translate the expression that is being assigned. - storm::dd::Add updateExpression = generationInfo.rowExpressionAdapter->translateExpression(assignment.getExpression()); - - // Combine the update expression with the guard. - storm::dd::Add result = updateExpression * guard; - - // Combine the variable and the assigned expression. - storm::dd::Add tmp = result; - result = result.equals(writtenVariable).template toAdd(); - result *= guard; - - // Restrict the transitions to the range of the written variable. - result = result * generationInfo.manager->getRange(primedMetaVariable).template toAdd(); - - updateDd *= result; - } - - // Compute the set of assigned global variables. - std::set assignedGlobalVariables; - std::set_intersection(assignedVariables.begin(), assignedVariables.end(), generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), std::inserter(assignedGlobalVariables, assignedGlobalVariables.begin())); - - // All unassigned boolean variables need to keep their value. - for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) { - if (assignedVariables.find(booleanVariable.getExpressionVariable()) == assignedVariables.end()) { - STORM_LOG_TRACE("Multiplying identity of variable " << booleanVariable.getName()); - updateDd *= generationInfo.variableToIdentityMap.at(booleanVariable.getExpressionVariable()); - } - } - - // All unassigned integer variables need to keep their value. - for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) { - if (assignedVariables.find(integerVariable.getExpressionVariable()) == assignedVariables.end()) { - STORM_LOG_TRACE("Multiplying identity of variable " << integerVariable.getName()); - updateDd *= generationInfo.variableToIdentityMap.at(integerVariable.getExpressionVariable()); - } - } - - return UpdateDecisionDiagram(updateDd, assignedGlobalVariables); - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::createCommandDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, storm::prism::Command const& command) { - STORM_LOG_TRACE("Translating guard " << command.getGuardExpression()); - storm::dd::Add guard = generationInfo.rowExpressionAdapter->translateExpression(command.getGuardExpression()) * generationInfo.moduleToRangeMap[module.getName()]; - STORM_LOG_WARN_COND(!guard.isZero(), "The guard '" << command.getGuardExpression() << "' is unsatisfiable."); - - if (!guard.isZero()) { - // Create the DDs representing the individual updates. - std::vector updateResults; - for (storm::prism::Update const& update : command.getUpdates()) { - updateResults.push_back(createUpdateDecisionDiagram(generationInfo, module, guard, update)); - - STORM_LOG_WARN_COND(!updateResults.back().updateDd.isZero(), "Update '" << update << "' does not have any effect."); - } - - // Start by gathering all variables that were written in at least one update. - std::set globalVariablesInSomeUpdate; - - // If the command is labeled, we have to analyze which portion of the global variables was written by - // any of the updates and make all update results equal w.r.t. this set. If the command is not labeled, - // we can already multiply the identities of all global variables. - if (command.isLabeled()) { - std::for_each(updateResults.begin(), updateResults.end(), [&globalVariablesInSomeUpdate] (UpdateDecisionDiagram const& update) { globalVariablesInSomeUpdate.insert(update.assignedGlobalVariables.begin(), update.assignedGlobalVariables.end()); } ); - } else { - globalVariablesInSomeUpdate = generationInfo.allGlobalVariables; - } - - // Then, multiply the missing identities. - for (auto& updateResult : updateResults) { - std::set missingIdentities; - std::set_difference(globalVariablesInSomeUpdate.begin(), globalVariablesInSomeUpdate.end(), updateResult.assignedGlobalVariables.begin(), updateResult.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity for variable " << variable.getName() << "[" << variable.getIndex() << "] to update."); - updateResult.updateDd *= generationInfo.variableToIdentityMap.at(variable); - } - } - - // Now combine the update DDs to the command DD. - storm::dd::Add commandDd = generationInfo.manager->template getAddZero(); - auto updateResultsIt = updateResults.begin(); - for (auto updateIt = command.getUpdates().begin(), updateIte = command.getUpdates().end(); updateIt != updateIte; ++updateIt, ++updateResultsIt) { - storm::dd::Add probabilityDd = generationInfo.rowExpressionAdapter->translateExpression(updateIt->getLikelihoodExpression()); - commandDd += updateResultsIt->updateDd * probabilityDd; - } - - return ActionDecisionDiagram(guard, guard * commandDd, globalVariablesInSomeUpdate); - } else { - return ActionDecisionDiagram(*generationInfo.manager); - } - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::createActionDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, uint_fast64_t synchronizationActionIndex, uint_fast64_t nondeterminismVariableOffset) { - std::vector commandDds; - for (storm::prism::Command const& command : module.getCommands()) { - - // Determine whether the command is relevant for the selected action. - bool relevant = (synchronizationActionIndex == 0 && !command.isLabeled()) || (synchronizationActionIndex && command.isLabeled() && command.getActionIndex() == synchronizationActionIndex); - - if (!relevant) { - continue; - } - - STORM_LOG_TRACE("Translating command " << command); - - // At this point, the command is known to be relevant for the action. - commandDds.push_back(createCommandDecisionDiagram(generationInfo, module, command)); - } - - ActionDecisionDiagram result(*generationInfo.manager); - if (!commandDds.empty()) { - switch (generationInfo.program.getModelType()){ - case storm::prism::Program::ModelType::DTMC: - case storm::prism::Program::ModelType::CTMC: - result = combineCommandsToActionMarkovChain(generationInfo, commandDds); - break; - case storm::prism::Program::ModelType::MDP: - result = combineCommandsToActionMDP(generationInfo, commandDds, nondeterminismVariableOffset); - break; - default: - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type."); - } - } - - return result; - } - - template - std::set DdPrismModelBuilder::equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2) { - // Start by gathering all variables that were written in at least one action DD. - std::set globalVariablesInActionDd; - std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(), action2.assignedGlobalVariables.end(), std::inserter(globalVariablesInActionDd, globalVariablesInActionDd.begin())); - - std::set missingIdentitiesInAction1; - std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction1, missingIdentitiesInAction1.begin())); - for (auto const& variable : missingIdentitiesInAction1) { - action1.transitionsDd *= generationInfo.variableToIdentityMap.at(variable); - } - - std::set missingIdentitiesInAction2; - std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction2, missingIdentitiesInAction2.begin())); - for (auto const& variable : missingIdentitiesInAction2) { - action2.transitionsDd *= generationInfo.variableToIdentityMap.at(variable); - } - - return globalVariablesInActionDd; - } - - template - std::set DdPrismModelBuilder::equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo, std::vector& actionDds) { - // Start by gathering all variables that were written in at least one action DD. - std::set globalVariablesInActionDd; - for (auto const& commandDd : actionDds) { - globalVariablesInActionDd.insert(commandDd.assignedGlobalVariables.begin(), commandDd.assignedGlobalVariables.end()); - } - - STORM_LOG_TRACE("Equalizing assigned global variables."); - - // Then multiply the transitions of each action with the missing identities. - for (auto& actionDd : actionDds) { - STORM_LOG_TRACE("Equalizing next action."); - std::set missingIdentities; - std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), actionDd.assignedGlobalVariables.begin(), actionDd.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of variable " << variable.getName() << "."); - actionDd.transitionsDd *= generationInfo.variableToIdentityMap.at(variable); - } - } - return globalVariablesInActionDd; - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineCommandsToActionMarkovChain(GenerationInformation& generationInfo, std::vector& commandDds) { - storm::dd::Add allGuards = generationInfo.manager->template getAddZero(); - storm::dd::Add allCommands = generationInfo.manager->template getAddZero(); - storm::dd::Add temporary; - - // Make all command DDs assign to the same global variables. - std::set assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, commandDds); - - // Then combine the commands to the full action DD and multiply missing identities along the way. - for (auto& commandDd : commandDds) { - // Check for overlapping guards. - temporary = commandDd.guardDd * allGuards; - - // Issue a warning if there are overlapping guards in a non-CTMC model. - STORM_LOG_WARN_COND(temporary.isZero() || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC, "Guard of a command overlaps with previous guards."); - - allGuards += commandDd.guardDd; - allCommands += commandDd.transitionsDd; - } - - return ActionDecisionDiagram(allGuards, allCommands, assignedGlobalVariables); - } - - template - storm::dd::Add DdPrismModelBuilder::encodeChoice(GenerationInformation& generationInfo, uint_fast64_t nondeterminismVariableOffset, uint_fast64_t numberOfBinaryVariables, int_fast64_t value) { - storm::dd::Add result = generationInfo.manager->template getAddZero(); - - STORM_LOG_TRACE("Encoding " << value << " with " << numberOfBinaryVariables << " binary variable(s) starting from offset " << nondeterminismVariableOffset << "."); - - std::map metaVariableNameToValueMap; - for (uint_fast64_t i = nondeterminismVariableOffset; i < nondeterminismVariableOffset + numberOfBinaryVariables; ++i) { - if (value & (1ull << (numberOfBinaryVariables - i - 1))) { - metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[i], 1); - } else { - metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[i], 0); - } - } - - result.setValue(metaVariableNameToValueMap, ValueType(1)); - return result; - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineCommandsToActionMDP(GenerationInformation& generationInfo, std::vector& commandDds, uint_fast64_t nondeterminismVariableOffset) { - storm::dd::Bdd allGuards = generationInfo.manager->getBddZero(); - storm::dd::Add allCommands = generationInfo.manager->template getAddZero(); - - // Make all command DDs assign to the same global variables. - std::set assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, commandDds); - - // Sum all guards, so we can read off the maximal number of nondeterministic choices in any given state. - storm::dd::Add sumOfGuards = generationInfo.manager->template getAddZero(); - for (auto const& commandDd : commandDds) { - sumOfGuards += commandDd.guardDd; - allGuards |= commandDd.guardDd.toBdd(); - } - uint_fast64_t maxChoices = static_cast(sumOfGuards.getMax()); - - STORM_LOG_TRACE("Found " << maxChoices << " local choices."); - - // Depending on the maximal number of nondeterminstic choices, we need to use some variables to encode the nondeterminism. - if (maxChoices == 0) { - return ActionDecisionDiagram(*generationInfo.manager); - } else if (maxChoices == 1) { - // Sum up all commands. - for (auto const& commandDd : commandDds) { - allCommands += commandDd.transitionsDd; - } - return ActionDecisionDiagram(sumOfGuards, allCommands, assignedGlobalVariables); - } else { - // Calculate number of required variables to encode the nondeterminism. - uint_fast64_t numberOfBinaryVariables = static_cast(std::ceil(storm::utility::math::log2(maxChoices))); - - storm::dd::Bdd equalsNumberOfChoicesDd; - std::vector> choiceDds(maxChoices, generationInfo.manager->template getAddZero()); - std::vector> remainingDds(maxChoices, generationInfo.manager->getBddZero()); - - for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) { - // Determine the set of states with exactly currentChoices choices. - equalsNumberOfChoicesDd = sumOfGuards.equals(generationInfo.manager->getConstant(ValueType(currentChoices))); - - // If there is no such state, continue with the next possible number of choices. - if (equalsNumberOfChoicesDd.isZero()) { - continue; - } - - // Reset the previously used intermediate storage. - for (uint_fast64_t j = 0; j < currentChoices; ++j) { - choiceDds[j] = generationInfo.manager->template getAddZero(); - remainingDds[j] = equalsNumberOfChoicesDd; - } - - for (std::size_t j = 0; j < commandDds.size(); ++j) { - // Check if command guard overlaps with equalsNumberOfChoicesDd. That is, there are states with exactly currentChoices - // choices such that one outgoing choice is given by the j-th command. - storm::dd::Bdd guardChoicesIntersection = commandDds[j].guardDd.toBdd() && equalsNumberOfChoicesDd; - - // If there is no such state, continue with the next command. - if (guardChoicesIntersection.isZero()) { - continue; - } - - // Split the nondeterministic choices. - for (uint_fast64_t k = 0; k < currentChoices; ++k) { - // Calculate the overlapping part of command guard and the remaining DD. - storm::dd::Bdd remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k]; - - // Check if we can add some overlapping parts to the current index. - if (!remainingGuardChoicesIntersection.isZero()) { - // Remove overlapping parts from the remaining DD. - remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection; - - // Combine the overlapping part of the guard with command updates and add it to the resulting DD. - choiceDds[k] += remainingGuardChoicesIntersection.template toAdd() * commandDds[j].transitionsDd; - } - - // Remove overlapping parts from the command guard DD - guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection; - - // If the guard DD has become equivalent to false, we can stop here. - if (guardChoicesIntersection.isZero()) { - break; - } - } - } - - // Add the meta variables that encode the nondeterminisim to the different choices. - for (uint_fast64_t j = 0; j < currentChoices; ++j) { - allCommands += encodeChoice(generationInfo, nondeterminismVariableOffset, numberOfBinaryVariables, j) * choiceDds[j]; - } - - // Delete currentChoices out of overlapping DD - sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd(); - } - - return ActionDecisionDiagram(allGuards.template toAdd(), allCommands, assignedGlobalVariables, nondeterminismVariableOffset + numberOfBinaryVariables); - } - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineSynchronizingActions(ActionDecisionDiagram const& action1, ActionDecisionDiagram const& action2) { - std::set assignedGlobalVariables; - std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(), action2.assignedGlobalVariables.end(), std::inserter(assignedGlobalVariables, assignedGlobalVariables.begin())); - return ActionDecisionDiagram(action1.guardDd * action2.guardDd, action1.transitionsDd * action2.transitionsDd, assignedGlobalVariables, std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables)); - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2, storm::dd::Add const& identityDd1, storm::dd::Add const& identityDd2) { - - // First extend the action DDs by the other identities. - STORM_LOG_TRACE("Multiplying identities to combine unsynchronized actions."); - action1.transitionsDd = action1.transitionsDd * identityDd2; - action2.transitionsDd = action2.transitionsDd * identityDd1; - - // Then combine the extended action DDs. - return combineUnsynchronizedActions(generationInfo, action1, action2); - } - - template - typename DdPrismModelBuilder::ActionDecisionDiagram DdPrismModelBuilder::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2) { - STORM_LOG_TRACE("Combining unsynchronized actions."); - - // Make both action DDs write to the same global variables. - std::set assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, action1, action2); - - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - return ActionDecisionDiagram(action1.guardDd + action2.guardDd, action1.transitionsDd + action2.transitionsDd, assignedGlobalVariables, 0); - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - if (action1.transitionsDd.isZero()) { - return ActionDecisionDiagram(action2.guardDd, action2.transitionsDd, assignedGlobalVariables, action2.numberOfUsedNondeterminismVariables); - } else if (action2.transitionsDd.isZero()) { - return ActionDecisionDiagram(action1.guardDd, action1.transitionsDd, assignedGlobalVariables, action1.numberOfUsedNondeterminismVariables); - } - - // Bring both choices to the same number of variables that encode the nondeterminism. - uint_fast64_t numberOfUsedNondeterminismVariables = std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables); - if (action1.numberOfUsedNondeterminismVariables > action2.numberOfUsedNondeterminismVariables) { - storm::dd::Add nondeterminismEncoding = generationInfo.manager->template getAddOne(); - - for (uint_fast64_t i = action2.numberOfUsedNondeterminismVariables; i < action1.numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - action2.transitionsDd *= nondeterminismEncoding; - } else if (action2.numberOfUsedNondeterminismVariables > action1.numberOfUsedNondeterminismVariables) { - storm::dd::Add nondeterminismEncoding = generationInfo.manager->template getAddOne(); - - for (uint_fast64_t i = action1.numberOfUsedNondeterminismVariables; i < action2.numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - action1.transitionsDd *= nondeterminismEncoding; - } - - // Add a new variable that resolves the nondeterminism between the two choices. - storm::dd::Add combinedTransitions = generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[numberOfUsedNondeterminismVariables], 1).ite(action2.transitionsDd, action1.transitionsDd); - - return ActionDecisionDiagram((action1.guardDd.toBdd() || action2.guardDd.toBdd()).template toAdd(), combinedTransitions, assignedGlobalVariables, numberOfUsedNondeterminismVariables + 1); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type."); - } - } - - template - typename DdPrismModelBuilder::ModuleDecisionDiagram DdPrismModelBuilder::createModuleDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, std::map const& synchronizingActionToOffsetMap) { - // Start by creating the action DD for the independent action. - ActionDecisionDiagram independentActionDd = createActionDecisionDiagram(generationInfo, module, 0, 0); - uint_fast64_t numberOfUsedNondeterminismVariables = independentActionDd.numberOfUsedNondeterminismVariables; - - // Create module DD for all synchronizing actions of the module. - std::map actionIndexToDdMap; - for (auto const& actionIndex : module.getSynchronizingActionIndices()) { - STORM_LOG_TRACE("Creating DD for action '" << actionIndex << "'."); - ActionDecisionDiagram tmp = createActionDecisionDiagram(generationInfo, module, actionIndex, synchronizingActionToOffsetMap.at(actionIndex)); - numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, tmp.numberOfUsedNondeterminismVariables); - actionIndexToDdMap.emplace(actionIndex, tmp); - } - - return ModuleDecisionDiagram(independentActionDd, actionIndexToDdMap, generationInfo.moduleToIdentityMap.at(module.getName()), numberOfUsedNondeterminismVariables); - } - - template - storm::dd::Add DdPrismModelBuilder::getSynchronizationDecisionDiagram(GenerationInformation& generationInfo, uint_fast64_t actionIndex) { - storm::dd::Add synchronization = generationInfo.manager->template getAddOne(); - if (actionIndex != 0) { - for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) { - if ((actionIndex - 1) == i) { - synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 1).template toAdd(); - } else { - synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0).template toAdd(); - } - } - } else { - for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) { - synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0).template toAdd(); - } - } - return synchronization; - } - - template - storm::dd::Add DdPrismModelBuilder::createSystemFromModule(GenerationInformation& generationInfo, ModuleDecisionDiagram const& module) { - // If the model is an MDP, we need to encode the nondeterminism using additional variables. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - storm::dd::Add result = generationInfo.manager->template getAddZero(); - - // First, determine the highest number of nondeterminism variables that is used in any action and make - // all actions use the same amout of nondeterminism variables. - uint_fast64_t numberOfUsedNondeterminismVariables = module.numberOfUsedNondeterminismVariables; - - // Compute missing global variable identities in independent action. - std::set missingIdentities; - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - storm::dd::Add identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to independent action."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - // Add variables to independent action DD. - storm::dd::Add nondeterminismEncoding = generationInfo.manager->template getAddOne(); - for (uint_fast64_t i = module.independentAction.numberOfUsedNondeterminismVariables; i < numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - result = identityEncoding * module.independentAction.transitionsDd * nondeterminismEncoding; - - // Add variables to synchronized action DDs. - std::map> synchronizingActionToDdMap; - for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) { - // Compute missing global variable identities in synchronizing actions. - missingIdentities = std::set(); - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), synchronizingAction.second.assignedGlobalVariables.begin(), synchronizingAction.second.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to synchronizing action '" << synchronizingAction.first << "'."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - nondeterminismEncoding = generationInfo.manager->template getAddOne(); - for (uint_fast64_t i = synchronizingAction.second.numberOfUsedNondeterminismVariables; i < numberOfUsedNondeterminismVariables; ++i) { - nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd(); - } - synchronizingActionToDdMap.emplace(synchronizingAction.first, identityEncoding * synchronizingAction.second.transitionsDd * nondeterminismEncoding); - } - - // Add variables for synchronization. - result *= getSynchronizationDecisionDiagram(generationInfo); - - for (auto& synchronizingAction : synchronizingActionToDdMap) { - synchronizingAction.second *= getSynchronizationDecisionDiagram(generationInfo, synchronizingAction.first); - } - - // Now, we can simply add all synchronizing actions to the result. - for (auto const& synchronizingAction : synchronizingActionToDdMap) { - result += synchronizingAction.second; - } - - return result; - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - // Simply add all actions, but make sure to include the missing global variable identities. - - // Compute missing global variable identities in independent action. - std::set missingIdentities; - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - storm::dd::Add identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to independent action."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - storm::dd::Add result = identityEncoding * module.independentAction.transitionsDd; - - for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) { - // Compute missing global variable identities in synchronizing actions. - missingIdentities = std::set(); - std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), synchronizingAction.second.assignedGlobalVariables.begin(), synchronizingAction.second.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin())); - identityEncoding = generationInfo.manager->template getAddOne(); - for (auto const& variable : missingIdentities) { - STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to synchronizing action '" << synchronizingAction.first << "'."); - identityEncoding *= generationInfo.variableToIdentityMap.at(variable); - } - - result += identityEncoding * synchronizingAction.second.transitionsDd; - } - return result; - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type."); - } - } - - template - typename DdPrismModelBuilder::SystemResult DdPrismModelBuilder::createSystemDecisionDiagram(GenerationInformation& generationInfo) { - ModuleComposer composer(generationInfo); - ModuleDecisionDiagram system = composer.compose(generationInfo.program.specifiesSystemComposition() ? generationInfo.program.getSystemCompositionConstruct().getSystemComposition() : *generationInfo.program.getDefaultSystemComposition()); - - storm::dd::Add result = createSystemFromModule(generationInfo, system); - - // Create an auxiliary DD that is used later during the construction of reward models. - STORM_LOG_TRACE("Counting: " << result.getNonZeroCount() << " // " << result.getNodeCount()); - storm::dd::Add stateActionDd = result.sumAbstract(generationInfo.columnMetaVariables); - - // For DTMCs, we normalize each row to 1 (to account for non-determinism). - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) { - result = result / stateActionDd; - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - // For MDPs, we need to throw away the nondeterminism variables from the generation information that - // were never used. - for (uint_fast64_t index = system.numberOfUsedNondeterminismVariables; index < generationInfo.nondeterminismMetaVariables.size(); ++index) { - generationInfo.allNondeterminismVariables.erase(generationInfo.nondeterminismMetaVariables[index]); - } - generationInfo.nondeterminismMetaVariables.resize(system.numberOfUsedNondeterminismVariables); - } - - return SystemResult(result, system, stateActionDd); - } - - template - storm::models::symbolic::StandardRewardModel DdPrismModelBuilder::createRewardModelDecisionDiagrams(GenerationInformation& generationInfo, storm::prism::RewardModel const& rewardModel, ModuleDecisionDiagram const& globalModule, storm::dd::Add const& reachableStatesAdd, storm::dd::Add const& stateActionDd) { - - // Start by creating the state reward vector. - boost::optional> stateRewards; - if (rewardModel.hasStateRewards()) { - stateRewards = generationInfo.manager->template getAddZero(); - - for (auto const& stateReward : rewardModel.getStateRewards()) { - storm::dd::Add states = generationInfo.rowExpressionAdapter->translateExpression(stateReward.getStatePredicateExpression()); - storm::dd::Add rewards = generationInfo.rowExpressionAdapter->translateExpression(stateReward.getRewardValueExpression()); - - // Restrict the rewards to those states that satisfy the condition. - rewards = reachableStatesAdd * states * rewards; - - // Perform some sanity checks. - STORM_LOG_WARN_COND(rewards.getMin() >= 0, "The reward model assigns negative rewards to some states."); - STORM_LOG_WARN_COND(!rewards.isZero(), "The reward model does not assign any non-zero rewards."); - - // Add the rewards to the global state reward vector. - stateRewards.get() += rewards; - } - } - - // Next, build the state-action reward vector. - boost::optional> stateActionRewards; - if (rewardModel.hasStateActionRewards()) { - stateActionRewards = generationInfo.manager->template getAddZero(); - - for (auto const& stateActionReward : rewardModel.getStateActionRewards()) { - storm::dd::Add states = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getStatePredicateExpression()); - storm::dd::Add rewards = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getRewardValueExpression()); - storm::dd::Add synchronization = generationInfo.manager->template getAddOne(); - - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - synchronization = getSynchronizationDecisionDiagram(generationInfo, stateActionReward.getActionIndex()); - } - ActionDecisionDiagram const& actionDd = stateActionReward.isLabeled() ? globalModule.synchronizingActionToDecisionDiagramMap.at(stateActionReward.getActionIndex()) : globalModule.independentAction; - states *= actionDd.guardDd * reachableStatesAdd; - storm::dd::Add stateActionRewardDd = synchronization * states * rewards; - - // If we are building the state-action rewards for an MDP, we need to make sure that the encoding - // of the nondeterminism is present in the reward vector, so we ne need to multiply it with the - // legal state-actions. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - stateActionRewardDd *= stateActionDd; - } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - // For CTMCs, we need to multiply the entries with the exit rate of the corresponding action. - stateActionRewardDd *= actionDd.transitionsDd.sumAbstract(generationInfo.columnMetaVariables); - } - - // Perform some sanity checks. - STORM_LOG_WARN_COND(stateActionRewardDd.getMin() >= 0, "The reward model assigns negative rewards to some states."); - STORM_LOG_WARN_COND(!stateActionRewardDd.isZero(), "The reward model does not assign any non-zero rewards."); - - // Add the rewards to the global transition reward matrix. - stateActionRewards.get() += stateActionRewardDd; - } - - // Scale state-action rewards for DTMCs and CTMCs. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { - stateActionRewards.get() /= stateActionDd; - } - } - - // Then build the transition reward matrix. - boost::optional> transitionRewards; - if (rewardModel.hasTransitionRewards()) { - transitionRewards = generationInfo.manager->template getAddZero(); - - for (auto const& transitionReward : rewardModel.getTransitionRewards()) { - storm::dd::Add sourceStates = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getSourceStatePredicateExpression()); - storm::dd::Add targetStates = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getTargetStatePredicateExpression()); - storm::dd::Add rewards = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getRewardValueExpression()); - - storm::dd::Add synchronization = generationInfo.manager->template getAddOne(); - - storm::dd::Add transitions; - if (transitionReward.isLabeled()) { - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - synchronization = getSynchronizationDecisionDiagram(generationInfo, transitionReward.getActionIndex()); - } - transitions = globalModule.synchronizingActionToDecisionDiagramMap.at(transitionReward.getActionIndex()).transitionsDd; - } else { - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { - synchronization = getSynchronizationDecisionDiagram(generationInfo); - } - transitions = globalModule.independentAction.transitionsDd; - } - - storm::dd::Add transitionRewardDd = synchronization * sourceStates * targetStates * rewards; - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) { - // For DTMCs we need to keep the weighting for the scaling that follows. - transitionRewardDd = transitions * transitionRewardDd; - } else { - // For all other model types, we do not scale the rewards. - transitionRewardDd = transitions.notZero().template toAdd() * transitionRewardDd; - } - - // Perform some sanity checks. - STORM_LOG_WARN_COND(transitionRewardDd.getMin() >= 0, "The reward model assigns negative rewards to some states."); - STORM_LOG_WARN_COND(!transitionRewardDd.isZero(), "The reward model does not assign any non-zero rewards."); - - // Add the rewards to the global transition reward matrix. - transitionRewards.get() += transitionRewardDd; - } - - // Scale transition rewards for DTMCs. - if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) { - transitionRewards.get() /= stateActionDd; - } - } - - return storm::models::symbolic::StandardRewardModel(stateRewards, stateActionRewards, transitionRewards); - } - - template - std::shared_ptr> DdPrismModelBuilder::build(storm::prism::Program const& program, Options const& options) { - if (program.hasUndefinedConstants()) { - std::vector> undefinedConstants = program.getUndefinedConstants(); - std::stringstream stream; - bool printComma = false; - for (auto const& constant : undefinedConstants) { - if (printComma) { - stream << ", "; - } else { - printComma = true; - } - stream << constant.get().getName() << " (" << constant.get().getType() << ")"; - } - stream << "."; - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str()); - } - - STORM_LOG_TRACE("Building representation of program:" << std::endl << program << std::endl); - - // Start by initializing the structure used for storing all information needed during the model generation. - // In particular, this creates the meta variables used to encode the model. - GenerationInformation generationInfo(program); - - SystemResult system = createSystemDecisionDiagram(generationInfo); - storm::dd::Add transitionMatrix = system.allTransitionsDd; - - ModuleDecisionDiagram const& globalModule = system.globalModule; - storm::dd::Add stateActionDd = system.stateActionDd; - - // If we were asked to treat some states as terminal states, we cut away their transitions now. - storm::dd::Bdd terminalStatesBdd = generationInfo.manager->getBddZero(); - if (options.terminalStates || options.negatedTerminalStates) { - std::map constantsSubstitution = program.getConstantsSubstitution(); - - if (options.terminalStates) { - storm::expressions::Expression terminalExpression; - if (options.terminalStates.get().type() == typeid(storm::expressions::Expression)) { - terminalExpression = boost::get(options.terminalStates.get()); - } else { - std::string const& labelName = boost::get(options.terminalStates.get()); - if (program.hasLabel(labelName)) { - terminalExpression = program.getLabelExpression(labelName); - } else { - STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); - } - } - - if (terminalExpression.isInitialized()) { - // If the expression refers to constants of the model, we need to substitute them. - terminalExpression = terminalExpression.substitute(constantsSubstitution); - - STORM_LOG_TRACE("Making the states satisfying " << terminalExpression << " terminal."); - terminalStatesBdd = generationInfo.rowExpressionAdapter->translateExpression(terminalExpression).toBdd(); - } - } - if (options.negatedTerminalStates) { - storm::expressions::Expression negatedTerminalExpression; - if (options.negatedTerminalStates.get().type() == typeid(storm::expressions::Expression)) { - negatedTerminalExpression = boost::get(options.negatedTerminalStates.get()); - } else { - std::string const& labelName = boost::get(options.negatedTerminalStates.get()); - if (program.hasLabel(labelName)) { - negatedTerminalExpression = program.getLabelExpression(labelName); - } else { - STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'."); - } - } - - if (negatedTerminalExpression.isInitialized()) { - // If the expression refers to constants of the model, we need to substitute them. - negatedTerminalExpression = negatedTerminalExpression.substitute(constantsSubstitution); - - STORM_LOG_TRACE("Making the states *not* satisfying " << negatedTerminalExpression << " terminal."); - terminalStatesBdd |= !generationInfo.rowExpressionAdapter->translateExpression(negatedTerminalExpression).toBdd(); - } - } - - transitionMatrix *= (!terminalStatesBdd).template toAdd(); - } - - std::cout << "trans matrix has size " << transitionMatrix.getNodeCount() << std::endl; - - // Cut the transitions and rewards to the reachable fragment of the state space. - storm::dd::Bdd initialStates = createInitialStatesDecisionDiagram(generationInfo); - - storm::dd::Bdd transitionMatrixBdd = transitionMatrix.notZero(); - if (program.getModelType() == storm::prism::Program::ModelType::MDP) { - transitionMatrixBdd = transitionMatrixBdd.existsAbstract(generationInfo.allNondeterminismVariables); - } - - storm::dd::Bdd reachableStates = storm::utility::dd::computeReachableStates(initialStates, transitionMatrixBdd, generationInfo.rowMetaVariables, generationInfo.columnMetaVariables); - storm::dd::Add reachableStatesAdd = reachableStates.template toAdd(); - transitionMatrix *= reachableStatesAdd; - stateActionDd *= reachableStatesAdd; - - // Detect deadlocks and 1) fix them if requested 2) throw an error otherwise. - storm::dd::Bdd statesWithTransition = transitionMatrixBdd.existsAbstract(generationInfo.columnMetaVariables); - storm::dd::Bdd deadlockStates = reachableStates && !statesWithTransition; - - // If there are deadlocks, either fix them or raise an error. - if (!deadlockStates.isZero()) { - // If we need to fix deadlocks, we do so now. - if (!storm::settings::getModule().isDontFixDeadlocksSet()) { - STORM_LOG_INFO("Fixing deadlocks in " << deadlockStates.getNonZeroCount() << " states. The first three of these states are: "); - - storm::dd::Add deadlockStatesAdd = deadlockStates.template toAdd(); - uint_fast64_t count = 0; - for (auto it = deadlockStatesAdd.begin(), ite = deadlockStatesAdd.end(); it != ite && count < 3; ++it, ++count) { - STORM_LOG_INFO((*it).first.toPrettyString(generationInfo.rowMetaVariables) << std::endl); - } - - if (program.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::CTMC) { - storm::dd::Add identity = globalModule.identity; - - // Make sure that global variables do not change along the introduced self-loops. - for (auto const& var : generationInfo.allGlobalVariables) { - identity *= generationInfo.variableToIdentityMap.at(var); - } - - // For DTMCs, we can simply add the identity of the global module for all deadlock states. - transitionMatrix += deadlockStatesAdd * identity; - } else if (program.getModelType() == storm::prism::Program::ModelType::MDP) { - // For MDPs, however, we need to select an action associated with the self-loop, if we do not - // want to attach a lot of self-loops to the deadlock states. - storm::dd::Add action = generationInfo.manager->template getAddOne(); - for (auto const& metaVariable : generationInfo.allNondeterminismVariables) { - action *= generationInfo.manager->template getIdentity(metaVariable); - } - // Make sure that global variables do not change along the introduced self-loops. - for (auto const& var : generationInfo.allGlobalVariables) { - action *= generationInfo.variableToIdentityMap.at(var); - } - transitionMatrix += deadlockStatesAdd * globalModule.identity * action; - } - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The model contains " << deadlockStates.getNonZeroCount() << " deadlock states. Please unset the option to not fix deadlocks, if you want to fix them automatically."); - } - } - - // Reduce the deadlock states by the states that we did simply not explore. - deadlockStates = deadlockStates && !terminalStatesBdd; - - // Now build the reward models. - std::vector> selectedRewardModels; - - // First, we make sure that all selected reward models actually exist. - for (auto const& rewardModelName : options.rewardModelsToBuild) { - STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'."); - } - - for (auto const& rewardModel : program.getRewardModels()) { - if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) { - std::cout << "build all? " << buildAllRewardModels << std::endl; - selectedRewardModels.push_back(rewardModel); - } - } - // If no reward model was selected until now and a referenced reward model appears to be unique, we build - // the only existing reward model (given that no explicit name was given for the referenced reward model). - if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") { - selectedRewardModels.push_back(program.getRewardModel(0)); - } - - std::unordered_map> rewardModels; - for (auto const& rewardModel : selectedRewardModels) { - rewardModels.emplace(rewardModel.get().getName(), createRewardModelDecisionDiagrams(generationInfo, rewardModel.get(), globalModule, reachableStatesAdd, stateActionDd)); - } - - // Build the labels that can be accessed as a shortcut. - std::map labelToExpressionMapping; - for (auto const& label : program.getLabels()) { - labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression()); - } - - if (program.getModelType() == storm::prism::Program::ModelType::DTMC) { - return std::shared_ptr>(new storm::models::symbolic::Dtmc(generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables, generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.columnExpressionAdapter, generationInfo.rowColumnMetaVariablePairs, labelToExpressionMapping, rewardModels)); - } else if (program.getModelType() == storm::prism::Program::ModelType::CTMC) { - return std::shared_ptr>(new storm::models::symbolic::Ctmc(generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables, generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.columnExpressionAdapter, generationInfo.rowColumnMetaVariablePairs, labelToExpressionMapping, rewardModels)); - } else if (program.getModelType() == storm::prism::Program::ModelType::MDP) { - return std::shared_ptr>(new storm::models::symbolic::Mdp(generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables, generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.columnExpressionAdapter, generationInfo.rowColumnMetaVariablePairs, generationInfo.allNondeterminismVariables, labelToExpressionMapping, rewardModels)); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Invalid model type."); - } - } - - template - storm::dd::Bdd DdPrismModelBuilder::createInitialStatesDecisionDiagram(GenerationInformation& generationInfo) { - storm::dd::Bdd initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialStatesExpression()).toBdd(); - - for (auto const& metaVariable : generationInfo.rowMetaVariables) { - initialStates &= generationInfo.manager->getRange(metaVariable); - } - - return initialStates; - } - - // Explicitly instantiate the symbolic model builder. - template class DdPrismModelBuilder; - template class DdPrismModelBuilder; - - } // namespace adapters -} // namespace storm - - diff --git a/src/storm/builder/DdPrismModelBuilder.h b/src/storm/builder/DdPrismModelBuilder.h index 57d990b23..fb357a6c8 100644 --- a/src/storm/builder/DdPrismModelBuilder.h +++ b/src/storm/builder/DdPrismModelBuilder.h @@ -3,6 +3,7 @@ #include #include +#include #include "storm/storage/prism/Program.h" diff --git a/src/storm/builder/ExplicitModelBuilder.cpp b/src/storm/builder/ExplicitModelBuilder.cpp index 337f912b0..6711c79f2 100644 --- a/src/storm/builder/ExplicitModelBuilder.cpp +++ b/src/storm/builder/ExplicitModelBuilder.cpp @@ -277,6 +277,7 @@ namespace storm { // (a) the transition matrix // (b) the initial states // (c) the hash map storing the mapping states -> ids + // (d) fix remapping for state-generation labels // Fix (a). transitionMatrixBuilder.replaceColumns(remapping, 0); @@ -289,6 +290,8 @@ namespace storm { // Fix (c). this->stateStorage.stateToId.remap([&remapping] (StateType const& state) { return remapping[state]; } ); + + this->generator->remapStateIds([&remapping] (StateType const& state) { return remapping[state]; }); } } diff --git a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp index 245e9d54d..f1e6ba3e8 100644 --- a/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp +++ b/src/storm/builder/jit/ExplicitJitJaniModelBuilder.cpp @@ -56,7 +56,7 @@ namespace storm { #endif template - ExplicitJitJaniModelBuilder::ExplicitJitJaniModelBuilder(storm::jani::Model const& model, storm::builder::BuilderOptions const& options) : options(options), model(model.substituteConstants()), modelComponentsBuilder(model.getModelType()) { + ExplicitJitJaniModelBuilder::ExplicitJitJaniModelBuilder(storm::jani::Model const& model, storm::builder::BuilderOptions const& options) : options(options), model(model.substituteConstantsFunctions()), modelComponentsBuilder(model.getModelType()) { // Load all options from the settings module. storm::settings::modules::JitBuilderSettings const& settings = storm::settings::getModule(); @@ -147,6 +147,11 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The input model contains undefined constants that influence the graph structure of the underlying model, which is not allowed."); } #endif + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + features.remove(storm::jani::ModelFeature::StateExitRewards); + STORM_LOG_THROW(features.empty(), storm::exceptions::InvalidArgumentException, "The jit model builder does not support the following model feature(s): " << features.toString() << "."); + //STORM_LOG_THROW(!model.reusesActionsInComposition(), storm::exceptions::InvalidArgumentException, "The jit JANI model builder currently does not support reusing actions in parallel composition"); // Comment this in to print the JANI model for debugging purposes. @@ -878,29 +883,20 @@ namespace storm { void ExplicitJitJaniModelBuilder::generateRewards(cpptempl::data_map& modelData) { // Extract the reward models from the program based on the names we were given. std::vector rewardVariables; - auto const& globalVariables = model.getGlobalVariables(); - for (auto const& rewardModelName : this->options.getRewardModelNames()) { - if (globalVariables.hasVariable(rewardModelName)) { - rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); - } else { - STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); - STORM_LOG_THROW(globalVariables.getNumberOfRealTransientVariables() + globalVariables.getNumberOfUnboundedIntegerTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); + if (this->options.isBuildAllRewardModelsSet()) { + for (auto const& rewExpr : model.getAllRewardModelExpressions()) { + STORM_LOG_ERROR_COND(rewExpr.second.isVariable(), "The jit builder can not build the non-trivial reward expression '" << rewExpr.second << "'."); + rewardVariables.push_back(rewExpr.second.getBaseExpression().asVariableExpression().getVariable()); } - } - - // If no reward model was yet added, but there was one that was given in the options, we try to build the - // standard reward model. - if (rewardVariables.empty() && !this->options.getRewardModelNames().empty()) { - bool foundTransientVariable = false; - for (auto const& transientVariable : globalVariables.getTransientVariables()) { - if (transientVariable.isUnboundedIntegerVariable() || transientVariable.isRealVariable()) { - rewardVariables.push_back(transientVariable.getExpressionVariable()); - foundTransientVariable = true; - break; - } + } else { + for (auto const& rewardModelName : this->options.getRewardModelNames()) { + auto const& rewExpr = model.getRewardModelExpression(rewardModelName); + STORM_LOG_ERROR_COND(rewExpr.isVariable(), "The jit builder can not build the non-trivial reward expression '" << rewExpr << "'."); + rewardVariables.push_back(rewExpr.getBaseExpression().asVariableExpression().getVariable()); } - STORM_LOG_ASSERT(foundTransientVariable, "Expected to find a fitting transient variable."); } + // Sort the reward variables to match the order in the ordered assignments + std::sort(rewardVariables.begin(), rewardVariables.end()); std::vector rewardModels; cpptempl::data_list rewards; @@ -1558,11 +1554,12 @@ namespace storm { } std::set expressionLabelStrings; - for (auto const& expression : this->options.getExpressionLabels()) { + for (auto const& expressionLabel : this->options.getExpressionLabels()) { cpptempl::data_map label; - std::string expressionLabelString = expression.toString(); + std::string const& expressionLabelString = expressionLabel.first; + auto const& expression = expressionLabel.second; if(expressionLabelStrings.count(expressionLabelString) == 0) { - label["name"] = expression.toString(); + label["name"] = expressionLabelString; label["predicate"] = expressionTranslator.translate(shiftVariablesWrtLowerBound(expression), storm::expressions::ToCppTranslationOptions(variablePrefixes, variableToName, storm::expressions::ToCppTranslationMode::CastDouble)); labels.push_back(label); expressionLabelStrings.insert(expressionLabelString); diff --git a/src/storm/builder/jit/ModelComponentsBuilder.cpp b/src/storm/builder/jit/ModelComponentsBuilder.cpp index 208d4490f..34cdf8af3 100644 --- a/src/storm/builder/jit/ModelComponentsBuilder.cpp +++ b/src/storm/builder/jit/ModelComponentsBuilder.cpp @@ -133,6 +133,7 @@ namespace storm { } else if (modelType == storm::jani::ModelType::MDP || modelType == storm::jani::ModelType::LTS) { return new storm::models::sparse::Mdp>(std::move(transitionMatrix), std::move(stateLabeling), std::move(rewardModels)); } else if (modelType == storm::jani::ModelType::MA) { + markovianStates->resize(transitionMatrix.getRowGroupCount()); return new storm::models::sparse::MarkovAutomaton>(std::move(transitionMatrix), std::move(stateLabeling), std::move(*markovianStates), std::move(rewardModels)); } else { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Model type unsupported by JIT builder."); diff --git a/src/storm/environment/Environment.cpp b/src/storm/environment/Environment.cpp index 0836de3f7..6d5d3ca2b 100644 --- a/src/storm/environment/Environment.cpp +++ b/src/storm/environment/Environment.cpp @@ -1,6 +1,8 @@ #include "storm/environment/Environment.h" #include "storm/environment/SubEnvironment.h" #include "storm/environment/solver/SolverEnvironment.h" +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" + namespace storm { @@ -12,11 +14,28 @@ namespace storm { // Intentionally left empty. } + Environment::Environment(Environment const& other) : internalEnv(other.internalEnv) { + // Intentionally left empty. + } + + Environment& Environment::operator=(Environment const& other) { + internalEnv = other.internalEnv; + return *this; + } + SolverEnvironment& Environment::solver() { - return solverEnvironment.get(); + return internalEnv.get().solverEnvironment.get(); } SolverEnvironment const& Environment::solver() const { - return solverEnvironment.get(); + return internalEnv.get().solverEnvironment.get(); + } + + ModelCheckerEnvironment& Environment::modelchecker() { + return internalEnv.get().modelcheckerEnvironment.get(); + } + + ModelCheckerEnvironment const& Environment::modelchecker() const { + return internalEnv.get().modelcheckerEnvironment.get(); } } \ No newline at end of file diff --git a/src/storm/environment/Environment.h b/src/storm/environment/Environment.h index 988ca34c6..30ac31803 100644 --- a/src/storm/environment/Environment.h +++ b/src/storm/environment/Environment.h @@ -6,19 +6,30 @@ namespace storm { // Forward declare sub-environments class SolverEnvironment; + class ModelCheckerEnvironment; + + // Avoid implementing ugly copy constructors for environment by using an internal environment. + struct InternalEnvironment { + SubEnvironment solverEnvironment; + SubEnvironment modelcheckerEnvironment; + }; class Environment { public: Environment(); virtual ~Environment(); + Environment(Environment const& other); + Environment& operator=(Environment const& other); SolverEnvironment& solver(); SolverEnvironment const& solver() const; + ModelCheckerEnvironment& modelchecker(); + ModelCheckerEnvironment const& modelchecker() const; private: - SubEnvironment solverEnvironment; + SubEnvironment internalEnv; }; } diff --git a/src/storm/environment/SubEnvironment.cpp b/src/storm/environment/SubEnvironment.cpp index 698300f03..5226fdca4 100644 --- a/src/storm/environment/SubEnvironment.cpp +++ b/src/storm/environment/SubEnvironment.cpp @@ -1,45 +1,72 @@ -#include +#include + +#include "storm/environment/Environment.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" + #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" namespace storm { template - SubEnvironment::SubEnvironment() : subEnv(std::make_unique()) { + SubEnvironment::SubEnvironment() : subEnv(nullptr) { // Intentionally left empty } template - SubEnvironment::SubEnvironment(SubEnvironment const& other) : subEnv(new EnvironmentType(*other.subEnv)) { + SubEnvironment::SubEnvironment(SubEnvironment const& other) : subEnv(other.subEnv ? new EnvironmentType(*other.subEnv) : nullptr) { // Intentionally left empty } template SubEnvironment& SubEnvironment::operator=(SubEnvironment const& other) { - subEnv = std::make_unique(*other.subEnv); + if (other.subEnv) { + subEnv = std::make_unique(*other.subEnv); + } else { + subEnv.reset(); + } return *this; } template EnvironmentType const& SubEnvironment::get() const { + assertInitialized(); return *subEnv; } template EnvironmentType& SubEnvironment::get() { + assertInitialized(); return *subEnv; } + template + void SubEnvironment::assertInitialized() const { + if (!subEnv) { + subEnv = std::make_unique(); + } + } + + template class SubEnvironment; + + template class SubEnvironment; + template class SubEnvironment; + template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; template class SubEnvironment; + template class SubEnvironment; template class SubEnvironment; + template class SubEnvironment; } diff --git a/src/storm/environment/SubEnvironment.h b/src/storm/environment/SubEnvironment.h index 2b6ecbf87..b1858936d 100644 --- a/src/storm/environment/SubEnvironment.h +++ b/src/storm/environment/SubEnvironment.h @@ -16,8 +16,8 @@ namespace storm { EnvironmentType& get(); private: - std::unique_ptr subEnv; + void assertInitialized() const; + mutable std::unique_ptr subEnv; }; } - diff --git a/src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp b/src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp new file mode 100644 index 000000000..f0d917a28 --- /dev/null +++ b/src/storm/environment/modelchecker/ModelCheckerEnvironment.cpp @@ -0,0 +1,31 @@ +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" + +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" + + +namespace storm { + + ModelCheckerEnvironment::ModelCheckerEnvironment() { + // Intentionally left empty + } + + ModelCheckerEnvironment::~ModelCheckerEnvironment() { + // Intentionally left empty + } + + MultiObjectiveModelCheckerEnvironment& ModelCheckerEnvironment::multi() { + return multiObjectiveModelCheckerEnvironment.get(); + } + + MultiObjectiveModelCheckerEnvironment const& ModelCheckerEnvironment::multi() const { + return multiObjectiveModelCheckerEnvironment.get(); + } +} + + diff --git a/src/storm/environment/modelchecker/ModelCheckerEnvironment.h b/src/storm/environment/modelchecker/ModelCheckerEnvironment.h new file mode 100644 index 000000000..2ec1eebd8 --- /dev/null +++ b/src/storm/environment/modelchecker/ModelCheckerEnvironment.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include "storm/environment/Environment.h" +#include "storm/environment/SubEnvironment.h" + +namespace storm { + + // Forward declare subenvironments + class MultiObjectiveModelCheckerEnvironment; + + class ModelCheckerEnvironment { + public: + + ModelCheckerEnvironment(); + ~ModelCheckerEnvironment(); + + MultiObjectiveModelCheckerEnvironment& multi(); + MultiObjectiveModelCheckerEnvironment const& multi() const; + + + private: + SubEnvironment multiObjectiveModelCheckerEnvironment; + }; +} + diff --git a/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp new file mode 100644 index 000000000..92b51fde8 --- /dev/null +++ b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.cpp @@ -0,0 +1,100 @@ +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + + MultiObjectiveModelCheckerEnvironment::MultiObjectiveModelCheckerEnvironment() { + auto const& multiobjectiveSettings = storm::settings::getModule(); + method = multiobjectiveSettings.getMultiObjectiveMethod(); + if (multiobjectiveSettings.isExportPlotSet()) { + plotPathUnderApprox = multiobjectiveSettings.getExportPlotDirectory() + "underapproximation.csv"; + plotPathOverApprox = multiobjectiveSettings.getExportPlotDirectory() + "overapproximation.csv"; + plotPathParetoPoints = multiobjectiveSettings.getExportPlotDirectory() + "paretopoints.csv"; + } + + precision = storm::utility::convertNumber(multiobjectiveSettings.getPrecision()); + if (multiobjectiveSettings.isMaxStepsSet()) { + maxSteps = multiobjectiveSettings.getMaxSteps(); + } + } + + MultiObjectiveModelCheckerEnvironment::~MultiObjectiveModelCheckerEnvironment() { + // Intentionally left empty + } + + storm::modelchecker::multiobjective::MultiObjectiveMethod const& MultiObjectiveModelCheckerEnvironment::getMethod() const { + return this->method; + } + + void MultiObjectiveModelCheckerEnvironment::setMethod(storm::modelchecker::multiobjective::MultiObjectiveMethod value) { + this->method = value; + } + + bool MultiObjectiveModelCheckerEnvironment::isExportPlotSet() const { + return this->plotPathUnderApprox.is_initialized() || this->plotPathOverApprox.is_initialized() || this->plotPathParetoPoints.is_initialized(); + } + + boost::optional MultiObjectiveModelCheckerEnvironment::getPlotPathUnderApproximation() const { + return plotPathUnderApprox; + } + + void MultiObjectiveModelCheckerEnvironment::setPlotPathUnderApproximation(std::string const& path) { + plotPathUnderApprox = path; + } + + void MultiObjectiveModelCheckerEnvironment::unsetPlotPathUnderApproximation() { + plotPathUnderApprox = boost::none; + } + + boost::optional MultiObjectiveModelCheckerEnvironment::getPlotPathOverApproximation() const { + return plotPathOverApprox; + } + + void MultiObjectiveModelCheckerEnvironment::setPlotPathOverApproximation(std::string const& path) { + plotPathOverApprox = path; + } + + void MultiObjectiveModelCheckerEnvironment::unsetPlotPathOverApproximation() { + plotPathOverApprox = boost::none; + } + + boost::optional MultiObjectiveModelCheckerEnvironment::getPlotPathParetoPoints() const { + return plotPathParetoPoints; + } + + void MultiObjectiveModelCheckerEnvironment::setPlotPathParetoPoints(std::string const& path) { + plotPathParetoPoints = path; + } + + void MultiObjectiveModelCheckerEnvironment::unsetPlotPathParetoPoints() { + plotPathParetoPoints = boost::none; + } + + storm::RationalNumber const& MultiObjectiveModelCheckerEnvironment::getPrecision() const { + return precision; + } + + void MultiObjectiveModelCheckerEnvironment::setPrecision(storm::RationalNumber const& value) { + precision = value; + } + + bool MultiObjectiveModelCheckerEnvironment::isMaxStepsSet() const { + return maxSteps.is_initialized(); + } + + uint64_t const& MultiObjectiveModelCheckerEnvironment::getMaxSteps() const { + return maxSteps.get(); + } + + void MultiObjectiveModelCheckerEnvironment::setMaxSteps(uint64_t const& value) { + maxSteps = value; + } + + void MultiObjectiveModelCheckerEnvironment::unsetMaxSteps() { + maxSteps = boost::none; + } +} \ No newline at end of file diff --git a/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h new file mode 100644 index 000000000..f1d4f0203 --- /dev/null +++ b/src/storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include "storm/environment/modelchecker/ModelCheckerEnvironment.h" +#include "storm/modelchecker/multiobjective/MultiObjectiveModelCheckingMethod.h" +#include "storm/adapters/RationalNumberAdapter.h" + +namespace storm { + + class MultiObjectiveModelCheckerEnvironment { + public: + + MultiObjectiveModelCheckerEnvironment(); + ~MultiObjectiveModelCheckerEnvironment(); + + storm::modelchecker::multiobjective::MultiObjectiveMethod const& getMethod() const; + void setMethod(storm::modelchecker::multiobjective::MultiObjectiveMethod value); + + bool isExportPlotSet() const; + boost::optional getPlotPathUnderApproximation() const; + void setPlotPathUnderApproximation(std::string const& path); + void unsetPlotPathUnderApproximation(); + boost::optional getPlotPathOverApproximation() const; + void setPlotPathOverApproximation(std::string const& path); + void unsetPlotPathOverApproximation(); + boost::optional getPlotPathParetoPoints() const; + void setPlotPathParetoPoints(std::string const& path); + void unsetPlotPathParetoPoints(); + + storm::RationalNumber const& getPrecision() const; + void setPrecision(storm::RationalNumber const& value); + + uint64_t const& getMaxSteps() const; + bool isMaxStepsSet() const; + void setMaxSteps(uint64_t const& value); + void unsetMaxSteps(); + + + private: + storm::modelchecker::multiobjective::MultiObjectiveMethod method; + boost::optional plotPathUnderApprox, plotPathOverApprox, plotPathParetoPoints; + storm::RationalNumber precision; + boost::optional maxSteps; + + }; +} + diff --git a/src/storm/environment/solver/EigenSolverEnvironment.cpp b/src/storm/environment/solver/EigenSolverEnvironment.cpp index a36bd0062..4b1c561e0 100644 --- a/src/storm/environment/solver/EigenSolverEnvironment.cpp +++ b/src/storm/environment/solver/EigenSolverEnvironment.cpp @@ -14,7 +14,11 @@ namespace storm { methodSetFromDefault = eigenSettings.isLinearEquationSystemMethodSetFromDefault(); preconditioner = eigenSettings.getPreconditioningMethod(); restartThreshold = eigenSettings.getRestartIterationCount(); - maxIterationCount = eigenSettings.getMaximalIterationCount(); + if (eigenSettings.isMaximalIterationCountSet()) { + maxIterationCount = eigenSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(eigenSettings.getPrecision()); } @@ -44,11 +48,11 @@ namespace storm { } uint64_t const& EigenSolverEnvironment::getRestartThreshold() const { - return maxIterationCount; + return restartThreshold; } void EigenSolverEnvironment::setRestartThreshold(uint64_t value) { - maxIterationCount = value; + restartThreshold = value; } uint64_t const& EigenSolverEnvironment::getMaximalNumberOfIterations() const { diff --git a/src/storm/environment/solver/GameSolverEnvironment.cpp b/src/storm/environment/solver/GameSolverEnvironment.cpp index aea27278d..9793312d3 100644 --- a/src/storm/environment/solver/GameSolverEnvironment.cpp +++ b/src/storm/environment/solver/GameSolverEnvironment.cpp @@ -12,7 +12,11 @@ namespace storm { gameMethod = gameSettings.getGameSolvingMethod(); methodSetFromDefault = gameSettings.isGameSolvingMethodSetFromDefaultValue(); - maxIterationCount = gameSettings.getMaximalIterationCount(); + if (gameSettings.isMaximalIterationCountSet()) { + maxIterationCount = gameSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(gameSettings.getPrecision()); considerRelativeTerminationCriterion = gameSettings.getConvergenceCriterion() == storm::settings::modules::GameSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || gameSettings.getConvergenceCriterion() == storm::settings::modules::GameSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); diff --git a/src/storm/environment/solver/GmmxxSolverEnvironment.cpp b/src/storm/environment/solver/GmmxxSolverEnvironment.cpp index 8b8992db4..d78f3e039 100644 --- a/src/storm/environment/solver/GmmxxSolverEnvironment.cpp +++ b/src/storm/environment/solver/GmmxxSolverEnvironment.cpp @@ -13,7 +13,11 @@ namespace storm { method = gmmxxSettings.getLinearEquationSystemMethod(); preconditioner = gmmxxSettings.getPreconditioningMethod(); restartThreshold = gmmxxSettings.getRestartIterationCount(); - maxIterationCount = gmmxxSettings.getMaximalIterationCount(); + if (gmmxxSettings.isMaximalIterationCountSet()) { + maxIterationCount = gmmxxSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(gmmxxSettings.getPrecision()); } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp index ed4b6145b..63cf5c698 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.cpp +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.cpp @@ -12,17 +12,21 @@ namespace storm { minMaxMethod = minMaxSettings.getMinMaxEquationSolvingMethod(); methodSetFromDefault = minMaxSettings.isMinMaxEquationSolvingMethodSetFromDefaultValue(); - maxIterationCount = minMaxSettings.getMaximalIterationCount(); + if (minMaxSettings.isMaximalIterationCountSet()) { + maxIterationCount = minMaxSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(minMaxSettings.getPrecision()); considerRelativeTerminationCriterion = minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || minMaxSettings.getConvergenceCriterion() == storm::settings::modules::MinMaxEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); multiplicationStyle = minMaxSettings.getValueIterationMultiplicationStyle(); + symmetricUpdates = minMaxSettings.isForceIntervalIterationSymmetricUpdatesSet(); } MinMaxSolverEnvironment::~MinMaxSolverEnvironment() { // Intentionally left empty } - storm::solver::MinMaxMethod const& MinMaxSolverEnvironment::getMethod() const { return minMaxMethod; @@ -32,8 +36,8 @@ namespace storm { return methodSetFromDefault; } - void MinMaxSolverEnvironment::setMethod(storm::solver::MinMaxMethod value) { - methodSetFromDefault = false; + void MinMaxSolverEnvironment::setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault) { + methodSetFromDefault = isSetFromDefault; minMaxMethod = value; } @@ -69,6 +73,12 @@ namespace storm { multiplicationStyle = value; } - - + bool MinMaxSolverEnvironment::isSymmetricUpdatesSet() const { + return symmetricUpdates; + } + + void MinMaxSolverEnvironment::setSymmetricUpdates(bool value) { + symmetricUpdates = value; + } + } diff --git a/src/storm/environment/solver/MinMaxSolverEnvironment.h b/src/storm/environment/solver/MinMaxSolverEnvironment.h index 6cca14221..3f54f0fa9 100644 --- a/src/storm/environment/solver/MinMaxSolverEnvironment.h +++ b/src/storm/environment/solver/MinMaxSolverEnvironment.h @@ -16,7 +16,7 @@ namespace storm { storm::solver::MinMaxMethod const& getMethod() const; bool const& isMethodSetFromDefault() const; - void setMethod(storm::solver::MinMaxMethod value); + void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault = false); uint64_t const& getMaximalNumberOfIterations() const; void setMaximalNumberOfIterations(uint64_t value); storm::RationalNumber const& getPrecision() const; @@ -25,6 +25,10 @@ namespace storm { void setRelativeTerminationCriterion(bool value); storm::solver::MultiplicationStyle const& getMultiplicationStyle() const; void setMultiplicationStyle(storm::solver::MultiplicationStyle value); + bool isForceBoundsSet() const; + void setForceBounds(bool value); + bool isSymmetricUpdatesSet() const; + void setSymmetricUpdates(bool value); private: storm::solver::MinMaxMethod minMaxMethod; @@ -33,7 +37,8 @@ namespace storm { storm::RationalNumber precision; bool considerRelativeTerminationCriterion; storm::solver::MultiplicationStyle multiplicationStyle; - + bool forceBounds; + bool symmetricUpdates; }; } diff --git a/src/storm/environment/solver/MultiplierEnvironment.cpp b/src/storm/environment/solver/MultiplierEnvironment.cpp new file mode 100644 index 000000000..85e3bac77 --- /dev/null +++ b/src/storm/environment/solver/MultiplierEnvironment.cpp @@ -0,0 +1,33 @@ +#include "storm/environment/solver/MultiplierEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/MultiplierSettings.h" +#include "storm/utility/constants.h" +#include "storm/utility/macros.h" + +namespace storm { + + MultiplierEnvironment::MultiplierEnvironment() { + auto const& multiplierSettings = storm::settings::getModule(); + type = multiplierSettings.getMultiplierType(); + typeSetFromDefault = multiplierSettings.isMultiplierTypeSetFromDefaultValue(); + } + + MultiplierEnvironment::~MultiplierEnvironment() { + // Intentionally left empty + } + + storm::solver::MultiplierType const& MultiplierEnvironment::getType() const { + return type; + } + + bool const& MultiplierEnvironment::isTypeSetFromDefault() const { + return typeSetFromDefault; + } + + void MultiplierEnvironment::setType(storm::solver::MultiplierType value, bool isSetFromDefault) { + type = value; + typeSetFromDefault = isSetFromDefault; + } + +} diff --git a/src/storm/environment/solver/MultiplierEnvironment.h b/src/storm/environment/solver/MultiplierEnvironment.h new file mode 100644 index 000000000..d9e35f5fb --- /dev/null +++ b/src/storm/environment/solver/MultiplierEnvironment.h @@ -0,0 +1,23 @@ +#pragma once + +#include "storm/environment/solver/SolverEnvironment.h" +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + + class MultiplierEnvironment { + public: + + MultiplierEnvironment(); + ~MultiplierEnvironment(); + + storm::solver::MultiplierType const& getType() const; + bool const& isTypeSetFromDefault() const; + void setType(storm::solver::MultiplierType value, bool isSetFromDefault = false); + + private: + storm::solver::MultiplierType type; + bool typeSetFromDefault; + }; +} + diff --git a/src/storm/environment/solver/NativeSolverEnvironment.cpp b/src/storm/environment/solver/NativeSolverEnvironment.cpp index 3a3d0cb08..9d152f92f 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.cpp +++ b/src/storm/environment/solver/NativeSolverEnvironment.cpp @@ -12,12 +12,18 @@ namespace storm { method = nativeSettings.getLinearEquationSystemMethod(); methodSetFromDefault = nativeSettings.isLinearEquationSystemTechniqueSetFromDefaultValue(); - maxIterationCount = nativeSettings.getMaximalIterationCount(); + if (nativeSettings.isMaximalIterationCountSet()) { + maxIterationCount = nativeSettings.getMaximalIterationCount(); + } else { + maxIterationCount = std::numeric_limits::max(); + } precision = storm::utility::convertNumber(nativeSettings.getPrecision()); considerRelativeTerminationCriterion = nativeSettings.getConvergenceCriterion() == storm::settings::modules::NativeEquationSolverSettings::ConvergenceCriterion::Relative; STORM_LOG_ASSERT(considerRelativeTerminationCriterion || nativeSettings.getConvergenceCriterion() == storm::settings::modules::NativeEquationSolverSettings::ConvergenceCriterion::Absolute, "Unknown convergence criterion"); powerMethodMultiplicationStyle = nativeSettings.getPowerMethodMultiplicationStyle(); sorOmega = storm::utility::convertNumber(nativeSettings.getOmega()); + symmetricUpdates = nativeSettings.isForceIntervalIterationSymmetricUpdatesSet(); + } NativeSolverEnvironment::~NativeSolverEnvironment() { @@ -77,4 +83,12 @@ namespace storm { sorOmega = value; } + bool NativeSolverEnvironment::isSymmetricUpdatesSet() const { + return symmetricUpdates; + } + + void NativeSolverEnvironment::setSymmetricUpdates(bool value) { + symmetricUpdates = value; + } + } diff --git a/src/storm/environment/solver/NativeSolverEnvironment.h b/src/storm/environment/solver/NativeSolverEnvironment.h index 51b96f613..d0b0e8b9b 100644 --- a/src/storm/environment/solver/NativeSolverEnvironment.h +++ b/src/storm/environment/solver/NativeSolverEnvironment.h @@ -27,6 +27,8 @@ namespace storm { void setPowerMethodMultiplicationStyle(storm::solver::MultiplicationStyle value); storm::RationalNumber const& getSorOmega() const; void setSorOmega(storm::RationalNumber const& value); + bool isSymmetricUpdatesSet() const; + void setSymmetricUpdates(bool value); private: storm::solver::NativeLinearEquationSolverMethod method; @@ -36,6 +38,7 @@ namespace storm { bool considerRelativeTerminationCriterion; storm::solver::MultiplicationStyle powerMethodMultiplicationStyle; storm::RationalNumber sorOmega; + bool symmetricUpdates; }; } diff --git a/src/storm/environment/solver/SolverEnvironment.cpp b/src/storm/environment/solver/SolverEnvironment.cpp index 8371b8158..42600adbb 100644 --- a/src/storm/environment/solver/SolverEnvironment.cpp +++ b/src/storm/environment/solver/SolverEnvironment.cpp @@ -1,10 +1,12 @@ #include "storm/environment/solver/SolverEnvironment.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/MultiplierEnvironment.h" #include "storm/environment/solver/EigenSolverEnvironment.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" @@ -12,6 +14,7 @@ #include "storm/utility/macros.h" #include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" namespace storm { @@ -34,6 +37,14 @@ namespace storm { return minMaxSolverEnvironment.get(); } + MultiplierEnvironment& SolverEnvironment::multiplier() { + return multiplierEnvironment.get(); + } + + MultiplierEnvironment const& SolverEnvironment::multiplier() const { + return multiplierEnvironment.get(); + } + EigenSolverEnvironment& SolverEnvironment::eigen() { return eigenSolverEnvironment.get(); } @@ -66,6 +77,14 @@ namespace storm { return gameSolverEnvironment.get(); } + TopologicalSolverEnvironment& SolverEnvironment::topological() { + return topologicalSolverEnvironment.get(); + } + + TopologicalSolverEnvironment const& SolverEnvironment::topological() const { + return topologicalSolverEnvironment.get(); + } + bool SolverEnvironment::isForceSoundness() const { return forceSoundness; } @@ -78,8 +97,8 @@ namespace storm { return linearEquationSolverType; } - void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value) { - linearEquationSolverTypeSetFromDefault = false; + void SolverEnvironment::setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault) { + linearEquationSolverTypeSetFromDefault = isSetFromDefault; linearEquationSolverType = value; } @@ -87,44 +106,49 @@ namespace storm { return linearEquationSolverTypeSetFromDefault; } - boost::optional SolverEnvironment::getPrecisionOfCurrentLinearEquationSolver() const { - switch (getLinearEquationSolverType()) { + std::pair, boost::optional> SolverEnvironment::getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const& solverType) const { + std::pair, boost::optional> result; + switch (solverType) { case storm::solver::EquationSolverType::Gmmxx: - return gmmxx().getPrecision(); + result.first = gmmxx().getPrecision(); + break; case storm::solver::EquationSolverType::Eigen: - return eigen().getPrecision(); + result.first = eigen().getPrecision(); + break; case storm::solver::EquationSolverType::Native: - return native().getPrecision(); + result.first = native().getPrecision(); + result.second = native().getRelativeTerminationCriterion(); + break; case storm::solver::EquationSolverType::Elimination: - return boost::none; + break; + case storm::solver::EquationSolverType::Topological: + result = getPrecisionOfLinearEquationSolver(topological().getUnderlyingEquationSolverType()); + break; default: - STORM_LOG_ASSERT(false, "The selected solver type is unknown."); + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "The selected solver type is unknown."); } + return result; } - void SolverEnvironment::setLinearEquationSolverPrecision(storm::RationalNumber const& value) { - STORM_LOG_ASSERT(getLinearEquationSolverType() == storm::solver::EquationSolverType::Native || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Gmmxx || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Eigen || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination, - "The current solver type is not respected in this method."); - native().setPrecision(value); - gmmxx().setPrecision(value); - eigen().setPrecision(value); - // Elimination solver does not have a precision - } - - void SolverEnvironment::setLinearEquationSolverRelativeTerminationCriterion(bool value) { + void SolverEnvironment::setLinearEquationSolverPrecision(boost::optional const& newPrecision, boost::optional const& relativePrecision) { + // Assert that each solver type is handled in this method. STORM_LOG_ASSERT(getLinearEquationSolverType() == storm::solver::EquationSolverType::Native || getLinearEquationSolverType() == storm::solver::EquationSolverType::Gmmxx || getLinearEquationSolverType() == storm::solver::EquationSolverType::Eigen || - getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination, + getLinearEquationSolverType() == storm::solver::EquationSolverType::Elimination || + getLinearEquationSolverType() == storm::solver::EquationSolverType::Topological, "The current solver type is not respected in this method."); - native().setRelativeTerminationCriterion(value); - // Elimination, gmm and eigen solver do not have an option for relative termination criterion + if (newPrecision) { + native().setPrecision(newPrecision.get()); + gmmxx().setPrecision(newPrecision.get()); + eigen().setPrecision(newPrecision.get()); + // Elimination and Topological solver do not have a precision + } + if (relativePrecision) { + native().setRelativeTerminationCriterion(relativePrecision.get()); + // gmm, eigen, elimination, and topological solvers do not have a precision + } } - - } diff --git a/src/storm/environment/solver/SolverEnvironment.h b/src/storm/environment/solver/SolverEnvironment.h index ec591beb2..5e24652e1 100644 --- a/src/storm/environment/solver/SolverEnvironment.h +++ b/src/storm/environment/solver/SolverEnvironment.h @@ -15,7 +15,9 @@ namespace storm { class GmmxxSolverEnvironment; class NativeSolverEnvironment; class MinMaxSolverEnvironment; + class MultiplierEnvironment; class GameSolverEnvironment; + class TopologicalSolverEnvironment; class SolverEnvironment { public: @@ -31,26 +33,31 @@ namespace storm { NativeSolverEnvironment const& native() const; MinMaxSolverEnvironment& minMax(); MinMaxSolverEnvironment const& minMax() const; + MultiplierEnvironment& multiplier(); + MultiplierEnvironment const& multiplier() const; GameSolverEnvironment& game(); GameSolverEnvironment const& game() const; + TopologicalSolverEnvironment& topological(); + TopologicalSolverEnvironment const& topological() const; bool isForceSoundness() const; void setForceSoundness(bool value); storm::solver::EquationSolverType const& getLinearEquationSolverType() const; - void setLinearEquationSolverType(storm::solver::EquationSolverType const& value); + void setLinearEquationSolverType(storm::solver::EquationSolverType const& value, bool isSetFromDefault = false); bool isLinearEquationSolverTypeSetFromDefaultValue() const; - - boost::optional getPrecisionOfCurrentLinearEquationSolver() const; - void setLinearEquationSolverPrecision(storm::RationalNumber const& value); - void setLinearEquationSolverRelativeTerminationCriterion(bool value); + + std::pair, boost::optional> getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const& solverType) const; + void setLinearEquationSolverPrecision(boost::optional const& newPrecision, boost::optional const& relativePrecision = boost::none); private: SubEnvironment eigenSolverEnvironment; SubEnvironment gmmxxSolverEnvironment; SubEnvironment nativeSolverEnvironment; SubEnvironment gameSolverEnvironment; + SubEnvironment topologicalSolverEnvironment; SubEnvironment minMaxSolverEnvironment; + SubEnvironment multiplierEnvironment; storm::solver::EquationSolverType linearEquationSolverType; bool linearEquationSolverTypeSetFromDefault; diff --git a/src/storm/environment/solver/TopologicalSolverEnvironment.cpp b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp new file mode 100644 index 000000000..aa580d67c --- /dev/null +++ b/src/storm/environment/solver/TopologicalSolverEnvironment.cpp @@ -0,0 +1,54 @@ +#include "storm/environment/solver/TopologicalSolverEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + + TopologicalSolverEnvironment::TopologicalSolverEnvironment() { + auto const& topologicalSettings = storm::settings::getModule(); + underlyingEquationSolverType = topologicalSettings.getUnderlyingEquationSolverType(); + underlyingEquationSolverTypeSetFromDefault = topologicalSettings.isUnderlyingEquationSolverTypeSetFromDefaultValue(); + + underlyingMinMaxMethod = topologicalSettings.getUnderlyingMinMaxMethod(); + underlyingMinMaxMethodSetFromDefault = topologicalSettings.isUnderlyingMinMaxMethodSetFromDefaultValue(); + } + + TopologicalSolverEnvironment::~TopologicalSolverEnvironment() { + // Intentionally left empty + } + + storm::solver::EquationSolverType const& TopologicalSolverEnvironment::getUnderlyingEquationSolverType() const { + return underlyingEquationSolverType; + } + + bool const& TopologicalSolverEnvironment::isUnderlyingEquationSolverTypeSetFromDefault() const { + return underlyingEquationSolverTypeSetFromDefault; + } + + void TopologicalSolverEnvironment::setUnderlyingEquationSolverType(storm::solver::EquationSolverType value) { + STORM_LOG_THROW(value != storm::solver::EquationSolverType::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver."); + underlyingEquationSolverTypeSetFromDefault = false; + underlyingEquationSolverType = value; + } + + storm::solver::MinMaxMethod const& TopologicalSolverEnvironment::getUnderlyingMinMaxMethod() const { + return underlyingMinMaxMethod; + } + + bool const& TopologicalSolverEnvironment::isUnderlyingMinMaxMethodSetFromDefault() const { + return underlyingMinMaxMethodSetFromDefault; + } + + void TopologicalSolverEnvironment::setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value) { + STORM_LOG_THROW(value != storm::solver::MinMaxMethod::Topological, storm::exceptions::InvalidArgumentException, "Can not use the topological solver as underlying solver of the topological solver."); + underlyingMinMaxMethodSetFromDefault = false; + underlyingMinMaxMethod = value; + } + + + +} diff --git a/src/storm/environment/solver/TopologicalSolverEnvironment.h b/src/storm/environment/solver/TopologicalSolverEnvironment.h new file mode 100644 index 000000000..594dd3d86 --- /dev/null +++ b/src/storm/environment/solver/TopologicalSolverEnvironment.h @@ -0,0 +1,31 @@ +#pragma once + +#include "storm/environment/solver/SolverEnvironment.h" + +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + + class TopologicalSolverEnvironment { + public: + + TopologicalSolverEnvironment(); + ~TopologicalSolverEnvironment(); + + storm::solver::EquationSolverType const& getUnderlyingEquationSolverType() const; + bool const& isUnderlyingEquationSolverTypeSetFromDefault() const; + void setUnderlyingEquationSolverType(storm::solver::EquationSolverType value); + + storm::solver::MinMaxMethod const& getUnderlyingMinMaxMethod() const; + bool const& isUnderlyingMinMaxMethodSetFromDefault() const; + void setUnderlyingMinMaxMethod(storm::solver::MinMaxMethod value); + + private: + storm::solver::EquationSolverType underlyingEquationSolverType; + bool underlyingEquationSolverTypeSetFromDefault; + + storm::solver::MinMaxMethod underlyingMinMaxMethod; + bool underlyingMinMaxMethodSetFromDefault; + }; +} + diff --git a/src/storm/generator/CompressedState.cpp b/src/storm/generator/CompressedState.cpp index 1711242b9..0bdda94de 100644 --- a/src/storm/generator/CompressedState.cpp +++ b/src/storm/generator/CompressedState.cpp @@ -86,6 +86,13 @@ namespace storm { template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager); + CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit) { + CompressedState result(varInfo.getTotalBitOffset(roundTo64Bit)); + assert(varInfo.hasOutOfBoundsBit()); + result.set(varInfo.getOutOfBoundsBit()); + return result; + } + #ifdef STORM_HAVE_CARL template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); template void unpackStateIntoEvaluator(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionEvaluator& evaluator); diff --git a/src/storm/generator/CompressedState.h b/src/storm/generator/CompressedState.h index 3cbac6e79..9a12d69c3 100644 --- a/src/storm/generator/CompressedState.h +++ b/src/storm/generator/CompressedState.h @@ -37,8 +37,27 @@ namespace storm { */ storm::expressions::SimpleValuation unpackStateIntoValuation(CompressedState const& state, VariableInformation const& variableInformation, storm::expressions::ExpressionManager const& manager); + /*! + * + * @param variableInformation + * @return + */ storm::storage::BitVector computeObservabilityMask(VariableInformation const& variableInformation); + /*! + * + * @param state + * @param observabilityMap + * @param mask + * @return + */ uint32_t unpackStateToObservabilityClass(CompressedState const& state, std::unordered_map& observabilityMap, storm::storage::BitVector const& mask); + /*! + * + * @param varInfo + * @param roundTo64Bit + * @return + */ + CompressedState createOutOfBoundsState(VariableInformation const& varInfo, bool roundTo64Bit = true); } } diff --git a/src/storm/generator/JaniNextStateGenerator.cpp b/src/storm/generator/JaniNextStateGenerator.cpp index 7024cfde3..eeae4b4ad 100644 --- a/src/storm/generator/JaniNextStateGenerator.cpp +++ b/src/storm/generator/JaniNextStateGenerator.cpp @@ -3,7 +3,6 @@ #include "storm/models/sparse/StateLabeling.h" #include "storm/storage/expressions/SimpleValuation.h" - #include "storm/solver/SmtSolver.h" #include "storm/storage/jani/Edge.h" @@ -14,6 +13,9 @@ #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/CompositionInformationVisitor.h" +#include "storm/storage/jani/traverser/AssignmentLevelFinder.h" +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" +#include "storm/storage/jani/traverser/AssignmentsFinder.h" #include "storm/storage/sparse/JaniChoiceOrigins.h" @@ -26,67 +28,59 @@ #include "storm/exceptions/InvalidSettingsException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace generator { template - JaniNextStateGenerator::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options) : JaniNextStateGenerator(model.substituteConstants(), options, false) { + JaniNextStateGenerator::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options) : JaniNextStateGenerator(model.substituteConstantsFunctions(), options, false) { // Intentionally left empty. } template - JaniNextStateGenerator::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool) : NextStateGenerator(model.getExpressionManager(), options), model(model), rewardVariables(), hasStateActionRewards(false) { - STORM_LOG_THROW(!model.hasNonGlobalTransientVariable(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support automata-local transient variables."); - STORM_LOG_THROW(!model.usesAssignmentLevels(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support assignment levels."); + JaniNextStateGenerator::JaniNextStateGenerator(storm::jani::Model const& model, NextStateGeneratorOptions const& options, bool) : NextStateGenerator(model.getExpressionManager(), options), model(model), rewardExpressions(), hasStateActionRewards(false) { STORM_LOG_THROW(!this->options.isBuildChoiceLabelsSet(), storm::exceptions::InvalidSettingsException, "JANI next-state generator cannot generate choice labels."); - // 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 (this->model.hasTransientEdgeDestinationAssignments()) { - this->model.liftTransientEdgeDestinationAssignments(); + auto features = model.getModelFeatures(); + features.remove(storm::jani::ModelFeature::DerivedOperators); + features.remove(storm::jani::ModelFeature::StateExitRewards); + // Eliminate arrays if necessary. + if (features.hasArrays()) { + arrayEliminatorData = this->model.eliminateArrays(true); + this->options.substituteExpressions([this](storm::expressions::Expression const& exp) {return arrayEliminatorData.transformExpression(exp);}); + features.remove(storm::jani::ModelFeature::Arrays); + } + 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()) { + this->model.pushEdgeAssignmentsToDestinations(); + } else { + this->model.liftTransientEdgeDestinationAssignments(storm::jani::AssignmentLevelFinder().getLowestAssignmentLevel(this->model)); } - STORM_LOG_THROW(!this->model.hasTransientEdgeDestinationAssignments(), storm::exceptions::InvalidSettingsException, "The explicit next-state generator currently does not support transient edge destination assignments."); // Create all synchronization-related information, e.g. the automata that are put in parallel. this->createSynchronizationInformation(); // Now we are ready to initialize the variable information. this->checkValid(); - this->variableInformation = VariableInformation(model, this->parallelAutomata); + this->variableInformation = VariableInformation(this->model, this->parallelAutomata, options.getReservedBitsForUnboundedVariables(), options.isAddOutOfBoundsStateSet()); + this->variableInformation.registerArrayVariableReplacements(arrayEliminatorData); + this->transientVariableInformation = TransientVariableInformation(this->model, this->parallelAutomata); + this->transientVariableInformation.registerArrayVariableReplacements(arrayEliminatorData); // Create a proper evalator. this->evaluator = std::make_unique>(model.getManager()); + this->transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator); if (this->options.isBuildAllRewardModelsSet()) { - for (auto const& variable : model.getGlobalVariables()) { - if (variable.isTransient()) { - rewardVariables.push_back(variable.getExpressionVariable()); - } - } + rewardExpressions = model.getAllRewardModelExpressions(); } else { - // Extract the reward models from the program based on the names we were given. - auto const& globalVariables = model.getGlobalVariables(); + // Extract the reward models from the model based on the names we were given. for (auto const& rewardModelName : this->options.getRewardModelNames()) { - if (globalVariables.hasVariable(rewardModelName)) { - rewardVariables.push_back(globalVariables.getVariable(rewardModelName).getExpressionVariable()); - } else { - STORM_LOG_THROW(rewardModelName.empty(), storm::exceptions::InvalidArgumentException, "Cannot build unknown reward model '" << rewardModelName << "'."); - STORM_LOG_THROW(globalVariables.getNumberOfRealTransientVariables() + globalVariables.getNumberOfUnboundedIntegerTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); - } - } - - // If no reward model was yet added, but there was one that was given in the options, we try to build the - // standard reward model. - if (rewardVariables.empty() && !this->options.getRewardModelNames().empty()) { - bool foundTransientVariable = false; - for (auto const& transientVariable : globalVariables.getTransientVariables()) { - if (transientVariable.isUnboundedIntegerVariable() || transientVariable.isRealVariable()) { - rewardVariables.push_back(transientVariable.getExpressionVariable()); - foundTransientVariable = true; - break; - } - } - STORM_LOG_ASSERT(foundTransientVariable, "Expected to find a fitting transient variable."); + rewardExpressions.emplace_back(rewardModelName, model.getRewardModelExpression(rewardModelName)); } } @@ -176,103 +170,255 @@ namespace storm { template std::vector JaniNextStateGenerator::getInitialStates(StateToIdCallback const& stateToIdCallback) { - // Prepare an SMT solver to enumerate all initial states. - storm::utility::solver::SmtSolverFactory factory; - std::unique_ptr solver = factory.create(model.getExpressionManager()); - - std::vector rangeExpressions = model.getAllRangeExpressions(this->parallelAutomata); - for (auto const& expression : rangeExpressions) { - solver->add(expression); - } - solver->add(model.getInitialStatesExpression(this->parallelAutomata)); - - // Proceed as long as the solver can still enumerate initial states. std::vector initialStateIndices; - while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) { - // Create fresh state. - CompressedState initialState(this->variableInformation.getTotalBitOffset()); + + if (this->model.hasNonTrivialInitialStates()) { + // Prepare an SMT solver to enumerate all initial states. + storm::utility::solver::SmtSolverFactory factory; + std::unique_ptr solver = factory.create(model.getExpressionManager()); - // Read variable assignment from the solution of the solver. Also, create an expression we can use to - // prevent the variable assignment from being enumerated again. - storm::expressions::Expression blockingExpression; - std::shared_ptr model = solver->getModel(); - for (auto const& booleanVariable : this->variableInformation.booleanVariables) { - bool variableValue = model->getBooleanValue(booleanVariable.variable); - storm::expressions::Expression localBlockingExpression = variableValue ? !booleanVariable.variable : booleanVariable.variable; - blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; - initialState.set(booleanVariable.bitOffset, variableValue); - } - for (auto const& integerVariable : this->variableInformation.integerVariables) { - int_fast64_t variableValue = model->getIntegerValue(integerVariable.variable); - storm::expressions::Expression localBlockingExpression = integerVariable.variable != model->getManager().integer(variableValue); - blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; - initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast(variableValue - integerVariable.lowerBound)); + std::vector rangeExpressions = model.getAllRangeExpressions(this->parallelAutomata); + for (auto const& expression : rangeExpressions) { + solver->add(expression); + } + solver->add(model.getInitialStatesExpression(this->parallelAutomata)); + + // Proceed as long as the solver can still enumerate initial states. + while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) { + // Create fresh state. + CompressedState initialState(this->variableInformation.getTotalBitOffset(true)); + + // Read variable assignment from the solution of the solver. Also, create an expression we can use to + // prevent the variable assignment from being enumerated again. + storm::expressions::Expression blockingExpression; + std::shared_ptr model = solver->getModel(); + for (auto const& booleanVariable : this->variableInformation.booleanVariables) { + bool variableValue = model->getBooleanValue(booleanVariable.variable); + storm::expressions::Expression localBlockingExpression = variableValue ? !booleanVariable.variable : booleanVariable.variable; + blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; + initialState.set(booleanVariable.bitOffset, variableValue); + } + for (auto const& integerVariable : this->variableInformation.integerVariables) { + int_fast64_t variableValue = model->getIntegerValue(integerVariable.variable); + if (integerVariable.forceOutOfBoundsCheck || this->getOptions().isExplorationChecksSet()) { + STORM_LOG_THROW(variableValue >= integerVariable.lowerBound, storm::exceptions::WrongFormatException, "The initial value for variable " << integerVariable.variable.getName() << " is lower than the lower bound."); + STORM_LOG_THROW(variableValue <= integerVariable.upperBound, storm::exceptions::WrongFormatException, "The initial value for variable " << integerVariable.variable.getName() << " is higher than the upper bound"); + } + storm::expressions::Expression localBlockingExpression = integerVariable.variable != model->getManager().integer(variableValue); + blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; + initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast(variableValue - integerVariable.lowerBound)); + } + + // Gather iterators to the initial locations of all the automata. + std::vector::const_iterator> initialLocationsIts; + std::vector::const_iterator> initialLocationsItes; + for (auto const& automatonRef : this->parallelAutomata) { + auto const& automaton = automatonRef.get(); + initialLocationsIts.push_back(automaton.getInitialLocationIndices().cbegin()); + initialLocationsItes.push_back(automaton.getInitialLocationIndices().cend()); + } + storm::utility::combinatorics::forEach(initialLocationsIts, initialLocationsItes, [this,&initialState] (uint64_t index, uint64_t value) { setLocation(initialState, this->variableInformation.locationVariables[index], value); }, [&stateToIdCallback,&initialStateIndices,&initialState] () { + // Register initial state. + StateType id = stateToIdCallback(initialState); + initialStateIndices.push_back(id); + return true; + }); + + // Block the current initial state to search for the next one. + if (!blockingExpression.isInitialized()) { + break; + } + solver->add(blockingExpression); } - // Gather iterators to the initial locations of all the automata. - std::vector::const_iterator> initialLocationsIts; - std::vector::const_iterator> initialLocationsItes; - for (auto const& automatonRef : this->parallelAutomata) { - auto const& automaton = automatonRef.get(); - initialLocationsIts.push_back(automaton.getInitialLocationIndices().cbegin()); - initialLocationsItes.push_back(automaton.getInitialLocationIndices().cend()); - } - storm::utility::combinatorics::forEach(initialLocationsIts, initialLocationsItes, [this,&initialState] (uint64_t index, uint64_t value) { setLocation(initialState, this->variableInformation.locationVariables[index], value); }, [&stateToIdCallback,&initialStateIndices,&initialState] () { - // Register initial state. - StateType id = stateToIdCallback(initialState); - initialStateIndices.push_back(id); - return true; - }); + STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using SMT solving."); + } else { + CompressedState initialState(this->variableInformation.getTotalBitOffset(true)); - // Block the current initial state to search for the next one. - if (!blockingExpression.isInitialized()) { - break; + std::vector currentIntegerValues; + currentIntegerValues.reserve(this->variableInformation.integerVariables.size()); + for (auto const& variable : this->variableInformation.integerVariables) { + STORM_LOG_THROW(variable.lowerBound <= variable.upperBound, storm::exceptions::InvalidArgumentException, "Expecting variable with non-empty set of possible values."); + currentIntegerValues.emplace_back(0); + initialState.setFromInt(variable.bitOffset, variable.bitWidth, 0); } - solver->add(blockingExpression); + + initialStateIndices.emplace_back(stateToIdCallback(initialState)); + + bool done = false; + while (!done) { + bool changedBooleanVariable = false; + for (auto const& booleanVariable : this->variableInformation.booleanVariables) { + if (initialState.get(booleanVariable.bitOffset)) { + initialState.set(booleanVariable.bitOffset); + changedBooleanVariable = true; + break; + } else { + initialState.set(booleanVariable.bitOffset, false); + } + } + + bool changedIntegerVariable = false; + if (changedBooleanVariable) { + initialStateIndices.emplace_back(stateToIdCallback(initialState)); + } else { + for (uint64_t integerVariableIndex = 0; integerVariableIndex < this->variableInformation.integerVariables.size(); ++integerVariableIndex) { + auto const& integerVariable = this->variableInformation.integerVariables[integerVariableIndex]; + if (currentIntegerValues[integerVariableIndex] < integerVariable.upperBound - integerVariable.lowerBound) { + ++currentIntegerValues[integerVariableIndex]; + changedIntegerVariable = true; + } else { + currentIntegerValues[integerVariableIndex] = integerVariable.lowerBound; + } + initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, currentIntegerValues[integerVariableIndex]); + + if (changedIntegerVariable) { + break; + } + } + } + + if (changedIntegerVariable) { + initialStateIndices.emplace_back(stateToIdCallback(initialState)); + } + + done = !changedBooleanVariable && !changedIntegerVariable; + } + + STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using brute force enumeration."); } return initialStateIndices; } template - CompressedState JaniNextStateGenerator::applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable) { - CompressedState newState(state); + void JaniNextStateGenerator::applyUpdate(CompressedState& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable, int64_t assignmentLevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator) { // Update the location of the state. - setLocation(newState, locationVariable, destination.getLocationIndex()); + setLocation(state, locationVariable, destination.getLocationIndex()); // Then perform the assignments. - auto assignmentIt = destination.getOrderedAssignments().getNonTransientAssignments().begin(); - auto assignmentIte = destination.getOrderedAssignments().getNonTransientAssignments().end(); + auto const& assignments = destination.getOrderedAssignments().getNonTransientAssignments(assignmentLevel); + auto assignmentIt = assignments.begin(); + auto assignmentIte = assignments.end(); // Iterate over all boolean assignments and carry them out. auto boolIt = this->variableInformation.booleanVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasBooleanType(); ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsVariable() && assignmentIt->getExpressionVariable().hasBooleanType(); ++assignmentIt) { while (assignmentIt->getExpressionVariable() != boolIt->variable) { ++boolIt; } - newState.set(boolIt->bitOffset, this->evaluator->asBool(assignmentIt->getAssignedExpression())); + state.set(boolIt->bitOffset, expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); } // Iterate over all integer assignments and carry them out. auto integerIt = this->variableInformation.integerVariables.begin(); - for (; assignmentIt != assignmentIte && assignmentIt->getAssignedExpression().hasIntegerType(); ++assignmentIt) { + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsVariable() && assignmentIt->getExpressionVariable().hasIntegerType(); ++assignmentIt) { while (assignmentIt->getExpressionVariable() != integerIt->variable) { ++integerIt; } - int_fast64_t assignedValue = this->evaluator->asInt(assignmentIt->getAssignedExpression()); - if (this->options.isExplorationChecksSet()) { + int_fast64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); + if (this->options.isAddOutOfBoundsStateSet()) { + if (assignedValue < integerIt->lowerBound || assignedValue > integerIt->upperBound) { + state = this->outOfBoundsState; + } + } else if (integerIt->forceOutOfBoundsCheck || this->options.isExplorationChecksSet()) { STORM_LOG_THROW(assignedValue >= integerIt->lowerBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); } - newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound); - STORM_LOG_ASSERT(static_cast(newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << newState.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); + state.setFromInt(integerIt->bitOffset, integerIt->bitWidth, assignedValue - integerIt->lowerBound); + STORM_LOG_ASSERT(static_cast(state.getAsInt(integerIt->bitOffset, integerIt->bitWidth)) + integerIt->lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << state.getAsInt(integerIt->bitOffset, integerIt->bitWidth) << " but wrote " << assignedValue << ")."); + } + // Iterate over all array access assignments and carry them out. + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsArrayAccess(); ++assignmentIt) { + int_fast64_t arrayIndex = expressionEvaluator.asInt(assignmentIt->getLValue().getArrayIndex()); + if (assignmentIt->getAssignedExpression().hasIntegerType()) { + IntegerVariableInformation const& intInfo = this->variableInformation.getIntegerArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); + int_fast64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); + + if (this->options.isAddOutOfBoundsStateSet()) { + if (assignedValue < intInfo.lowerBound || assignedValue > intInfo.upperBound) { + state = this->outOfBoundsState; + } + } else if (this->options.isExplorationChecksSet()) { + STORM_LOG_THROW(assignedValue >= intInfo.lowerBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getLValue() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + STORM_LOG_THROW(assignedValue <= intInfo.upperBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getLValue() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + } + state.setFromInt(intInfo.bitOffset, intInfo.bitWidth, assignedValue - intInfo.lowerBound); + STORM_LOG_ASSERT(static_cast(state.getAsInt(intInfo.bitOffset, intInfo.bitWidth)) + intInfo.lowerBound == assignedValue, "Writing to the bit vector bucket failed (read " << state.getAsInt(intInfo.bitOffset, intInfo.bitWidth) << " but wrote " << assignedValue << ")."); + } else if (assignmentIt->getAssignedExpression().hasBooleanType()) { + BooleanVariableInformation const& boolInfo = this->variableInformation.getBooleanArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); + state.set(boolInfo.bitOffset, expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); + } else { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable."); + } } // Check that we processed all assignments. STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); + } + + template + void JaniNextStateGenerator::applyTransientUpdate(TransientVariableValuation& transientValuation, storm::jani::detail::ConstAssignments const& transientAssignments, storm::expressions::ExpressionEvaluator const& expressionEvaluator) { - return newState; + auto assignmentIt = transientAssignments.begin(); + auto assignmentIte = transientAssignments.end(); + + // Iterate over all boolean assignments and carry them out. + auto boolIt = this->transientVariableInformation.booleanVariableInformation.begin(); + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsVariable() && assignmentIt->getExpressionVariable().hasBooleanType(); ++assignmentIt) { + while (assignmentIt->getExpressionVariable() != boolIt->variable) { + ++boolIt; + } + transientValuation.booleanValues.emplace_back(&(*boolIt), expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); + } + // Iterate over all integer assignments and carry them out. + auto integerIt = this->transientVariableInformation.integerVariableInformation.begin(); + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsVariable() && assignmentIt->getExpressionVariable().hasIntegerType(); ++assignmentIt) { + while (assignmentIt->getExpressionVariable() != integerIt->variable) { + ++integerIt; + } + int64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); + if (this->options.isExplorationChecksSet()) { + STORM_LOG_THROW(assignedValue >= integerIt->lowerBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getExpressionVariable().getName() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + } + transientValuation.integerValues.emplace_back(&(*integerIt), assignedValue); + } + // Iterate over all rational assignments and carry them out. + auto rationalIt = this->transientVariableInformation.rationalVariableInformation.begin(); + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsVariable() && assignmentIt->getExpressionVariable().hasRationalType(); ++assignmentIt) { + while (assignmentIt->getExpressionVariable() != rationalIt->variable) { + ++rationalIt; + } + transientValuation.rationalValues.emplace_back(&(*rationalIt), expressionEvaluator.asRational(assignmentIt->getAssignedExpression())); + } + + // Iterate over all array access assignments and carry them out. + for (; assignmentIt != assignmentIte && assignmentIt->lValueIsArrayAccess(); ++assignmentIt) { + int_fast64_t arrayIndex = expressionEvaluator.asInt(assignmentIt->getLValue().getArrayIndex()); + storm::expressions::Type const& baseType = assignmentIt->getLValue().getArray().getExpressionVariable().getType(); + if (baseType.isIntegerType()) { + auto const& intInfo = this->transientVariableInformation.getIntegerArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); + int64_t assignedValue = expressionEvaluator.asInt(assignmentIt->getAssignedExpression()); + if (this->options.isExplorationChecksSet()) { + STORM_LOG_THROW(assignedValue >= intInfo.lowerBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getLValue() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + STORM_LOG_THROW(assignedValue <= intInfo.upperBound, storm::exceptions::WrongFormatException, "The update " << assignmentIt->getLValue() << " := " << assignmentIt->getAssignedExpression() << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getExpressionVariable().getName() << "'."); + } + transientValuation.integerValues.emplace_back(&intInfo, assignedValue); + } else if (baseType.isBooleanType()) { + auto const& boolInfo = this->transientVariableInformation.getBooleanArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); + transientValuation.booleanValues.emplace_back(&boolInfo, expressionEvaluator.asBool(assignmentIt->getAssignedExpression())); + } else if (baseType.isRationalType()) { + auto const& rationalInfo = this->transientVariableInformation.getRationalArrayVariableReplacement(assignmentIt->getLValue().getArray().getExpressionVariable(), arrayIndex); + transientValuation.rationalValues.emplace_back(&rationalInfo, expressionEvaluator.asRational(assignmentIt->getAssignedExpression())); + } else { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Unhandled type of base variable."); + } + } + + // Check that we processed all assignments. + STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); } template @@ -285,17 +431,20 @@ namespace storm { // First, construct the state rewards, as we may return early if there are no choices later and we already // need the state rewards then. - std::vector stateRewards(this->rewardVariables.size(), storm::utility::zero()); uint64_t automatonIndex = 0; + TransientVariableValuation transientVariableValuation; for (auto const& automatonRef : this->parallelAutomata) { auto const& automaton = automatonRef.get(); uint64_t currentLocationIndex = locations[automatonIndex]; storm::jani::Location const& location = automaton.getLocation(currentLocationIndex); - auto valueIt = stateRewards.begin(); - performTransientAssignments(location.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); + STORM_LOG_ASSERT(!location.getAssignments().hasMultipleLevels(true), "Indexed assignments at locations are not supported in the jani standard."); + applyTransientUpdate(transientVariableValuation, location.getAssignments().getTransientAssignments(), *this->evaluator); ++automatonIndex; } - result.addStateRewards(std::move(stateRewards)); + transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet()); + result.addStateRewards(evaluateRewardExpressions()); + this->transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator); + // If a terminal expression was set and we must not expand this state, return now. if (!this->terminalStates.empty()) { @@ -320,6 +469,10 @@ namespace storm { // If the model is a deterministic model, we need to fuse the choices into one. if (this->isDeterministicModel() && totalNumberOfChoices > 1) { Choice globalChoice; + + if (this->options.isAddOverlappingGuardLabelSet()) { + this->overlappingGuardStates->push_back(stateToIdCallback(*this->state)); + } // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs // this is equal to the number of choices, which is why we initialize it like this here. @@ -340,9 +493,9 @@ namespace storm { } } - std::vector stateActionRewards(rewardVariables.size(), storm::utility::zero()); + std::vector stateActionRewards(rewardExpressions.size(), storm::utility::zero()); for (auto const& choice : allChoices) { - for (uint_fast64_t rewardVariableIndex = 0; rewardVariableIndex < rewardVariables.size(); ++rewardVariableIndex) { + for (uint_fast64_t rewardVariableIndex = 0; rewardVariableIndex < rewardExpressions.size(); ++rewardVariableIndex) { stateActionRewards[rewardVariableIndex] += choice.getRewards()[rewardVariableIndex] * choice.getTotalMass() / totalExitRate; } @@ -377,17 +530,67 @@ namespace storm { Choice choice(edge.getActionIndex(), static_cast(exitRate)); + // Perform the transient edge assignments and create the state action rewards + TransientVariableValuation transientVariableValuation; + if (!edge.getAssignments().empty()) { + 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 stateActionRewards = evaluateRewardExpressions(); + if (!edge.getAssignments().empty()) { + transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator); + } + // Iterate over all updates of the current command. ValueType probabilitySum = storm::utility::zero(); for (auto const& destination : edge.getDestinations()) { ValueType probability = this->evaluator->asRational(destination.getProbability()); if (probability != storm::utility::zero()) { + bool evaluatorChanged = false; // Obtain target state index and add it to the list of known states. If it has not yet been // seen, we also add it to the set of states that have yet to be explored. - auto newState = applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex]); + int64_t assignmentLevel = edge.getLowestAssignmentLevel(); // Might be the largest possible integer, if there is no assignment + int64_t const& highestLevel = edge.getHighestAssignmentLevel(); + bool hasTransientAssignments = destination.hasTransientAssignment(); + CompressedState newState = state; + applyUpdate(newState, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, *this->evaluator); + if (hasTransientAssignments) { + STORM_LOG_ASSERT(this->options.isScaleAndLiftTransitionRewardsSet(), "Transition rewards are not supported and scaling to action rewards is disabled."); + transientVariableValuation.clear(); + applyTransientUpdate(transientVariableValuation, destination.getOrderedAssignments().getTransientAssignments(assignmentLevel), *this->evaluator); + transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet()); + evaluatorChanged = true; + } + if (assignmentLevel < highestLevel) { + while (assignmentLevel < highestLevel) { + ++assignmentLevel; + unpackStateIntoEvaluator(newState, this->variableInformation, *this->evaluator); + evaluatorChanged = true; + applyUpdate(newState, destination, this->variableInformation.locationVariables[automatonIndex], assignmentLevel, *this->evaluator); + if (hasTransientAssignments) { + transientVariableValuation.clear(); + applyTransientUpdate(transientVariableValuation, destination.getOrderedAssignments().getTransientAssignments(assignmentLevel), *this->evaluator); + transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet()); + evaluatorChanged = true; + } + } + } + + addEvaluatedRewardExpressions(stateActionRewards, probability); + + if (evaluatorChanged) { + // Restore the old variable valuation + unpackStateIntoEvaluator(state, this->variableInformation, *this->evaluator); + if (hasTransientAssignments) { + this->transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator); + } + } - StateType stateIndex = stateToIdCallback(applyUpdate(state, destination, this->variableInformation.locationVariables[automatonIndex])); + StateType stateIndex = stateToIdCallback(newState); // Update the choice by adding the probability/target state to it. probability = exitRate ? exitRate.get() * probability : probability; @@ -399,8 +602,8 @@ namespace storm { } } - // Create the state-action reward for the newly created choice. - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&choice] (ValueType const& value) { choice.addReward(value); } ); + // Add the state action rewards + choice.addRewards(std::move(stateActionRewards)); if (this->options.isExplorationChecksSet()) { // Check that the resulting distribution is in fact a distribution. @@ -410,6 +613,112 @@ namespace storm { return choice; } + template + void JaniNextStateGenerator::generateSynchronizedDistribution(storm::storage::BitVector const& state, AutomataEdgeSets const& edgeCombination, std::vector const& iteratorList, storm::builder::jit::Distribution& distribution, std::vector& stateActionRewards, EdgeIndexSet& edgeIndices, StateToIdCallback stateToIdCallback) { + + // Collect some information of the edges. + int64_t lowestDestinationAssignmentLevel = std::numeric_limits::max(); + int64_t highestDestinationAssignmentLevel = std::numeric_limits::min(); + int64_t lowestEdgeAssignmentLevel = std::numeric_limits::max(); + int64_t highestEdgeAssignmentLevel = std::numeric_limits::min(); + uint64_t numDestinations = 1; + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + if (this->getOptions().isBuildChoiceOriginsSet()) { + edgeIndices.insert(model.encodeAutomatonAndEdgeIndices(edgeCombination[i].first, iteratorList[i]->first)); + } + storm::jani::Edge const& edge = *iteratorList[i]->second; + lowestDestinationAssignmentLevel = std::min(lowestDestinationAssignmentLevel, edge.getLowestAssignmentLevel()); + highestDestinationAssignmentLevel = std::max(highestDestinationAssignmentLevel, edge.getHighestAssignmentLevel()); + if (!edge.getAssignments().empty()) { + lowestEdgeAssignmentLevel = std::min(lowestEdgeAssignmentLevel, edge.getAssignments().getLowestLevel(true)); + highestEdgeAssignmentLevel = std::max(highestEdgeAssignmentLevel, edge.getAssignments().getHighestLevel(true)); + } + numDestinations *= edge.getNumberOfDestinations(); + } + + // Perform the edge assignments (if there are any) + TransientVariableValuation transientVariableValuation; + if (lowestEdgeAssignmentLevel <= highestEdgeAssignmentLevel) { + for (int64_t assignmentLevel = lowestEdgeAssignmentLevel; assignmentLevel <= highestEdgeAssignmentLevel; ++assignmentLevel) { + transientVariableValuation.clear(); + for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { + storm::jani::Edge const& edge = *iteratorList[i]->second; + applyTransientUpdate(transientVariableValuation, edge.getAssignments().getTransientAssignments(assignmentLevel), *this->evaluator); + } + transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet()); + } + addEvaluatedRewardExpressions(stateActionRewards, storm::utility::one()); + transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator); + } + + std::vector destinations; + std::vector locationVars; + destinations.reserve(iteratorList.size()); + locationVars.reserve(iteratorList.size()); + + for (uint64_t destinationId = 0; destinationId < numDestinations; ++destinationId) { + // First assignment level + destinations.clear(); + locationVars.clear(); + transientVariableValuation.clear(); + CompressedState successorState = state; + ValueType successorProbability = storm::utility::one(); + + uint64_t destinationIndex = destinationId; + for (uint64_t i = 0; i < iteratorList.size(); ++i) { + storm::jani::Edge const& edge = *iteratorList[i]->second; + STORM_LOG_ASSERT(edge.getNumberOfDestinations() > 0, "Found an edge with zero destinations. This is not expected."); + uint64_t localDestinationIndex = destinationIndex % edge.getNumberOfDestinations(); + destinations.push_back(&edge.getDestination(localDestinationIndex)); + locationVars.push_back(&this->variableInformation.locationVariables[edgeCombination[i].first]); + destinationIndex /= edge.getNumberOfDestinations(); + ValueType probability = this->evaluator->asRational(destinations.back()->getProbability()); + if (edge.hasRate()) { + successorProbability *= probability * this->evaluator->asRational(edge.getRate()); + } else { + successorProbability *= probability; + } + if (storm::utility::isZero(successorProbability)) { + break; + } + + applyUpdate(successorState, *destinations.back(), *locationVars.back(), lowestDestinationAssignmentLevel, *this->evaluator); + applyTransientUpdate(transientVariableValuation, destinations.back()->getOrderedAssignments().getTransientAssignments(lowestDestinationAssignmentLevel), *this->evaluator); + } + + + if (!storm::utility::isZero(successorProbability)) { + bool evaluatorChanged = false; + // remaining assignment levels (if there are any) + for (int64_t assignmentLevel = lowestDestinationAssignmentLevel + 1; assignmentLevel <= highestDestinationAssignmentLevel; ++assignmentLevel) { + unpackStateIntoEvaluator(successorState, this->variableInformation, *this->evaluator); + transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet()); + transientVariableValuation.clear(); + evaluatorChanged = true; + auto locationVarIt = locationVars.begin(); + for (auto const& destPtr : destinations) { + applyUpdate(successorState, *destPtr, **locationVarIt, assignmentLevel, *this->evaluator); + applyTransientUpdate(transientVariableValuation, destinations.back()->getOrderedAssignments().getTransientAssignments(assignmentLevel), *this->evaluator); + ++locationVarIt; + } + } + if (!transientVariableValuation.empty()) { + evaluatorChanged = true; + transientVariableValuation.setInEvaluator(*this->evaluator, this->getOptions().isExplorationChecksSet()); + } + addEvaluatedRewardExpressions(stateActionRewards, successorProbability); + if (evaluatorChanged) { + // Restore the old state information + unpackStateIntoEvaluator(state, this->variableInformation, *this->evaluator); + this->transientVariableInformation.setDefaultValuesInEvaluator(*this->evaluator); + } + + StateType id = stateToIdCallback(successorState); + distribution.add(id, successorProbability); + } + } + } + template std::vector> JaniNextStateGenerator::expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback) { std::vector> result; @@ -426,54 +735,18 @@ namespace storm { iteratorList[i] = edgeCombination[i].second.cbegin(); } - storm::builder::jit::Distribution currentDistribution; - storm::builder::jit::Distribution nextDistribution; + storm::builder::jit::Distribution distribution; // As long as there is one feasible combination of commands, keep on expanding it. bool done = false; while (!done) { - std::vector stateActionRewards(rewardVariables.size(), storm::utility::zero()); - - currentDistribution.add(state, storm::utility::one()); - + distribution.clear(); + EdgeIndexSet edgeIndices; - for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { - auto const& indexAndEdge = *iteratorList[i]; - - if (this->getOptions().isBuildChoiceOriginsSet()) { - edgeIndices.insert(model.encodeAutomatonAndEdgeIndices(edgeCombination[i].first, indexAndEdge.first)); - } - - storm::jani::Edge const& edge = *indexAndEdge.second; - - for (auto const& destination : edge.getDestinations()) { - for (auto const& stateProbability : currentDistribution) { - // Compute the new state under the current update and add it to the set of new target states. - CompressedState newTargetState = applyUpdate(stateProbability.getState(), destination, this->variableInformation.locationVariables[edgeCombination[i].first]); - - // If the new state was already found as a successor state, update the probability - // and otherwise insert it. - ValueType probability = stateProbability.getValue() * this->evaluator->asRational(destination.getProbability()); - if (edge.hasRate()) { - probability *= this->evaluator->asRational(edge.getRate()); - } - if (probability != storm::utility::zero()) { - nextDistribution.add(newTargetState, probability); - } - } - - // Create the state-action reward for the newly created choice. - auto valueIt = stateActionRewards.begin(); - performTransientAssignments(edge.getAssignments().getTransientAssignments(), [&valueIt] (ValueType const& value) { *valueIt += value; ++valueIt; } ); - } - - nextDistribution.compress(); - - // If there is one more command to come, shift the target states one time step back. - if (i < iteratorList.size() - 1) { - currentDistribution = std::move(nextDistribution); - } - } + std::vector stateActionRewards(rewardExpressions.size(), storm::utility::zero()); + // old version without assignment levels generateSynchronizedDistribution(state, storm::utility::one(), 0, edgeCombination, iteratorList, distribution, stateActionRewards, edgeIndices, stateToIdCallback); + generateSynchronizedDistribution(state, edgeCombination, iteratorList, distribution, stateActionRewards, edgeIndices, stateToIdCallback); + distribution.compress(); // At this point, we applied all commands of the current command combination and newTargetStates // contains all target states and their respective probabilities. That means we are now ready to @@ -493,9 +766,8 @@ namespace storm { // Add the probabilities/rates to the newly created choice. ValueType probabilitySum = storm::utility::zero(); - for (auto const& stateProbability : nextDistribution) { - StateType actualIndex = stateToIdCallback(stateProbability.getState()); - choice.addProbability(actualIndex, stateProbability.getValue()); + for (auto const& stateProbability : distribution) { + choice.addProbability(stateProbability.getState(), stateProbability.getValue()); if (this->options.isExplorationChecksSet()) { probabilitySum += stateProbability.getValue(); @@ -504,7 +776,7 @@ namespace storm { if (this->options.isExplorationChecksSet()) { // Check that the resulting distribution is in fact a distribution. - STORM_LOG_THROW(!this->isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not sum to one for some command (actually sum to " << probabilitySum << ")."); + STORM_LOG_THROW(!this->isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not sum to one for some edge (actually sum to " << probabilitySum << ")."); } // Now, check whether there is one more command combination to consider. @@ -601,6 +873,8 @@ namespace storm { template void JaniNextStateGenerator::checkGlobalVariableWritesValid(AutomataEdgeSets const& enabledEdges) const { + // Todo: this also throws if the writes are on different assignment level + // Todo: this also throws if the writes are on different elements of the same array std::map writtenGlobalVariables; for (auto edgeSetIt = enabledEdges.begin(), edgeSetIte = enabledEdges.end(); edgeSetIt != edgeSetIte; ++edgeSetIt) { for (auto const& indexAndEdge : edgeSetIt->second) { @@ -620,7 +894,7 @@ namespace storm { template std::size_t JaniNextStateGenerator::getNumberOfRewardModels() const { - return rewardVariables.size(); + return rewardExpressions.size(); } template @@ -633,10 +907,15 @@ namespace storm { // As in JANI we can use transient boolean variable assignments in locations to identify states, we need to // create a list of boolean transient variables and the expressions that define them. std::unordered_map transientVariableToExpressionMap; + bool translateArrays = !this->arrayEliminatorData.replacements.empty(); for (auto const& variable : model.getGlobalVariables().getTransientVariables()) { if (variable.isBooleanVariable()) { if (this->options.isBuildAllLabelsSet() || this->options.getLabelNames().find(variable.getName()) != this->options.getLabelNames().end()) { - transientVariableToExpressionMap[variable.getExpressionVariable()] = model.getLabelExpression(variable.asBooleanVariable(), this->parallelAutomata); + storm::expressions::Expression labelExpression = model.getLabelExpression(variable.asBooleanVariable(), this->parallelAutomata); + if (translateArrays) { + labelExpression = this->arrayEliminatorData.transformExpression(labelExpression); + } + transientVariableToExpressionMap[variable.getExpressionVariable()] = std::move(labelExpression); } } } @@ -645,84 +924,67 @@ namespace storm { for (auto const& element : transientVariableToExpressionMap) { transientVariableExpressions.push_back(std::make_pair(element.first.getName(), element.second)); } - return NextStateGenerator::label(stateStorage, initialStateIndices, deadlockStateIndices, transientVariableExpressions); } template - void JaniNextStateGenerator::performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function const& callback) { - // If there are no reward variables, there is no need to iterate at all. - if (rewardVariables.empty()) { - return; + std::vector JaniNextStateGenerator::evaluateRewardExpressions() const { + std::vector result; + result.reserve(rewardExpressions.size()); + for (auto const& rewardExpression : rewardExpressions) { + result.push_back(this->evaluator->asRational(rewardExpression.second)); } - - // Otherwise, perform the callback for all selected reward variables. - auto rewardVariableIt = rewardVariables.begin(); - auto rewardVariableIte = rewardVariables.end(); - for (auto const& assignment : transientAssignments) { - while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { - callback(storm::utility::zero()); - ++rewardVariableIt; - } - if (rewardVariableIt == rewardVariableIte) { - break; - } else if (*rewardVariableIt == assignment.getExpressionVariable()) { - callback(ValueType(this->evaluator->asRational(assignment.getAssignedExpression()))); - ++rewardVariableIt; - } - } - // Add a value of zero for all variables that have no assignment. - for (; rewardVariableIt != rewardVariableIte; ++rewardVariableIt) { - callback(storm::utility::zero()); + return result; + } + + template + void JaniNextStateGenerator::addEvaluatedRewardExpressions(std::vector& rewards, ValueType const& factor) const { + assert(rewards.size() == rewardExpressions.size()); + auto rewIt = rewards.begin(); + for (auto const& rewardExpression : rewardExpressions) { + (*rewIt) += factor * this->evaluator->asRational(rewardExpression.second); + ++rewIt; } } template void JaniNextStateGenerator::buildRewardModelInformation() { - // Prepare all reward model information structs. - for (auto const& variable : rewardVariables) { - rewardModelInformation.emplace_back(variable.getName(), false, false, false); + // Prepare all reward model information structs and get a mapping from variables to rewardModels that use this variable + std::map> variableToRewardIndices; + for (uint64_t i = 0; i < rewardExpressions.size(); ++i) { + rewardModelInformation.emplace_back(rewardExpressions[i].first, false, false, false); + auto varsInExpression = rewardExpressions[i].second.getVariables(); + for (auto const& v : varsInExpression) { + auto mapIt = variableToRewardIndices.emplace(v, std::vector()).first; + mapIt->second.push_back(i); + } } - // Then fill them. - for (auto const& automatonRef : this->parallelAutomata) { - auto const& automaton = automatonRef.get(); - for (auto const& location : automaton.getLocations()) { - auto rewardVariableIt = rewardVariables.begin(); - auto rewardVariableIte = rewardVariables.end(); - - for (auto const& assignment : location.getAssignments().getTransientAssignments()) { - while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { - ++rewardVariableIt; - } - if (rewardVariableIt == rewardVariableIte) { - break; - } - if (*rewardVariableIt == assignment.getExpressionVariable()) { - rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateRewards(); - ++rewardVariableIt; - } + storm::jani::AssignmentsFinder finder; + for (auto const& varRewIndices : variableToRewardIndices) { + auto assignmentsFinderResult = finder.find(this->model, varRewIndices.first); + if (assignmentsFinderResult.hasLocationAssignment) { + for (auto const& rewModelIndex : varRewIndices.second) { + rewardModelInformation[rewModelIndex].setHasStateRewards(); } } - - for (auto const& edge : automaton.getEdges()) { - auto rewardVariableIt = rewardVariables.begin(); - auto rewardVariableIte = rewardVariables.end(); - - for (auto const& assignment : edge.getAssignments().getTransientAssignments()) { - while (rewardVariableIt != rewardVariableIte && *rewardVariableIt < assignment.getExpressionVariable()) { - ++rewardVariableIt; - } - if (rewardVariableIt == rewardVariableIte) { - break; - } - if (*rewardVariableIt == assignment.getExpressionVariable()) { - rewardModelInformation[std::distance(rewardVariables.begin(), rewardVariableIt)].setHasStateActionRewards(); - hasStateActionRewards = true; - ++rewardVariableIt; - } + if (assignmentsFinderResult.hasEdgeAssignment || (this->options.isScaleAndLiftTransitionRewardsSet() && assignmentsFinderResult.hasEdgeDestinationAssignment)) { + for (auto const& rewModelIndex : varRewIndices.second) { + rewardModelInformation[rewModelIndex].setHasStateActionRewards(); + hasStateActionRewards = true; } } + STORM_LOG_THROW(this->options.isScaleAndLiftTransitionRewardsSet() || !assignmentsFinderResult.hasEdgeDestinationAssignment, storm::exceptions::NotSupportedException, "Transition rewards are not supported and a reduction to action-based rewards was not possible."); + } + + // If the reward expression does not evaluate to zero, we set all reward types to true + for (uint64_t i = 0; i < rewardExpressions.size(); ++i) { + auto const& rewExpr = rewardExpressions[i].second; + if (rewExpr.containsVariables() || !storm::utility::isZero(this->evaluator->asRational(rewExpr))) { + rewardModelInformation[i].setHasStateRewards(); + rewardModelInformation[i].setHasStateActionRewards(); + hasStateActionRewards = true; + } } } diff --git a/src/storm/generator/JaniNextStateGenerator.h b/src/storm/generator/JaniNextStateGenerator.h index d2580da54..62241dde1 100644 --- a/src/storm/generator/JaniNextStateGenerator.h +++ b/src/storm/generator/JaniNextStateGenerator.h @@ -3,11 +3,20 @@ #include #include "storm/generator/NextStateGenerator.h" +#include "storm/generator/TransientVariableInformation.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/OrderedAssignments.h" namespace storm { + namespace builder { + namespace jit { + template + class Distribution; + } + } + namespace jani { class Edge; class EdgeDestination; @@ -65,11 +74,23 @@ namespace storm { * Applies an update to the state currently loaded into the evaluator and applies the resulting values to * the given compressed state. * @params state The state to which to apply the new values. - * @params update The update to apply. + * @params destination The update to apply. + * @params locationVariable The location variable that is being updated. + * @params assignmentLevel The assignmentLevel that is to be considered for the update. + * @return The resulting state. + */ + void applyUpdate(CompressedState& state, storm::jani::EdgeDestination const& destination, storm::generator::LocationVariableInformation const& locationVariable, int64_t assignmentlevel, storm::expressions::ExpressionEvaluator const& expressionEvaluator); + + /*! + * Applies an update to the state currently loaded into the evaluator and applies the resulting values to + * the given compressed state. + * @params state The state to which to apply the new values. + * @params destination The update to apply. * @params locationVariable The location variable that is being updated. + * @params assignmentLevel The assignmentLevel that is to be considered for the update. * @return The resulting state. */ - CompressedState applyUpdate(CompressedState const& state, storm::jani::EdgeDestination const& update, storm::generator::LocationVariableInformation const& locationVariable); + void applyTransientUpdate(TransientVariableValuation& transientValuation, storm::jani::detail::ConstAssignments const& transientAssignments, storm::expressions::ExpressionEvaluator const& expressionEvaluator); /*! * Retrieves all choices possible from the given state. @@ -94,17 +115,22 @@ namespace storm { typedef std::vector AutomataEdgeSets; std::vector> expandSynchronizingEdgeCombination(AutomataEdgeSets const& edgeCombination, uint64_t outputActionIndex, CompressedState const& state, StateToIdCallback stateToIdCallback); - + void generateSynchronizedDistribution(storm::storage::BitVector const& state, AutomataEdgeSets const& edgeCombination, std::vector const& iteratorList, storm::builder::jit::Distribution& distribution, std::vector& stateActionRewards, EdgeIndexSet& edgeIndices, StateToIdCallback stateToIdCallback); + /*! * Checks the list of enabled edges for multiple synchronized writes to the same global variable. */ void checkGlobalVariableWritesValid(AutomataEdgeSets const& enabledEdges) const; /*! - * Treats the given transient assignments by calling the callback function whenever a transient assignment - * to one of the reward variables of this generator is performed. + * Evaluates the reward expressions using the current evaluator + */ + std::vector evaluateRewardExpressions() const; + + /*! + * Evaluates the reward expressions using the current evaluator, multiplies them by the given factor and adds it to the given vector. */ - void performTransientAssignments(storm::jani::detail::ConstAssignments const& transientAssignments, std::function const& callback); + void addEvaluatedRewardExpressions(std::vector& rewards, ValueType const& factor) const; /*! * Builds the information structs for the reward models. @@ -130,14 +156,20 @@ namespace storm { /// The vector storing the edges that need to be explored (synchronously or asynchronously). std::vector edges; - /// The transient variables of reward models that need to be considered. - std::vector rewardVariables; + /// The names and defining expressions of reward models that need to be considered. + std::vector> rewardExpressions; /// A vector storing information about the corresponding reward models (variables). std::vector rewardModelInformation; /// A flag that stores whether at least one of the selected reward models has state-action rewards. bool hasStateActionRewards; + + /// Data from eliminated array expressions. These are required to keep references to array variables in LValues alive. + storm::jani::ArrayEliminatorData arrayEliminatorData; + + /// Information about the transient variables of the model. + TransientVariableInformation transientVariableInformation; }; } diff --git a/src/storm/generator/NextStateGenerator.cpp b/src/storm/generator/NextStateGenerator.cpp index e2add8f89..bbc89d7af 100644 --- a/src/storm/generator/NextStateGenerator.cpp +++ b/src/storm/generator/NextStateGenerator.cpp @@ -1,3 +1,5 @@ +#include +#include #include "storm/generator/NextStateGenerator.h" #include "storm/adapters/RationalFunctionAdapter.h" @@ -17,12 +19,22 @@ namespace storm { template NextStateGenerator::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(nullptr), state(nullptr) { - // Intentionally left empty. + if(variableInformation.hasOutOfBoundsBit()) { + outOfBoundsState = createOutOfBoundsState(variableInformation); + } + if (options.isAddOverlappingGuardLabelSet()) { + overlappingGuardStates = std::vector(); + } } template NextStateGenerator::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(), evaluator(nullptr), state(nullptr) { - // Intentionally left empty. + if(variableInformation.hasOutOfBoundsBit()) { + outOfBoundsState = createOutOfBoundsState(variableInformation); + } + if (options.isAddOverlappingGuardLabelSet()) { + overlappingGuardStates = std::vector(); + } } template @@ -55,11 +67,7 @@ namespace storm { template storm::models::sparse::StateLabeling NextStateGenerator::label(storm::storage::sparse::StateStorage const& stateStorage, std::vector const& initialStateIndices, std::vector const& deadlockStateIndices, std::vector> labelsAndExpressions) { - for (auto const& expression : this->options.getExpressionLabels()) { - std::stringstream stream; - stream << expression; - labelsAndExpressions.push_back(std::make_pair(stream.str(), expression)); - } + labelsAndExpressions.insert(labelsAndExpressions.end(), this->options.getExpressionLabels().begin(), this->options.getExpressionLabels().end()); // Make the labels unique. std::sort(labelsAndExpressions.begin(), labelsAndExpressions.end(), [] (std::pair const& a, std::pair const& b) { return a.first < b.first; } ); @@ -99,6 +107,20 @@ namespace storm { result.addLabelToState("deadlock", index); } } + + if (this->options.isAddOverlappingGuardLabelSet()) { + STORM_LOG_THROW(!result.containsLabel("overlap_guards"), storm::exceptions::WrongFormatException, "Label 'overlap_guards' is reserved when adding overlapping guard labels"); + result.addLabel("overlap_guards"); + for (auto index : overlappingGuardStates.get()) { + result.addLabelToState("overlap_guards", index); + } + } + + if (this->options.isAddOutOfBoundsStateSet() && stateStorage.stateToId.contains(outOfBoundsState)) { + STORM_LOG_THROW(!result.containsLabel("out_of_bounds"),storm::exceptions::WrongFormatException, "Label 'out_of_bounds' is reserved when adding out of bounds states."); + result.addLabel("out_of_bounds"); + result.addLabelToState("out_of_bounds", stateStorage.stateToId.getValue(outOfBoundsState)); + } return result; } @@ -165,6 +187,14 @@ namespace storm { return unpackStateToObservabilityClass(state, observabilityMap, mask); } + template + void NextStateGenerator::remapStateIds(std::function const& remapping) { + if (overlappingGuardStates != boost::none) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Remapping of Ids during model building is not supported for overlapping guard statements."); + } + // Nothing to be done. + } + template class NextStateGenerator; #ifdef STORM_HAVE_CARL diff --git a/src/storm/generator/NextStateGenerator.h b/src/storm/generator/NextStateGenerator.h index ce93a0c10..eb01c7aa4 100644 --- a/src/storm/generator/NextStateGenerator.h +++ b/src/storm/generator/NextStateGenerator.h @@ -70,6 +70,13 @@ namespace storm { NextStateGeneratorOptions const& getOptions() const; virtual std::shared_ptr generateChoiceOrigins(std::vector& dataForChoiceOrigins) const; + + /*! + * Performs a remapping of all values stored by applying the given remapping. + * + * @param remapping The remapping to apply. + */ + void remapStateIds(std::function const& remapping); protected: /*! @@ -106,6 +113,12 @@ namespace storm { /// The observability classes handed out so far. // TODO consider using a BitVectorHashMap for this? mutable std::unordered_map observabilityMap; + /// A state that encodes the outOfBoundsState + CompressedState outOfBoundsState; + + /// A map that stores the indices of states with overlapping guards. + boost::optional> overlappingGuardStates; + }; } } diff --git a/src/storm/generator/PrismNextStateGenerator.cpp b/src/storm/generator/PrismNextStateGenerator.cpp index 89617bd8b..627aa2d7f 100644 --- a/src/storm/generator/PrismNextStateGenerator.cpp +++ b/src/storm/generator/PrismNextStateGenerator.cpp @@ -22,7 +22,7 @@ namespace storm { namespace generator { template - PrismNextStateGenerator::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options) : PrismNextStateGenerator(program.substituteConstants(), options, false) { + PrismNextStateGenerator::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options) : PrismNextStateGenerator(program.substituteConstantsFormulas(), options, false) { // Intentionally left empty. } @@ -33,7 +33,7 @@ namespace storm { // Only after checking validity of the program, we initialize the variable information. this->checkValid(); - this->variableInformation = VariableInformation(program); + this->variableInformation = VariableInformation(program, options.isAddOutOfBoundsStateSet()); // Create a proper evalator. this->evaluator = std::make_unique>(program.getManager()); @@ -142,48 +142,108 @@ namespace storm { template std::vector PrismNextStateGenerator::getInitialStates(StateToIdCallback const& stateToIdCallback) { - // Prepare an SMT solver to enumerate all initial states. - storm::utility::solver::SmtSolverFactory factory; - std::unique_ptr solver = factory.create(program.getManager()); - - std::vector rangeExpressions = program.getAllRangeExpressions(); - for (auto const& expression : rangeExpressions) { - solver->add(expression); - } - solver->add(program.getInitialStatesExpression()); - - // Proceed ss long as the solver can still enumerate initial states. std::vector initialStateIndices; - while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) { - // Create fresh state. - CompressedState initialState(this->variableInformation.getTotalBitOffset()); - - // Read variable assignment from the solution of the solver. Also, create an expression we can use to - // prevent the variable assignment from being enumerated again. - storm::expressions::Expression blockingExpression; - std::shared_ptr model = solver->getModel(); - for (auto const& booleanVariable : this->variableInformation.booleanVariables) { - bool variableValue = model->getBooleanValue(booleanVariable.variable); - storm::expressions::Expression localBlockingExpression = variableValue ? !booleanVariable.variable : booleanVariable.variable; - blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; - initialState.set(booleanVariable.bitOffset, variableValue); + + // If all states are initial, we can simplify the enumeration substantially. + if (program.hasInitialConstruct() && program.getInitialConstruct().getInitialStatesExpression().isTrue()) { + CompressedState initialState(this->variableInformation.getTotalBitOffset(true)); + + std::vector currentIntegerValues; + currentIntegerValues.reserve(this->variableInformation.integerVariables.size()); + for (auto const& variable : this->variableInformation.integerVariables) { + STORM_LOG_THROW(variable.lowerBound <= variable.upperBound, storm::exceptions::InvalidArgumentException, "Expecting variable with non-empty set of possible values."); + currentIntegerValues.emplace_back(0); + initialState.setFromInt(variable.bitOffset, variable.bitWidth, 0); } - for (auto const& integerVariable : this->variableInformation.integerVariables) { - int_fast64_t variableValue = model->getIntegerValue(integerVariable.variable); - storm::expressions::Expression localBlockingExpression = integerVariable.variable != model->getManager().integer(variableValue); - blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; - initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast(variableValue - integerVariable.lowerBound)); + + initialStateIndices.emplace_back(stateToIdCallback(initialState)); + + bool done = false; + while (!done) { + bool changedBooleanVariable = false; + for (auto const& booleanVariable : this->variableInformation.booleanVariables) { + if (initialState.get(booleanVariable.bitOffset)) { + initialState.set(booleanVariable.bitOffset); + changedBooleanVariable = true; + break; + } else { + initialState.set(booleanVariable.bitOffset, false); + } + } + + bool changedIntegerVariable = false; + if (changedBooleanVariable) { + initialStateIndices.emplace_back(stateToIdCallback(initialState)); + } else { + for (uint64_t integerVariableIndex = 0; integerVariableIndex < this->variableInformation.integerVariables.size(); ++integerVariableIndex) { + auto const& integerVariable = this->variableInformation.integerVariables[integerVariableIndex]; + if (currentIntegerValues[integerVariableIndex] < integerVariable.upperBound - integerVariable.lowerBound) { + ++currentIntegerValues[integerVariableIndex]; + changedIntegerVariable = true; + } else { + currentIntegerValues[integerVariableIndex] = integerVariable.lowerBound; + } + initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, currentIntegerValues[integerVariableIndex]); + + if (changedIntegerVariable) { + break; + } + } + } + + if (changedIntegerVariable) { + initialStateIndices.emplace_back(stateToIdCallback(initialState)); + } + + done = !changedBooleanVariable && !changedIntegerVariable; } - // Register initial state and return it. - StateType id = stateToIdCallback(initialState); - initialStateIndices.push_back(id); + STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using brute force enumeration."); + } else { + // Prepare an SMT solver to enumerate all initial states. + storm::utility::solver::SmtSolverFactory factory; + std::unique_ptr solver = factory.create(program.getManager()); + + std::vector rangeExpressions = program.getAllRangeExpressions(); + for (auto const& expression : rangeExpressions) { + solver->add(expression); + } + solver->add(program.getInitialStatesExpression()); - // Block the current initial state to search for the next one. - if (!blockingExpression.isInitialized()) { - break; + // Proceed ss long as the solver can still enumerate initial states. + while (solver->check() == storm::solver::SmtSolver::CheckResult::Sat) { + // Create fresh state. + CompressedState initialState(this->variableInformation.getTotalBitOffset(true)); + + // Read variable assignment from the solution of the solver. Also, create an expression we can use to + // prevent the variable assignment from being enumerated again. + storm::expressions::Expression blockingExpression; + std::shared_ptr model = solver->getModel(); + for (auto const& booleanVariable : this->variableInformation.booleanVariables) { + bool variableValue = model->getBooleanValue(booleanVariable.variable); + storm::expressions::Expression localBlockingExpression = variableValue ? !booleanVariable.variable : booleanVariable.variable; + blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; + initialState.set(booleanVariable.bitOffset, variableValue); + } + for (auto const& integerVariable : this->variableInformation.integerVariables) { + int_fast64_t variableValue = model->getIntegerValue(integerVariable.variable); + storm::expressions::Expression localBlockingExpression = integerVariable.variable != model->getManager().integer(variableValue); + blockingExpression = blockingExpression.isInitialized() ? blockingExpression || localBlockingExpression : localBlockingExpression; + initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast(variableValue - integerVariable.lowerBound)); + } + + // Register initial state and return it. + StateType id = stateToIdCallback(initialState); + initialStateIndices.push_back(id); + + // Block the current initial state to search for the next one. + if (!blockingExpression.isInitialized()) { + break; + } + solver->add(blockingExpression); } - solver->add(blockingExpression); + + STORM_LOG_DEBUG("Enumerated " << initialStateIndices.size() << " initial states using SMT solving."); } return initialStateIndices; @@ -235,6 +295,10 @@ namespace storm { // If the model is a deterministic model, we need to fuse the choices into one. if (this->isDeterministicModel() && totalNumberOfChoices > 1) { Choice globalChoice; + + if (this->options.isAddOverlappingGuardLabelSet()) { + this->overlappingGuardStates->push_back(stateToIdCallback(*this->state)); + } // For CTMCs, we need to keep track of the total exit rate to scale the action rewards later. For DTMCs // this is equal to the number of choices, which is why we initialize it like this here. @@ -324,7 +388,11 @@ namespace storm { ++integerIt; } int_fast64_t assignedValue = this->evaluator->asInt(assignmentIt->getExpression()); - if (this->options.isExplorationChecksSet()) { + if (this->options.isAddOutOfBoundsStateSet()) { + if (assignedValue < integerIt->lowerBound || assignedValue > integerIt->upperBound) { + return this->outOfBoundsState; + } + } else if (integerIt->forceOutOfBoundsCheck || this->options.isExplorationChecksSet()) { STORM_LOG_THROW(assignedValue >= integerIt->lowerBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'."); STORM_LOG_THROW(assignedValue <= integerIt->upperBound, storm::exceptions::WrongFormatException, "The update " << update << " leads to an out-of-bounds value (" << assignedValue << ") for the variable '" << assignmentIt->getVariableName() << "'."); } @@ -452,67 +520,60 @@ namespace storm { return result; } - + + template + void PrismNextStateGenerator::generateSynchronizedDistribution(storm::storage::BitVector const& state, ValueType const& probability, uint64_t position, std::vector>::const_iterator> const& iteratorList, storm::builder::jit::Distribution& distribution, StateToIdCallback stateToIdCallback) { + + if (storm::utility::isZero(probability)) { + return; + } + + if (position >= iteratorList.size()) { + StateType id = stateToIdCallback(state); + distribution.add(id, probability); + } else { + storm::prism::Command const& command = *iteratorList[position]; + for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { + storm::prism::Update const& update = command.getUpdate(j); + generateSynchronizedDistribution(applyUpdate(state, update), probability * this->evaluator->asRational(update.getLikelihoodExpression()), position + 1, iteratorList, distribution, stateToIdCallback); + } + } + } + template std::vector> PrismNextStateGenerator::getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback) { std::vector> result; - storm::builder::jit::Distribution currentDistribution; - storm::builder::jit::Distribution nextDistribution; - for (uint_fast64_t actionIndex : program.getSynchronizingActionIndices()) { boost::optional>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(actionIndex); - + // Only process this action label, if there is at least one feasible solution. if (optionalActiveCommandLists) { std::vector>> const& activeCommandList = optionalActiveCommandLists.get(); std::vector>::const_iterator> iteratorList(activeCommandList.size()); - + // Initialize the list of iterators. for (size_t i = 0; i < activeCommandList.size(); ++i) { iteratorList[i] = activeCommandList[i].cbegin(); } - + + storm::builder::jit::Distribution distribution; + // As long as there is one feasible combination of commands, keep on expanding it. bool done = false; while (!done) { - currentDistribution.clear(); - nextDistribution.clear(); + distribution.clear(); + generateSynchronizedDistribution(state, storm::utility::one(), 0, iteratorList, distribution, stateToIdCallback); + distribution.compress(); - currentDistribution.add(state, storm::utility::one()); - - for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { - storm::prism::Command const& command = *iteratorList[i]; - for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { - storm::prism::Update const& update = command.getUpdate(j); - - for (auto const& stateProbability : currentDistribution) { - ValueType probability = stateProbability.getValue() * this->evaluator->asRational(update.getLikelihoodExpression()); - - if (!storm::utility::isZero(probability)) { - // Compute the new state under the current update and add it to the set of new target states. - CompressedState newTargetState = applyUpdate(stateProbability.getState(), update); - nextDistribution.add(newTargetState, probability); - } - } - } - - nextDistribution.compress(); - - // If there is one more command to come, shift the target states one time step back. - if (i < iteratorList.size() - 1) { - currentDistribution = std::move(nextDistribution); - } - } - // At this point, we applied all commands of the current command combination and newTargetStates // contains all target states and their respective probabilities. That means we are now ready to // add the choice to the list of transitions. result.push_back(Choice(actionIndex)); - + // Now create the actual distribution. Choice& choice = result.back(); - + // Remember the choice label and origins only if we were asked to. if (this->options.isBuildChoiceLabelsSet()) { choice.addLabel(program.getActionName(actionIndex)); @@ -524,22 +585,21 @@ namespace storm { } choice.addOriginData(boost::any(std::move(commandIndices))); } - + // Add the probabilities/rates to the newly created choice. ValueType probabilitySum = storm::utility::zero(); - for (auto const& stateProbability : nextDistribution) { - StateType actualIndex = stateToIdCallback(stateProbability.getState()); - choice.addProbability(actualIndex, stateProbability.getValue()); + for (auto const& stateProbability : distribution) { + choice.addProbability(stateProbability.getState(), stateProbability.getValue()); if (this->options.isExplorationChecksSet()) { probabilitySum += stateProbability.getValue(); } } - + if (this->options.isExplorationChecksSet()) { // Check that the resulting distribution is in fact a distribution. STORM_LOG_THROW(!program.isDiscreteTimeModel() || !this->comparator.isConstant(probabilitySum) || this->comparator.isOne(probabilitySum), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ")."); } - + // Create the state-action reward for the newly created choice. for (auto const& rewardModel : rewardModels) { ValueType stateActionRewardValue = storm::utility::zero(); @@ -552,7 +612,7 @@ namespace storm { } choice.addReward(stateActionRewardValue); } - + // Now, check whether there is one more command combination to consider. bool movedIterator = false; for (int_fast64_t j = iteratorList.size() - 1; !movedIterator && j >= 0; --j) { @@ -564,12 +624,12 @@ namespace storm { iteratorList[j] = activeCommandList[j].begin(); } } - + done = !movedIterator; } } } - + return result; } diff --git a/src/storm/generator/PrismNextStateGenerator.h b/src/storm/generator/PrismNextStateGenerator.h index 03b2676af..73f2fd247 100644 --- a/src/storm/generator/PrismNextStateGenerator.h +++ b/src/storm/generator/PrismNextStateGenerator.h @@ -8,6 +8,13 @@ #include "storm/storage/prism/Program.h" namespace storm { + namespace builder { + namespace jit { + template + class Distribution; + } + } + namespace generator { template @@ -86,6 +93,11 @@ namespace storm { */ std::vector> getLabeledChoices(CompressedState const& state, StateToIdCallback stateToIdCallback); + /*! + * A recursive helper function to generate a synchronziing distribution. + */ + void generateSynchronizedDistribution(storm::storage::BitVector const& state, ValueType const& probability, uint64_t position, std::vector>::const_iterator> const& iteratorList, storm::builder::jit::Distribution& distribution, StateToIdCallback stateToIdCallback); + // The program used for the generation of next states. storm::prism::Program program; diff --git a/src/storm/generator/TransientVariableInformation.cpp b/src/storm/generator/TransientVariableInformation.cpp new file mode 100644 index 000000000..461b43eb0 --- /dev/null +++ b/src/storm/generator/TransientVariableInformation.cpp @@ -0,0 +1,183 @@ +#include "storm/generator/TransientVariableInformation.h" + +#include "storm/storage/jani/Model.h" + +#include "storm/storage/jani/Automaton.h" +#include "storm/storage/jani/ArrayEliminator.h" +#include "storm/storage/jani/AutomatonComposition.h" +#include "storm/storage/jani/ParallelComposition.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/WrongFormatException.h" +#include "storm/exceptions/OutOfRangeException.h" + + +#include + +namespace storm { + namespace generator { + + template <> + TransientVariableData::TransientVariableData(storm::expressions::Variable const& variable, boost::optional const& lowerBound, boost::optional const& upperBound, storm::RationalFunction const& defaultValue, bool global) : variable(variable), lowerBound(lowerBound), upperBound(upperBound), defaultValue(defaultValue) { + // There is no '<=' for rational functions. Therefore, do not check the bounds for this ValueType + } + + template + TransientVariableData::TransientVariableData(storm::expressions::Variable const& variable, boost::optional const& lowerBound, boost::optional const& upperBound, VariableType const& defaultValue, bool global) : variable(variable), lowerBound(lowerBound), upperBound(upperBound), defaultValue(defaultValue) { + STORM_LOG_THROW(!lowerBound.is_initialized() || lowerBound.get() <= defaultValue, storm::exceptions::OutOfRangeException, "The default value for transient variable " << variable.getName() << " is smaller than its lower bound."); + STORM_LOG_THROW(!upperBound.is_initialized() || defaultValue <= upperBound.get(), storm::exceptions::OutOfRangeException, "The default value for transient variable " << variable.getName() << " is higher than its upper bound."); + } + + template + TransientVariableData::TransientVariableData(storm::expressions::Variable const& variable, VariableType const& defaultValue, bool global) : variable(variable), defaultValue(defaultValue) { + // Intentionally left empty. + } + + template + TransientVariableInformation::TransientVariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata) { + + createVariablesForVariableSet(model.getGlobalVariables(), true); + + for (auto const& automatonRef : parallelAutomata) { + createVariablesForAutomaton(automatonRef.get()); + } + + sortVariables(); + } + + template + void TransientVariableInformation::registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData) { + arrayVariableToElementInformations.clear(); + // Find for each replaced array variable the corresponding references in this variable information + for (auto const& arrayVariable : arrayEliminatorData.eliminatedArrayVariables) { + if (arrayVariable->isTransient()) { + STORM_LOG_ASSERT(arrayEliminatorData.replacements.count(arrayVariable->getExpressionVariable()) > 0, "No replacement for array variable."); + auto const& replacements = arrayEliminatorData.replacements.find(arrayVariable->getExpressionVariable())->second; + std::vector varInfoIndices; + for (auto const& replacedVar : replacements) { + if (replacedVar->getExpressionVariable().hasIntegerType()) { + uint64_t index = 0; + for (auto const& intInfo : integerVariableInformation) { + if (intInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); + } else if (replacedVar->getExpressionVariable().hasBooleanType()) { + uint64_t index = 0; + for (auto const& boolInfo : booleanVariableInformation) { + if (boolInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); + } else if (replacedVar->getExpressionVariable().hasRationalType()) { + uint64_t index = 0; + for (auto const& rationalInfo : rationalVariableInformation) { + if (rationalInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); + } else { + STORM_LOG_ASSERT(false, "Unhandled type of base variable."); + } + } + this->arrayVariableToElementInformations.emplace(arrayVariable->getExpressionVariable(), std::move(varInfoIndices)); + } + } + } + + template + TransientVariableData const& TransientVariableInformation::getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& indices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < indices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << indices.size() << "."); + return booleanVariableInformation[indices[arrayIndex]]; + } + + template + TransientVariableData const& TransientVariableInformation::getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& indices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < indices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << indices.size() << "."); + return integerVariableInformation[indices[arrayIndex]]; + } + + template + TransientVariableData const& TransientVariableInformation::getRationalArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& indices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < indices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << indices.size() << "."); + return rationalVariableInformation[indices[arrayIndex]]; + } + + template + void TransientVariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton) { + createVariablesForVariableSet(automaton.getVariables(), false); + } + + template + void TransientVariableInformation::createVariablesForVariableSet(storm::jani::VariableSet const& variableSet, bool global) { + for (auto const& variable : variableSet.getBooleanVariables()) { + if (variable.isTransient()) { + booleanVariableInformation.emplace_back(variable.getExpressionVariable(), variable.getInitExpression().evaluateAsBool(), global); + } + } + for (auto const& variable : variableSet.getBoundedIntegerVariables()) { + if (variable.isTransient()) { + boost::optional lowerBound; + boost::optional upperBound; + if (variable.hasLowerBound()) { + lowerBound = variable.getLowerBound().evaluateAsInt(); + } + if (variable.hasUpperBound()) { + upperBound = variable.getUpperBound().evaluateAsInt(); + } + integerVariableInformation.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, variable.getInitExpression().evaluateAsInt(), global); + } + } + for (auto const& variable : variableSet.getUnboundedIntegerVariables()) { + if (variable.isTransient()) { + integerVariableInformation.emplace_back(variable.getExpressionVariable(), variable.getInitExpression().evaluateAsInt(), global); + } + } + for (auto const& variable : variableSet.getRealVariables()) { + if (variable.isTransient()) { + rationalVariableInformation.emplace_back(variable.getExpressionVariable(), storm::utility::convertNumber(variable.getInitExpression().evaluateAsRational()), global); + } + } + } + + template + void TransientVariableInformation::sortVariables() { + // Sort the variables so we can make some assumptions when iterating over them (in the next-state generators). + std::sort(booleanVariableInformation.begin(), booleanVariableInformation.end(), [] (TransientVariableData const& a, TransientVariableData const& b) { return a.variable < b.variable; } ); + std::sort(integerVariableInformation.begin(), integerVariableInformation.end(), [] (TransientVariableData const& a, TransientVariableData const& b) { return a.variable < b.variable; } ); + std::sort(rationalVariableInformation.begin(), rationalVariableInformation.end(), [] (TransientVariableData const& a, TransientVariableData const& b) { return a.variable < b.variable; } ); + } + + template + void TransientVariableInformation::setDefaultValuesInEvaluator(storm::expressions::ExpressionEvaluator& evaluator) const { + for (auto const& variableData : booleanVariableInformation) { + evaluator.setBooleanValue(variableData.variable, variableData.defaultValue); + } + for (auto const& variableData : integerVariableInformation) { + evaluator.setIntegerValue(variableData.variable, variableData.defaultValue); + } + for (auto const& variableData : rationalVariableInformation) { + evaluator.setRationalValue(variableData.variable, variableData.defaultValue); + } + } + + template class TransientVariableInformation; + template class TransientVariableInformation; + template class TransientVariableInformation; + + } +} diff --git a/src/storm/generator/TransientVariableInformation.h b/src/storm/generator/TransientVariableInformation.h new file mode 100644 index 000000000..c6047f470 --- /dev/null +++ b/src/storm/generator/TransientVariableInformation.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +#include "storm/storage/expressions/Variable.h" +#include "storm/storage/expressions/Expression.h" +#include "storm/storage/expressions/ExpressionEvaluator.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/OutOfRangeException.h" + +namespace storm { + + namespace jani { + class Model; + class Automaton; + struct ArrayEliminatorData; + class VariableSet; + } + + namespace expressions { + template + class ExpressionEvaluator; + } + + namespace generator { + + + // A structure storing information about a transient variable + + template + struct TransientVariableData { + TransientVariableData(storm::expressions::Variable const& variable, boost::optional const& lowerBound, boost::optional const& upperBound, VariableType const& defaultValue, bool global = false); + TransientVariableData(storm::expressions::Variable const& variable, VariableType const& defaultValue, bool global = false); + + // The integer variable. + storm::expressions::Variable variable; + + // The lower bound of its range. + boost::optional lowerBound; + + // The upper bound of its range. + boost::optional upperBound; + + // Its default value + VariableType defaultValue; + + // A flag indicating whether the variable is a global one. + bool global; + + }; + + template + struct TransientVariableValuation { + std::vector const*, bool>> booleanValues; + std::vector const*, int64_t>> integerValues; + std::vector const*, ValueType>> rationalValues; + + void clear() { + booleanValues.clear(); + integerValues.clear(); + rationalValues.clear(); + } + + bool empty() const { + return booleanValues.empty() && integerValues.empty() && rationalValues.empty(); + } + + void setInEvaluator(storm::expressions::ExpressionEvaluator& evaluator, bool explorationChecks) const { + for (auto const& varValue : booleanValues) { + evaluator.setBooleanValue(varValue.first->variable, varValue.second); + } + for (auto const& varValue : integerValues) { + if (explorationChecks) { + STORM_LOG_THROW(!varValue.first->lowerBound.is_initialized() || varValue.first->lowerBound.get() <= varValue.second, storm::exceptions::OutOfRangeException, "The assigned value for transient variable " << varValue.first->variable.getName() << " is smaller than its lower bound."); + STORM_LOG_THROW(varValue.first->upperBound.is_initialized() || varValue.second <= varValue.first->upperBound.get(), storm::exceptions::OutOfRangeException, "The assigned value for transient variable " << varValue.first->variable.getName() << " is higher than its upper bound."); + } + evaluator.setIntegerValue(varValue.first->variable, varValue.second); + } + for (auto const& varValue : rationalValues) { + evaluator.setRationalValue(varValue.first->variable, varValue.second); + } + } + }; + + // A structure storing information about the used variables of the program. + template + struct TransientVariableInformation { + TransientVariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata); + + TransientVariableInformation() = default; + + void registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData); + TransientVariableData const& getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + TransientVariableData const& getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + TransientVariableData const& getRationalArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + + void setDefaultValuesInEvaluator(storm::expressions::ExpressionEvaluator& evaluator) const; + + std::vector> booleanVariableInformation; + std::vector> integerVariableInformation; + std::vector> rationalVariableInformation; + + /// Replacements for each array variable + std::unordered_map> arrayVariableToElementInformations; + + + private: + /*! + * Sorts the variables to establish a known ordering. + */ + void sortVariables(); + + /*! + * Creates all necessary variables for a JANI automaton. + */ + void createVariablesForAutomaton(storm::jani::Automaton const& automaton); + + /*! + * Creates all non-transient variables from the given set + */ + void createVariablesForVariableSet(storm::jani::VariableSet const& variableSet, bool global); + }; + + } +} diff --git a/src/storm/generator/VariableInformation.cpp b/src/storm/generator/VariableInformation.cpp index 62894270b..72a351250 100644 --- a/src/storm/generator/VariableInformation.cpp +++ b/src/storm/generator/VariableInformation.cpp @@ -4,6 +4,7 @@ #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Automaton.h" +#include "storm/storage/jani/ArrayEliminator.h" #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/expressions/ExpressionManager.h" @@ -20,16 +21,23 @@ namespace storm { BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, uint_fast64_t bitOffset, bool global, bool observable) : variable(variable), bitOffset(bitOffset), global(global), observable(observable) { // Intentionally left empty. } - - IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool global, bool observable) : variable(variable), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth), global(global), observable(observable) { - // Intentionally left empty. + + IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool global, bool observable, bool forceOutOfBoundsCheck) : variable(variable), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth), global(global), observable(observable), forceOutOfBoundsCheck(forceOutOfBoundsCheck) { + // Intentionally left empty. } LocationVariableInformation::LocationVariableInformation(storm::expressions::Variable const& variable, uint64_t highestValue, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool observable) : variable(variable), highestValue(highestValue), bitOffset(bitOffset), bitWidth(bitWidth), observable(observable) { // Intentionally left empty. } - VariableInformation::VariableInformation(storm::prism::Program const& program) : totalBitOffset(0) { + VariableInformation::VariableInformation(storm::prism::Program const& program, bool outOfBoundsState) : totalBitOffset(0) { + if (outOfBoundsState) { + outOfBoundsBit = 0; + ++totalBitOffset; + } else { + outOfBoundsBit = boost::none; + } + for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), totalBitOffset, true, booleanVariable.isObservable()); ++totalBitOffset; @@ -37,6 +45,7 @@ namespace storm { for (auto const& integerVariable : program.getGlobalIntegerVariables()) { int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); + STORM_LOG_THROW(lowerBound <= upperBound, storm::exceptions::WrongFormatException, "Lower bound must not be above upper bound"); uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); integerVariables.emplace_back(integerVariable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true, integerVariable.isObservable()); totalBitOffset += bitwidth; @@ -49,6 +58,7 @@ namespace storm { for (auto const& integerVariable : module.getIntegerVariables()) { int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); + STORM_LOG_THROW(lowerBound <= upperBound, storm::exceptions::WrongFormatException, "Lower bound must not be above upper bound"); uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); integerVariables.emplace_back(integerVariable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, false, integerVariable.isObservable()); totalBitOffset += bitwidth; @@ -58,67 +68,158 @@ namespace storm { sortVariables(); } - VariableInformation::VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata) : totalBitOffset(0) { - // Check that the model does not contain non-transient unbounded integer or non-transient real variables. + VariableInformation::VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata, uint64_t reservedBitsForUnboundedVariables, bool outOfBoundsState) : totalBitOffset(0) { + // Check that the model does not contain non-transient real variables. STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains global non-transient real variables."); - STORM_LOG_THROW(!model.getGlobalVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient unbounded integer variables."); for (auto const& automaton : model.getAutomata()) { - STORM_LOG_THROW(!automaton.getVariables().containsNonTransientUnboundedIntegerVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient unbounded integer variables in automaton '" << automaton.getName() << "'."); STORM_LOG_THROW(!automaton.getVariables().containsNonTransientRealVariables(), storm::exceptions::InvalidArgumentException, "Cannot build model from JANI model that contains non-transient real variables in automaton '" << automaton.getName() << "'."); } - - for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) { - if (!variable.isTransient()) { - booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, true, true); - ++totalBitOffset; - } - } - for (auto const& variable : model.getGlobalVariables().getBoundedIntegerVariables()) { - if (!variable.isTransient()) { - int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt(); - int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt(); - uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); - integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true, true); - totalBitOffset += bitwidth; - } +// +// for (auto const& variable : model.getGlobalVariables().getBooleanVariables()) { +// if (!variable.isTransient()) { +// booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, true, true); +// ++totalBitOffset; +// } +// } +// for (auto const& variable : model.getGlobalVariables().getBoundedIntegerVariables()) { +// if (!variable.isTransient()) { +// int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt(); +// int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt(); +// uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); +// integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, true, true); +// totalBitOffset += bitwidth; +// } +// } + + if (outOfBoundsState) { + outOfBoundsBit = 0; + ++totalBitOffset; + } else { + outOfBoundsBit = boost::none; } + createVariablesForVariableSet(model.getGlobalVariables(), reservedBitsForUnboundedVariables, true); + for (auto const& automatonRef : parallelAutomata) { - createVariablesForAutomaton(automatonRef.get()); + createVariablesForAutomaton(automatonRef.get(), reservedBitsForUnboundedVariables); } sortVariables(); } - void VariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton) { + void VariableInformation::registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData) { + arrayVariableToElementInformations.clear(); + // Find for each replaced array variable the corresponding references in this variable information + for (auto const& arrayVariable : arrayEliminatorData.eliminatedArrayVariables) { + if (!arrayVariable->isTransient()) { + STORM_LOG_ASSERT(arrayEliminatorData.replacements.count(arrayVariable->getExpressionVariable()) > 0, "No replacement for array variable."); + auto const& replacements = arrayEliminatorData.replacements.find(arrayVariable->getExpressionVariable())->second; + std::vector varInfoIndices; + for (auto const& replacedVar : replacements) { + if (replacedVar->getExpressionVariable().hasIntegerType()) { + uint64_t index = 0; + for (auto const& intInfo : integerVariables) { + if (intInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); + } else if (replacedVar->getExpressionVariable().hasBooleanType()) { + uint64_t index = 0; + for (auto const& boolInfo : booleanVariables) { + if (boolInfo.variable == replacedVar->getExpressionVariable()) { + varInfoIndices.push_back(index); + break; + } + ++index; + } + STORM_LOG_ASSERT(!varInfoIndices.empty() && varInfoIndices.back() == index, "Could not find a basic variable for replacement of array variable " << replacedVar->getExpressionVariable().getName() << " ."); + } else { + STORM_LOG_ASSERT(false, "Unhandled type of base variable."); + } + } + this->arrayVariableToElementInformations.emplace(arrayVariable->getExpressionVariable(), std::move(varInfoIndices)); + } + } + } + + BooleanVariableInformation const& VariableInformation::getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& boolInfoIndices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < boolInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << boolInfoIndices.size()); + return booleanVariables[boolInfoIndices[arrayIndex]]; + } + + IntegerVariableInformation const& VariableInformation::getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t arrayIndex) { + std::vector const& intInfoIndices = arrayVariableToElementInformations.at(arrayVariable); + STORM_LOG_THROW(arrayIndex < intInfoIndices.size(), storm::exceptions::WrongFormatException, "Array access at array " << arrayVariable.getName() << " evaluates to array index " << arrayIndex << " which is out of bounds as the array size is " << intInfoIndices.size()); + return integerVariables[intInfoIndices[arrayIndex]]; + } + + void VariableInformation::createVariablesForAutomaton(storm::jani::Automaton const& automaton, uint64_t reservedBitsForUnboundedVariables) { uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(automaton.getNumberOfLocations()))); locationVariables.emplace_back(automaton.getLocationExpressionVariable(), automaton.getNumberOfLocations() - 1, totalBitOffset, bitwidth, true); totalBitOffset += bitwidth; - for (auto const& variable : automaton.getVariables().getBooleanVariables()) { + createVariablesForVariableSet(automaton.getVariables(), reservedBitsForUnboundedVariables, false); + } + + void VariableInformation::createVariablesForVariableSet(storm::jani::VariableSet const& variableSet, uint64_t reservedBitsForUnboundedVariables, bool global) { + for (auto const& variable : variableSet.getBooleanVariables()) { if (!variable.isTransient()) { - booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, false, true); + booleanVariables.emplace_back(variable.getExpressionVariable(), totalBitOffset, global, true); ++totalBitOffset; } } - for (auto const& variable : automaton.getVariables().getBoundedIntegerVariables()) { + for (auto const& variable : variableSet.getBoundedIntegerVariables()) { if (!variable.isTransient()) { - int_fast64_t lowerBound = variable.getLowerBound().evaluateAsInt(); - int_fast64_t upperBound = variable.getUpperBound().evaluateAsInt(); + int64_t lowerBound; + int64_t upperBound; + if (variable.hasLowerBound()) { + lowerBound = variable.getLowerBound().evaluateAsInt(); + if (variable.hasUpperBound()) { + upperBound = variable.getUpperBound().evaluateAsInt(); + } else { + upperBound = lowerBound + ((1ll << reservedBitsForUnboundedVariables) - 1); + } + } else { + STORM_LOG_THROW(variable.hasUpperBound(), storm::exceptions::WrongFormatException, "Bounded integer variable has neither a lower nor an upper bound."); + upperBound = variable.getUpperBound().evaluateAsInt(); + lowerBound = upperBound - ((1ll << reservedBitsForUnboundedVariables) - 1); + } uint_fast64_t bitwidth = static_cast(std::ceil(std::log2(upperBound - lowerBound + 1))); - integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, false, true); + integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, bitwidth, global, true, !variable.hasLowerBound() || !variable.hasUpperBound()); totalBitOffset += bitwidth; } } + for (auto const& variable : variableSet.getUnboundedIntegerVariables()) { + if (!variable.isTransient()) { + int64_t lowerBound = -(1ll << (reservedBitsForUnboundedVariables - 1)); + int64_t upperBound = (1ll << (reservedBitsForUnboundedVariables - 1)) - 1; + integerVariables.emplace_back(variable.getExpressionVariable(), lowerBound, upperBound, totalBitOffset, reservedBitsForUnboundedVariables, global, true, true); + totalBitOffset += reservedBitsForUnboundedVariables; + } + } } uint_fast64_t VariableInformation::getTotalBitOffset(bool roundTo64Bit) const { uint_fast64_t result = totalBitOffset; - if (roundTo64Bit) { + if (roundTo64Bit & ((result & ((1ull << 6) - 1)) != 0)) { result = ((result >> 6) + 1) << 6; } return result; } + + bool VariableInformation::hasOutOfBoundsBit() const { + return outOfBoundsBit != boost::none; + } + + uint64_t VariableInformation::getOutOfBoundsBit() const { + assert(hasOutOfBoundsBit()); + return outOfBoundsBit.get(); + } + void VariableInformation::sortVariables() { // Sort the variables so we can make some assumptions when iterating over them (in the next-state generators). diff --git a/src/storm/generator/VariableInformation.h b/src/storm/generator/VariableInformation.h index 98e846caf..ffa02f5ac 100644 --- a/src/storm/generator/VariableInformation.h +++ b/src/storm/generator/VariableInformation.h @@ -2,7 +2,9 @@ #define STORM_GENERATOR_VARIABLEINFORMATION_H_ #include +#include #include +#include #include "storm/storage/expressions/Variable.h" @@ -14,6 +16,8 @@ namespace storm { namespace jani { class Model; class Automaton; + struct ArrayEliminatorData; + class VariableSet; } namespace generator { @@ -36,8 +40,9 @@ namespace storm { // A structure storing information about the integer variables of the model. struct IntegerVariableInformation { - IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool global, bool observable); - + + IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth, bool global = false, bool observable = true, bool forceOutOfBoundsCheck = false); + // The integer variable. storm::expressions::Variable variable; @@ -57,6 +62,9 @@ namespace storm { bool global; bool observable; + + // A flag indicating whether an out of bounds check is enforced for this variable. + bool forceOutOfBoundsCheck; }; // A structure storing information about the location variables of the model. @@ -80,12 +88,16 @@ namespace storm { // A structure storing information about the used variables of the program. struct VariableInformation { - VariableInformation(storm::prism::Program const& program); - VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata); + VariableInformation(storm::prism::Program const& program, bool outOfBoundsState = false); + VariableInformation(storm::jani::Model const& model, std::vector> const& parallelAutomata, uint64_t reservedBitsForUnboundedVariables, bool outOfBoundsState); VariableInformation() = default; uint_fast64_t getTotalBitOffset(bool roundTo64Bit = false) const; + void registerArrayVariableReplacements(storm::jani::ArrayEliminatorData const& arrayEliminatorData); + BooleanVariableInformation const& getBooleanArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + IntegerVariableInformation const& getIntegerArrayVariableReplacement(storm::expressions::Variable const& arrayVariable, uint64_t index); + /// The total bit offset over all variables. uint_fast64_t totalBitOffset; @@ -98,16 +110,30 @@ namespace storm { /// The integer variables. std::vector integerVariables; + /// Replacements for each array variable + std::unordered_map> arrayVariableToElementInformations; + + bool hasOutOfBoundsBit() const; + + uint64_t getOutOfBoundsBit() const; + private: + boost::optional outOfBoundsBit; + /*! * Sorts the variables to establish a known ordering. */ void sortVariables(); - + /*! * Creates all necessary variables for a JANI automaton. */ - void createVariablesForAutomaton(storm::jani::Automaton const& automaton); + void createVariablesForAutomaton(storm::jani::Automaton const& automaton, uint64_t reservedBitsForUnboundedVariables); + + /*! + * Creates all non-transient variables from the given set + */ + void createVariablesForVariableSet(storm::jani::VariableSet const& variableSet, uint64_t reservedBitsForUnboundedVariables, bool global); }; } diff --git a/src/storm/logic/AtomicExpressionFormula.cpp b/src/storm/logic/AtomicExpressionFormula.cpp index b7af29bfb..6fe7b6fdb 100644 --- a/src/storm/logic/AtomicExpressionFormula.cpp +++ b/src/storm/logic/AtomicExpressionFormula.cpp @@ -24,6 +24,10 @@ namespace storm { atomicExpressionFormulas.push_back(std::dynamic_pointer_cast(this->shared_from_this())); } + void AtomicExpressionFormula::gatherUsedVariables(std::set& usedVariables) const { + expression.gatherVariables(usedVariables); + } + std::ostream& AtomicExpressionFormula::writeToStream(std::ostream& out) const { out << expression; return out; diff --git a/src/storm/logic/AtomicExpressionFormula.h b/src/storm/logic/AtomicExpressionFormula.h index bf3a2982f..21168493b 100644 --- a/src/storm/logic/AtomicExpressionFormula.h +++ b/src/storm/logic/AtomicExpressionFormula.h @@ -22,7 +22,8 @@ namespace storm { virtual std::ostream& writeToStream(std::ostream& out) const override; virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + private: // The atomic expression represented by this node in the formula tree. storm::expressions::Expression expression; diff --git a/src/storm/logic/BinaryPathFormula.cpp b/src/storm/logic/BinaryPathFormula.cpp index b6db33e01..5de44c0c5 100644 --- a/src/storm/logic/BinaryPathFormula.cpp +++ b/src/storm/logic/BinaryPathFormula.cpp @@ -33,6 +33,11 @@ namespace storm { this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels); } + void BinaryPathFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getLeftSubformula().gatherUsedVariables(usedVariables); + this->getRightSubformula().gatherUsedVariables(usedVariables); + } + bool BinaryPathFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/BinaryPathFormula.h b/src/storm/logic/BinaryPathFormula.h index 82a93d344..13f2573cc 100644 --- a/src/storm/logic/BinaryPathFormula.h +++ b/src/storm/logic/BinaryPathFormula.h @@ -23,7 +23,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/BinaryStateFormula.cpp b/src/storm/logic/BinaryStateFormula.cpp index 83535081c..b2f45e269 100644 --- a/src/storm/logic/BinaryStateFormula.cpp +++ b/src/storm/logic/BinaryStateFormula.cpp @@ -32,5 +32,10 @@ namespace storm { this->getLeftSubformula().gatherReferencedRewardModels(referencedRewardModels); this->getRightSubformula().gatherReferencedRewardModels(referencedRewardModels); } + + void BinaryStateFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getLeftSubformula().gatherUsedVariables(usedVariables); + this->getRightSubformula().gatherUsedVariables(usedVariables); + } } } diff --git a/src/storm/logic/BinaryStateFormula.h b/src/storm/logic/BinaryStateFormula.h index 85c996342..67c85a0b1 100644 --- a/src/storm/logic/BinaryStateFormula.h +++ b/src/storm/logic/BinaryStateFormula.h @@ -21,6 +21,7 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; + virtual void gatherUsedVariables(std::set& usedVariables) const override; private: std::shared_ptr leftSubformula; diff --git a/src/storm/logic/BoundedUntilFormula.cpp b/src/storm/logic/BoundedUntilFormula.cpp index 97c768944..1933db10e 100644 --- a/src/storm/logic/BoundedUntilFormula.cpp +++ b/src/storm/logic/BoundedUntilFormula.cpp @@ -84,6 +84,30 @@ namespace storm { } } + void BoundedUntilFormula::gatherUsedVariables(std::set& usedVariables) const { + if (hasMultiDimensionalSubformulas()) { + for (unsigned i = 0; i < this->getDimension(); ++i) { + this->getLeftSubformula(i).gatherUsedVariables(usedVariables); + this->getRightSubformula(i).gatherUsedVariables(usedVariables); + if (this->hasLowerBound(i)) { + this->getLowerBound(i).gatherVariables(usedVariables); + } + if (this->hasUpperBound(i)) { + this->getUpperBound(i).gatherVariables(usedVariables); + } + } + } else { + this->getLeftSubformula().gatherUsedVariables(usedVariables); + this->getRightSubformula().gatherUsedVariables(usedVariables); + if (this->hasLowerBound(0)) { + this->getLowerBound().gatherVariables(usedVariables); + } + if (this->hasUpperBound(0)) { + this->getUpperBound().gatherVariables(usedVariables); + } + } + } + bool BoundedUntilFormula::hasQualitativeResult() const { return false; } @@ -165,7 +189,7 @@ namespace storm { } bool BoundedUntilFormula::hasUpperBound() const { - for(auto const& ub : upperBound) { + for (auto const& ub : upperBound) { if (static_cast(ub)) { return true; } @@ -285,7 +309,11 @@ namespace storm { out << ", "; } if (this->getTimeBoundReference(i).isRewardBound()) { - out << "rew{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; + out << "rew"; + if (this->getTimeBoundReference(i).hasRewardAccumulation()) { + out << "[" << this->getTimeBoundReference(i).getRewardAccumulation() << "]"; + } + out << "{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; } else if (this->getTimeBoundReference(i).isStepBound()) { out << "steps"; //} else if (this->getTimeBoundReference(i).isStepBound()) diff --git a/src/storm/logic/BoundedUntilFormula.h b/src/storm/logic/BoundedUntilFormula.h index eed5c5220..5ae10e8b5 100644 --- a/src/storm/logic/BoundedUntilFormula.h +++ b/src/storm/logic/BoundedUntilFormula.h @@ -24,7 +24,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/CloneVisitor.cpp b/src/storm/logic/CloneVisitor.cpp index d97dd41d6..4b427b1dc 100644 --- a/src/storm/logic/CloneVisitor.cpp +++ b/src/storm/logic/CloneVisitor.cpp @@ -70,7 +70,11 @@ namespace storm { boost::any CloneVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); - return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); + if (f.hasRewardAccumulation()) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } else { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); + } } boost::any CloneVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { @@ -119,8 +123,8 @@ namespace storm { return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), f.getOperatorInformation())); } - boost::any CloneVisitor::visit(TotalRewardFormula const&, boost::any const&) const { - return std::static_pointer_cast(std::make_shared()); + boost::any CloneVisitor::visit(TotalRewardFormula const& f, boost::any const&) const { + return std::static_pointer_cast(std::make_shared(f)); } boost::any CloneVisitor::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const { diff --git a/src/storm/logic/ConditionalFormula.cpp b/src/storm/logic/ConditionalFormula.cpp index 31043e07b..a02af1877 100644 --- a/src/storm/logic/ConditionalFormula.cpp +++ b/src/storm/logic/ConditionalFormula.cpp @@ -49,6 +49,11 @@ namespace storm { this->getConditionFormula().gatherReferencedRewardModels(referencedRewardModels); } + void ConditionalFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getSubformula().gatherUsedVariables(usedVariables); + this->getConditionFormula().gatherUsedVariables(usedVariables); + } + bool ConditionalFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/ConditionalFormula.h b/src/storm/logic/ConditionalFormula.h index 30af1a3a6..3a32b3463 100644 --- a/src/storm/logic/ConditionalFormula.h +++ b/src/storm/logic/ConditionalFormula.h @@ -28,7 +28,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/CumulativeRewardFormula.cpp b/src/storm/logic/CumulativeRewardFormula.cpp index 19a60a623..7abcdc7e4 100644 --- a/src/storm/logic/CumulativeRewardFormula.cpp +++ b/src/storm/logic/CumulativeRewardFormula.cpp @@ -9,11 +9,11 @@ namespace storm { namespace logic { - CumulativeRewardFormula::CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference) : timeBoundReferences({timeBoundReference}), bounds({bound}) { + CumulativeRewardFormula::CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference, boost::optional rewardAccumulation) : timeBoundReferences({timeBoundReference}), bounds({bound}), rewardAccumulation(rewardAccumulation) { // Intentionally left empty. } - CumulativeRewardFormula::CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences) : timeBoundReferences(timeBoundReferences), bounds(bounds) { + CumulativeRewardFormula::CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences, boost::optional rewardAccumulation) : timeBoundReferences(timeBoundReferences), bounds(bounds), rewardAccumulation(rewardAccumulation) { STORM_LOG_ASSERT(this->timeBoundReferences.size() == this->bounds.size(), "Number of time bounds and number of time bound references does not match."); STORM_LOG_ASSERT(!this->timeBoundReferences.empty(), "No time bounds given."); @@ -47,6 +47,12 @@ namespace storm { } } + void CumulativeRewardFormula::gatherUsedVariables(std::set& usedVariables) const { + for (unsigned i = 0; i < this->getDimension(); ++i) { + this->getBound(i).gatherVariables(usedVariables); + } + } + TimeBoundReference const& CumulativeRewardFormula::getTimeBoundReference() const { STORM_LOG_ASSERT(!isMultiDimensional(), "Cumulative Reward Formula is multi-dimensional."); return getTimeBoundReference(0); @@ -137,12 +143,24 @@ namespace storm { STORM_LOG_THROW(!bound.containsVariables(), storm::exceptions::InvalidOperationException, "Cannot evaluate time-bound '" << bound << "' as it contains undefined constants."); } + bool CumulativeRewardFormula::hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& CumulativeRewardFormula::getRewardAccumulation() const { + return rewardAccumulation.get(); + } + + std::shared_ptr CumulativeRewardFormula::restrictToDimension(unsigned i) const { return std::make_shared(bounds.at(i), getTimeBoundReference(i)); } std::ostream& CumulativeRewardFormula::writeToStream(std::ostream& out) const { out << "C"; + if (hasRewardAccumulation()) { + out << "[" << getRewardAccumulation() << "]"; + } if (this->isMultiDimensional()) { out << "^{"; } @@ -151,7 +169,11 @@ namespace storm { out << ", "; } if (this->getTimeBoundReference(i).isRewardBound()) { - out << "rew{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; + out << "rew"; + if (this->getTimeBoundReference(i).hasRewardAccumulation()) { + out << "[" << this->getTimeBoundReference(i).getRewardAccumulation() << "]"; + } + out << "{\"" << this->getTimeBoundReference(i).getRewardName() << "\"}"; } else if (this->getTimeBoundReference(i).isStepBound()) { out << "steps"; //} else if (this->getTimeBoundReference(i).isStepBound()) diff --git a/src/storm/logic/CumulativeRewardFormula.h b/src/storm/logic/CumulativeRewardFormula.h index e40370b07..cccd1ac9e 100644 --- a/src/storm/logic/CumulativeRewardFormula.h +++ b/src/storm/logic/CumulativeRewardFormula.h @@ -10,8 +10,8 @@ namespace storm { namespace logic { class CumulativeRewardFormula : public PathFormula { public: - CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference = TimeBoundReference(TimeBoundType::Time)); - CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences); + CumulativeRewardFormula(TimeBound const& bound, TimeBoundReference const& timeBoundReference = TimeBoundReference(TimeBoundType::Time), boost::optional rewardAccumulation = boost::none); + CumulativeRewardFormula(std::vector const& bounds, std::vector const& timeBoundReferences, boost::optional rewardAccumulation = boost::none); virtual ~CumulativeRewardFormula() = default; @@ -24,7 +24,8 @@ namespace storm { virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual std::ostream& writeToStream(std::ostream& out) const override; TimeBoundReference const& getTimeBoundReference() const; @@ -47,6 +48,9 @@ namespace storm { template ValueType getNonStrictBound() const; + bool hasRewardAccumulation() const; + RewardAccumulation const& getRewardAccumulation() const; + std::shared_ptr restrictToDimension(unsigned i) const; private: @@ -54,6 +58,8 @@ namespace storm { std::vector timeBoundReferences; std::vector bounds; + boost::optional rewardAccumulation; + }; } } diff --git a/src/storm/logic/EventuallyFormula.cpp b/src/storm/logic/EventuallyFormula.cpp index 5b7a2cdac..c8ed335e5 100644 --- a/src/storm/logic/EventuallyFormula.cpp +++ b/src/storm/logic/EventuallyFormula.cpp @@ -6,8 +6,9 @@ namespace storm { namespace logic { - EventuallyFormula::EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context) : UnaryPathFormula(subformula), context(context) { + EventuallyFormula::EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context, boost::optional rewardAccumulation) : UnaryPathFormula(subformula), context(context), rewardAccumulation(rewardAccumulation) { STORM_LOG_THROW(context == FormulaContext::Probability || context == FormulaContext::Reward || context == FormulaContext::Time, storm::exceptions::InvalidPropertyException, "Invalid context for formula."); + STORM_LOG_THROW(context != FormulaContext::Probability || !rewardAccumulation.is_initialized(), storm::exceptions::InvalidPropertyException, "Reward accumulations should only be given for time- and reward formulas"); } FormulaContext const& EventuallyFormula::getContext() const { @@ -31,7 +32,7 @@ namespace storm { } bool EventuallyFormula::isProbabilityPathFormula() const { - return this->isEventuallyFormula(); + return this->isReachabilityProbabilityFormula(); } bool EventuallyFormula::isRewardPathFormula() const { @@ -42,6 +43,14 @@ namespace storm { return this->isReachabilityTimeFormula(); } + bool EventuallyFormula::hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& EventuallyFormula::getRewardAccumulation() const { + return rewardAccumulation.get(); + } + boost::any EventuallyFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { return visitor.visit(*this, data); } @@ -49,6 +58,9 @@ namespace storm { std::ostream& EventuallyFormula::writeToStream(std::ostream& out) const { out << "F "; this->getSubformula().writeToStream(out); + if (hasRewardAccumulation()) { + out << "[" << getRewardAccumulation() << "]"; + } return out; } } diff --git a/src/storm/logic/EventuallyFormula.h b/src/storm/logic/EventuallyFormula.h index 9cc4d853d..5fa30da6d 100644 --- a/src/storm/logic/EventuallyFormula.h +++ b/src/storm/logic/EventuallyFormula.h @@ -1,14 +1,17 @@ #ifndef STORM_LOGIC_EVENTUALLYFORMULA_H_ #define STORM_LOGIC_EVENTUALLYFORMULA_H_ +#include + #include "storm/logic/UnaryPathFormula.h" #include "storm/logic/FormulaContext.h" +#include "storm/logic/RewardAccumulation.h" namespace storm { namespace logic { class EventuallyFormula : public UnaryPathFormula { public: - EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context = FormulaContext::Probability); + EventuallyFormula(std::shared_ptr const& subformula, FormulaContext context = FormulaContext::Probability, boost::optional rewardAccumulation = boost::none); virtual ~EventuallyFormula() { // Intentionally left empty. @@ -27,9 +30,12 @@ namespace storm { virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; virtual std::ostream& writeToStream(std::ostream& out) const override; + bool hasRewardAccumulation() const; + RewardAccumulation const& getRewardAccumulation() const; private: FormulaContext context; + boost::optional rewardAccumulation; }; } } diff --git a/src/storm/logic/VariableSubstitutionVisitor.cpp b/src/storm/logic/ExpressionSubstitutionVisitor.cpp similarity index 54% rename from src/storm/logic/VariableSubstitutionVisitor.cpp rename to src/storm/logic/ExpressionSubstitutionVisitor.cpp index 7fae8498c..267fcf42c 100644 --- a/src/storm/logic/VariableSubstitutionVisitor.cpp +++ b/src/storm/logic/ExpressionSubstitutionVisitor.cpp @@ -1,50 +1,59 @@ -#include "storm/logic/VariableSubstitutionVisitor.h" +#include "storm/logic/ExpressionSubstitutionVisitor.h" #include "storm/logic/Formulas.h" namespace storm { namespace logic { - VariableSubstitutionVisitor::VariableSubstitutionVisitor(std::map const& substitution) : substitution(substitution) { - // Intentionally left empty. + std::shared_ptr ExpressionSubstitutionVisitor::substitute(Formula const& f, std::function const& substitutionFunction) const { + boost::any result = f.accept(*this, &substitutionFunction); + return boost::any_cast>(result); } - std::shared_ptr VariableSubstitutionVisitor::substitute(Formula const& f) const { - boost::any result = f.accept(*this, boost::any()); - return boost::any_cast>(result); + OperatorInformation substituteOperatorInformation(OperatorInformation const& operatorInformation, std::function const& substitutionFunction) { + boost::optional bound; + if(operatorInformation.bound) { + bound = Bound(operatorInformation.bound->comparisonType, substitutionFunction(operatorInformation.bound->threshold)); + } + return OperatorInformation(operatorInformation.optimalityType, bound); } - - boost::any VariableSubstitutionVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { + + boost::any ExpressionSubstitutionVisitor::visit(TimeOperatorFormula const& f, boost::any const& data) const { std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); - return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation()))); + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); } - boost::any VariableSubstitutionVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { + boost::any ExpressionSubstitutionVisitor::visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); - return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation()))); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); } - boost::any VariableSubstitutionVisitor::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const { + boost::any ExpressionSubstitutionVisitor::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); - return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation()))); + return std::static_pointer_cast(std::make_shared(subformula, substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); } - boost::any VariableSubstitutionVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + boost::any ExpressionSubstitutionVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); - return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), substituteOperatorInformation(f.getOperatorInformation()))); + return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), substituteOperatorInformation(f.getOperatorInformation(), substitutionFunction))); } - boost::any VariableSubstitutionVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + boost::any ExpressionSubstitutionVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); std::vector> lowerBounds, upperBounds; std::vector timeBoundReferences; for (uint64_t i = 0; i < f.getDimension(); ++i) { if (f.hasLowerBound(i)) { - lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), f.getLowerBound(i).substitute(substitution))); + lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), substitutionFunction(f.getLowerBound(i)))); } else { lowerBounds.emplace_back(); } if (f.hasUpperBound(i)) { - upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), f.getUpperBound(i).substitute(substitution))); + upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), substitutionFunction(f.getUpperBound(i)))); } else { upperBounds.emplace_back(); } @@ -64,31 +73,27 @@ namespace storm { } } - boost::any VariableSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const&) const { + boost::any ExpressionSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); std::vector bounds; std::vector timeBoundReferences; for (uint64_t i = 0; i < f.getDimension(); ++i) { - bounds.emplace_back(TimeBound(f.isBoundStrict(i), f.getBound(i).substitute(substitution))); + bounds.emplace_back(TimeBound(f.isBoundStrict(i), substitutionFunction(f.getBound(i)))); timeBoundReferences.push_back(f.getTimeBoundReference(i)); } return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences)); } - boost::any VariableSubstitutionVisitor::visit(InstantaneousRewardFormula const& f, boost::any const&) const { - return std::static_pointer_cast(std::make_shared(f.getBound().substitute(substitution), f.getTimeBoundType())); + boost::any ExpressionSubstitutionVisitor::visit(InstantaneousRewardFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(substitutionFunction(f.getBound()), f.getTimeBoundType())); } - boost::any VariableSubstitutionVisitor::visit(AtomicExpressionFormula const& f, boost::any const&) const { - return std::static_pointer_cast(std::make_shared(f.getExpression().substitute(substitution))); + boost::any ExpressionSubstitutionVisitor::visit(AtomicExpressionFormula const& f, boost::any const& data) const { + auto const& substitutionFunction = *boost::any_cast const*>(data); + return std::static_pointer_cast(std::make_shared(substitutionFunction(f.getExpression()))); } - OperatorInformation VariableSubstitutionVisitor::substituteOperatorInformation(OperatorInformation const& operatorInformation) const { - boost::optional bound; - if(operatorInformation.bound) { - bound = Bound(operatorInformation.bound->comparisonType, operatorInformation.bound->threshold.substitute(substitution)); - } - return OperatorInformation(operatorInformation.optimalityType, bound); - } } } diff --git a/src/storm/logic/VariableSubstitutionVisitor.h b/src/storm/logic/ExpressionSubstitutionVisitor.h similarity index 65% rename from src/storm/logic/VariableSubstitutionVisitor.h rename to src/storm/logic/ExpressionSubstitutionVisitor.h index 80156c064..e594f9b79 100644 --- a/src/storm/logic/VariableSubstitutionVisitor.h +++ b/src/storm/logic/ExpressionSubstitutionVisitor.h @@ -1,22 +1,22 @@ -#ifndef STORM_LOGIC_VARIABLESUBSTITUTIONVISITOR_H_ -#define STORM_LOGIC_VARIABLESUBSTITUTIONVISITOR_H_ +#pragma once #include +#include #include "storm/logic/CloneVisitor.h" #include "storm/storage/expressions/Expression.h" namespace storm { + namespace logic { - class VariableSubstitutionVisitor : public CloneVisitor { + class ExpressionSubstitutionVisitor : public CloneVisitor { public: - VariableSubstitutionVisitor(std::map const& substitution); + ExpressionSubstitutionVisitor() = default; - std::shared_ptr substitute(Formula const& f) const; + std::shared_ptr substitute(Formula const& f, std::function const& substitutionFunction) const; - virtual boost::any visit(TimeOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(LongRunAverageOperatorFormula const& f, boost::any const& data) const override; virtual boost::any visit(ProbabilityOperatorFormula const& f, boost::any const& data) const override; @@ -26,15 +26,8 @@ namespace storm { virtual boost::any visit(InstantaneousRewardFormula const& f, boost::any const& data) const override; virtual boost::any visit(AtomicExpressionFormula const& f, boost::any const& data) const override; - private: - - OperatorInformation substituteOperatorInformation(OperatorInformation const& operatorInformation) const; - - std::map const& substitution; }; } } - -#endif /* STORM_LOGIC_VARIABLESUBSTITUTIONVISITOR_H_ */ diff --git a/src/storm/logic/Formula.cpp b/src/storm/logic/Formula.cpp index 3f871908e..9dd2b0fba 100644 --- a/src/storm/logic/Formula.cpp +++ b/src/storm/logic/Formula.cpp @@ -3,8 +3,10 @@ #include "storm/logic/FragmentChecker.h" #include "storm/logic/FormulaInformationVisitor.h" -#include "storm/logic/VariableSubstitutionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" +#include "storm/logic/ExpressionSubstitutionVisitor.h" #include "storm/logic/LabelSubstitutionVisitor.h" +#include "storm/logic/RewardModelNameSubstitutionVisitor.h" #include "storm/logic/ToExpressionVisitor.h" namespace storm { @@ -431,6 +433,12 @@ namespace storm { return result; } + std::set Formula::getUsedVariables() const { + std::set usedVariables; + this->gatherUsedVariables(usedVariables); + return usedVariables; + } + std::set Formula::getReferencedRewardModels() const { std::set referencedRewardModels; this->gatherReferencedRewardModels(referencedRewardModels); @@ -438,8 +446,13 @@ namespace storm { } std::shared_ptr Formula::substitute(std::map const& substitution) const { - VariableSubstitutionVisitor visitor(substitution); - return visitor.substitute(*this); + storm::expressions::JaniExpressionSubstitutionVisitor> v(substitution); + return substitute([&v](storm::expressions::Expression const& exp) {return v.substitute(exp);}); + } + + std::shared_ptr Formula::substitute(std::function const& expressionSubstitution) const { + ExpressionSubstitutionVisitor visitor; + return visitor.substitute(*this, expressionSubstitution); } std::shared_ptr Formula::substitute(std::map const& labelSubstitution) const { @@ -452,6 +465,11 @@ namespace storm { return visitor.substitute(*this); } + std::shared_ptr Formula::substituteRewardModelNames(std::map const& rewardModelNameSubstitution) const { + RewardModelNameSubstitutionVisitor visitor(rewardModelNameSubstitution); + return visitor.substitute(*this); + } + storm::expressions::Expression Formula::toExpression(storm::expressions::ExpressionManager const& manager, std::map const& labelToExpressionMapping) const { ToExpressionVisitor visitor; if (labelToExpressionMapping.empty()) { @@ -480,7 +498,11 @@ namespace storm { void Formula::gatherReferencedRewardModels(std::set&) const { return; } - + + void Formula::gatherUsedVariables(std::set& usedVariables) const { + return; + } + std::string Formula::toString() const { std::stringstream str2; writeToStream(str2); diff --git a/src/storm/logic/Formula.h b/src/storm/logic/Formula.h index a76dd0ef7..91ccdf342 100644 --- a/src/storm/logic/Formula.h +++ b/src/storm/logic/Formula.h @@ -192,14 +192,17 @@ namespace storm { std::vector> getAtomicExpressionFormulas() const; std::vector> getAtomicLabelFormulas() const; + std::set getUsedVariables() const; std::set getReferencedRewardModels() const; std::shared_ptr asSharedPointer(); std::shared_ptr asSharedPointer() const; std::shared_ptr substitute(std::map const& substitution) const; + std::shared_ptr substitute(std::function const& expressionSubstitution) const; std::shared_ptr substitute(std::map const& labelSubstitution) const; std::shared_ptr substitute(std::map const& labelSubstitution) const; + std::shared_ptr substituteRewardModelNames(std::map const& rewardModelNameSubstitution) const; /*! * Takes the formula and converts it to an equivalent expression. The formula may contain atomic labels, but @@ -218,7 +221,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const; - + virtual void gatherUsedVariables(std::set& usedVariables) const; + private: // Currently empty. }; diff --git a/src/storm/logic/FragmentChecker.cpp b/src/storm/logic/FragmentChecker.cpp index 24ad016c8..adc96728b 100644 --- a/src/storm/logic/FragmentChecker.cpp +++ b/src/storm/logic/FragmentChecker.cpp @@ -70,6 +70,9 @@ namespace storm { } else { assert(tbr.isRewardBound()); result = result && inherited.getSpecification().areRewardBoundedUntilFormulasAllowed(); + if (tbr.hasRewardAccumulation()) { + result = result && inherited.getSpecification().isRewardAccumulationAllowed(); + } } } @@ -118,6 +121,7 @@ namespace storm { bool result = inherited.getSpecification().areCumulativeRewardFormulasAllowed(); result = result && (!f.isMultiDimensional() || inherited.getSpecification().areMultiDimensionalCumulativeRewardFormulasAllowed()); + result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); for (uint64_t i = 0; i < f.getDimension(); ++i) { auto tbr = f.getTimeBoundReference(i); if (tbr.isStepBound()) { @@ -127,6 +131,9 @@ namespace storm { } else { assert(tbr.isRewardBound()); result = result && inherited.getSpecification().areRewardBoundedCumulativeRewardFormulasAllowed(); + if (tbr.hasRewardAccumulation()) { + result = result && inherited.getSpecification().isRewardAccumulationAllowed(); + } } } return result; @@ -140,12 +147,15 @@ namespace storm { if (!inherited.getSpecification().areNestedPathFormulasAllowed()) { result = result && !f.getSubformula().isPathFormula(); } + result = result && !f.hasRewardAccumulation(); } else if (f.isReachabilityRewardFormula()) { result = result && inherited.getSpecification().areReachabilityRewardFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); + result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); } else if (f.isReachabilityTimeFormula()) { result = result && inherited.getSpecification().areReachbilityTimeFormulasAllowed(); result = result && f.getSubformula().isStateFormula(); + result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); } result = result && boost::any_cast(f.getSubformula().accept(*this, data)); return result; @@ -250,6 +260,7 @@ namespace storm { result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed()); result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula()); result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation); + if (!inherited.getSpecification().areNestedOperatorsAllowed()) { result = result && boost::any_cast(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false)))); } else { @@ -258,9 +269,11 @@ namespace storm { return result; } - boost::any FragmentChecker::visit(TotalRewardFormula const&, boost::any const& data) const { + boost::any FragmentChecker::visit(TotalRewardFormula const& f, boost::any const& data) const { InheritedInformation const& inherited = boost::any_cast(data); - return inherited.getSpecification().areTotalRewardFormulasAllowed(); + bool result = (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed()); + result = result && inherited.getSpecification().areTotalRewardFormulasAllowed(); + return result; } boost::any FragmentChecker::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const { diff --git a/src/storm/logic/FragmentSpecification.cpp b/src/storm/logic/FragmentSpecification.cpp index cdcfc6ecd..9b5b8b17e 100644 --- a/src/storm/logic/FragmentSpecification.cpp +++ b/src/storm/logic/FragmentSpecification.cpp @@ -1,6 +1,7 @@ #include "storm/logic/FragmentSpecification.h" #include +#include "storm/logic/RewardAccumulation.h" namespace storm { namespace logic { @@ -161,6 +162,8 @@ namespace storm { operatorAtTopLevelRequired = false; multiObjectiveFormulaAtTopLevelRequired = false; operatorsAtTopLevelOfMultiObjectiveFormulasRequired = false; + + rewardAccumulation = false; } FragmentSpecification FragmentSpecification::copy() const { @@ -564,5 +567,15 @@ namespace storm { return *this; } + bool FragmentSpecification::isRewardAccumulationAllowed() const { + return rewardAccumulation; + } + + FragmentSpecification& FragmentSpecification::setRewardAccumulationAllowed(bool newValue) { + rewardAccumulation = newValue; + return *this; + } + + } } diff --git a/src/storm/logic/FragmentSpecification.h b/src/storm/logic/FragmentSpecification.h index d90ebd5fb..012716c78 100644 --- a/src/storm/logic/FragmentSpecification.h +++ b/src/storm/logic/FragmentSpecification.h @@ -1,8 +1,14 @@ #ifndef STORM_LOGIC_FRAGMENTSPECIFICATION_H_ #define STORM_LOGIC_FRAGMENTSPECIFICATION_H_ +#include +#include + namespace storm { namespace logic { + + class RewardAccumulation; + class FragmentSpecification { public: FragmentSpecification(); @@ -139,6 +145,10 @@ namespace storm { bool areOperatorsAtTopLevelOfMultiObjectiveFormulasRequired() const; FragmentSpecification& setOperatorsAtTopLevelOfMultiObjectiveFormulasRequired(bool newValue); + bool isRewardAccumulationAllowed() const; + FragmentSpecification& setRewardAccumulationAllowed(bool newValue); + + FragmentSpecification& setOperatorsAllowed(bool newValue); FragmentSpecification& setTimeAllowed(bool newValue); FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue); @@ -195,6 +205,8 @@ namespace storm { bool operatorAtTopLevelRequired; bool multiObjectiveFormulaAtTopLevelRequired; bool operatorsAtTopLevelOfMultiObjectiveFormulasRequired; + + bool rewardAccumulation; }; // Propositional. diff --git a/src/storm/logic/InstantaneousRewardFormula.cpp b/src/storm/logic/InstantaneousRewardFormula.cpp index f702ca578..37bdee1c9 100644 --- a/src/storm/logic/InstantaneousRewardFormula.cpp +++ b/src/storm/logic/InstantaneousRewardFormula.cpp @@ -60,6 +60,10 @@ namespace storm { return value; } + void InstantaneousRewardFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getBound().gatherVariables(usedVariables); + } + void InstantaneousRewardFormula::checkNoVariablesInBound(storm::expressions::Expression const& bound) { STORM_LOG_THROW(!bound.containsVariables(), storm::exceptions::InvalidOperationException, "Cannot evaluate time-instant '" << bound << "' as it contains undefined constants."); } diff --git a/src/storm/logic/InstantaneousRewardFormula.h b/src/storm/logic/InstantaneousRewardFormula.h index ee9b5b28f..69e5dd38f 100644 --- a/src/storm/logic/InstantaneousRewardFormula.h +++ b/src/storm/logic/InstantaneousRewardFormula.h @@ -35,6 +35,8 @@ namespace storm { template ValueType getBound() const; + virtual void gatherUsedVariables(std::set& usedVariables) const override; + private: static void checkNoVariablesInBound(storm::expressions::Expression const& bound); diff --git a/src/storm/logic/LabelSubstitutionVisitor.cpp b/src/storm/logic/LabelSubstitutionVisitor.cpp index 1e17649a3..08726901c 100644 --- a/src/storm/logic/LabelSubstitutionVisitor.cpp +++ b/src/storm/logic/LabelSubstitutionVisitor.cpp @@ -24,14 +24,14 @@ namespace storm { if (it != labelToExpressionMapping->end()) { return std::static_pointer_cast(std::make_shared(it->second)); } else { - return f.asSharedPointer(); + return std::static_pointer_cast(std::make_shared(f.getLabel())); } } else { auto it = labelToLabelMapping->find(f.getLabel()); if (it != labelToLabelMapping->end()) { return std::static_pointer_cast(std::make_shared(it->second)); } else { - return f.asSharedPointer(); + return std::static_pointer_cast(std::make_shared(f.getLabel())); } } } diff --git a/src/storm/logic/OperatorFormula.cpp b/src/storm/logic/OperatorFormula.cpp index 3b0fbcd1c..a86e5a47a 100644 --- a/src/storm/logic/OperatorFormula.cpp +++ b/src/storm/logic/OperatorFormula.cpp @@ -85,6 +85,13 @@ namespace storm { return !this->hasBound(); } + void OperatorFormula::gatherUsedVariables(std::set& usedVariables) const { + UnaryStateFormula::gatherUsedVariables(usedVariables); + if (this->hasBound()) { + this->getThreshold().gatherVariables(usedVariables); + } + } + std::ostream& OperatorFormula::writeToStream(std::ostream& out) const { if (hasOptimalityType()) { out << (getOptimalityType() == OptimizationDirection::Minimize ? "min" : "max"); diff --git a/src/storm/logic/OperatorFormula.h b/src/storm/logic/OperatorFormula.h index 502cfaec6..a396f21ac 100644 --- a/src/storm/logic/OperatorFormula.h +++ b/src/storm/logic/OperatorFormula.h @@ -49,6 +49,8 @@ namespace storm { virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual std::ostream& writeToStream(std::ostream& out) const override; protected: diff --git a/src/storm/logic/RewardAccumulation.cpp b/src/storm/logic/RewardAccumulation.cpp new file mode 100644 index 000000000..4a4ba4366 --- /dev/null +++ b/src/storm/logic/RewardAccumulation.cpp @@ -0,0 +1,51 @@ +#include "storm/logic/RewardAccumulation.h" + +namespace storm { + namespace logic { + + RewardAccumulation::RewardAccumulation(bool steps, bool time, bool exit) : time(time), steps(steps), exit(exit){ + // Intentionally left empty + } + + bool RewardAccumulation::isStepsSet() const { + return steps; + } + + bool RewardAccumulation::isTimeSet() const { + return time; + } + + bool RewardAccumulation::isExitSet() const { + return exit; + } + + bool RewardAccumulation::isEmpty() const { + return !isStepsSet() && !isTimeSet() && !isExitSet(); + } + + std::ostream& operator<<(std::ostream& out, RewardAccumulation const& acc) { + bool hasEntry = false; + if (acc.isStepsSet()) { + out << "steps"; + hasEntry = true; + } + if (acc.isTimeSet()) { + if (hasEntry) { + out << ", "; + } + out << "time"; + hasEntry = true; + } + if (acc.isExitSet()) { + if (hasEntry) { + out << ", "; + } + out << "exit"; + hasEntry = true; + } + + return out; + } + + } +} diff --git a/src/storm/logic/RewardAccumulation.h b/src/storm/logic/RewardAccumulation.h new file mode 100644 index 000000000..4f8a50b29 --- /dev/null +++ b/src/storm/logic/RewardAccumulation.h @@ -0,0 +1,27 @@ +#pragma once +#include + +namespace storm { + namespace logic { + + class RewardAccumulation { + public: + RewardAccumulation(bool steps, bool time, bool exit); + RewardAccumulation(RewardAccumulation const& other) = default; + + bool isStepsSet() const; // If set, choice rewards and transition rewards are accumulated upon taking the transition + bool isTimeSet() const; // If set, state rewards are accumulated over time (assuming 0 time passes in discrete-time model states) + bool isExitSet() const; // If set, state rewards are accumulated upon exiting the state + + // Returns true iff accumulation for all types of reward is disabled. + bool isEmpty() const; + + private: + bool time, steps, exit; + }; + + std::ostream& operator<<(std::ostream& out, RewardAccumulation const& acc); + + } +} + diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.cpp b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp new file mode 100644 index 000000000..34f911da7 --- /dev/null +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.cpp @@ -0,0 +1,157 @@ +#include "storm/logic/RewardAccumulationEliminationVisitor.h" +#include "storm/logic/Formulas.h" + +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/traverser/AssignmentsFinder.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/InvalidPropertyException.h" + +namespace storm { + namespace logic { + + RewardAccumulationEliminationVisitor::RewardAccumulationEliminationVisitor(storm::jani::Model const& model) : model(model) { + // Intentionally left empty + } + + std::shared_ptr RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(Formula const& f) const { + boost::any result = f.accept(*this, boost::any()); + return boost::any_cast>(result); + } + + void RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(std::vector& properties) const { + for (auto& p : properties) { + eliminateRewardAccumulations(p); + } + } + + void RewardAccumulationEliminationVisitor::eliminateRewardAccumulations(storm::jani::Property& property) const { + auto formula = eliminateRewardAccumulations(*property.getFilter().getFormula()); + auto states = eliminateRewardAccumulations(*property.getFilter().getStatesFormula()); + storm::jani::FilterExpression fe(formula, property.getFilter().getFilterType(), states); + property = storm::jani::Property(property.getName(), storm::jani::FilterExpression(formula, property.getFilter().getFilterType(), states), property.getUndefinedConstants(), property.getComment()); + } + + boost::any RewardAccumulationEliminationVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + std::vector> lowerBounds, upperBounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + if (f.hasLowerBound(i)) { + lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), f.getLowerBound(i))); + } else { + lowerBounds.emplace_back(); + } + if (f.hasUpperBound(i)) { + upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), f.getUpperBound(i))); + } else { + upperBounds.emplace_back(); + } + storm::logic::TimeBoundReference tbr = f.getTimeBoundReference(i); + if (tbr.hasRewardAccumulation() && canEliminate(tbr.getRewardAccumulation(), tbr.getRewardName())) { + // Eliminate accumulation + tbr = storm::logic::TimeBoundReference(tbr.getRewardName(), boost::none); + } + timeBoundReferences.push_back(std::move(tbr)); + } + if (f.hasMultiDimensionalSubformulas()) { + std::vector> leftSubformulas, rightSubformulas; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + leftSubformulas.push_back(boost::any_cast>(f.getLeftSubformula(i).accept(*this, data))); + rightSubformulas.push_back(boost::any_cast>(f.getRightSubformula(i).accept(*this, data))); + } + return std::static_pointer_cast(std::make_shared(leftSubformulas, rightSubformulas, lowerBounds, upperBounds, timeBoundReferences)); + } else { + std::shared_ptr left = boost::any_cast>(f.getLeftSubformula().accept(*this, data)); + std::shared_ptr right = boost::any_cast>(f.getRightSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(left, right, lowerBounds, upperBounds, timeBoundReferences)); + } + } + + boost::any RewardAccumulationEliminationVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + boost::optional rewAcc; + STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); + auto rewName = boost::any_cast>(data); + if (f.hasRewardAccumulation() && !canEliminate(f.getRewardAccumulation(), rewName)) { + rewAcc = f.getRewardAccumulation(); + } + + std::vector bounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + bounds.emplace_back(TimeBound(f.isBoundStrict(i), f.getBound(i))); + storm::logic::TimeBoundReference tbr = f.getTimeBoundReference(i); + if (tbr.hasRewardAccumulation() && canEliminate(tbr.getRewardAccumulation(), tbr.getRewardName())) { + // Eliminate accumulation + tbr = storm::logic::TimeBoundReference(tbr.getRewardName(), boost::none); + } + timeBoundReferences.push_back(std::move(tbr)); + } + return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences, rewAcc)); + } + + boost::any RewardAccumulationEliminationVisitor::visit(EventuallyFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + if (f.hasRewardAccumulation()) { + if (f.isTimePathFormula()) { + if (model.isDiscreteTimeModel() && ((!f.getRewardAccumulation().isExitSet() && !f.getRewardAccumulation().isStepsSet()) || (f.getRewardAccumulation().isStepsSet() && f.getRewardAccumulation().isExitSet()))) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } else if (!model.isDiscreteTimeModel() && (!f.getRewardAccumulation().isTimeSet() || f.getRewardAccumulation().isExitSet() || f.getRewardAccumulation().isStepsSet())) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } + } else if (f.isRewardPathFormula()) { + STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); + auto rewName = boost::any_cast>(data); + if (!canEliminate(f.getRewardAccumulation(), rewName)) { + return std::static_pointer_cast(std::make_shared(subformula, f.getContext(), f.getRewardAccumulation())); + } + } + } + return std::static_pointer_cast(std::make_shared(subformula, f.getContext())); + } + + boost::any RewardAccumulationEliminationVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, f.getOptionalRewardModelName())); + return std::static_pointer_cast(std::make_shared(subformula, f.getOptionalRewardModelName(), f.getOperatorInformation())); + } + + boost::any RewardAccumulationEliminationVisitor::visit(TotalRewardFormula const& f, boost::any const& data) const { + STORM_LOG_THROW(!data.empty(), storm::exceptions::UnexpectedException, "Formula " << f << " does not seem to be a subformula of a reward operator."); + auto rewName = boost::any_cast>(data); + if (!f.hasRewardAccumulation() || canEliminate(f.getRewardAccumulation(), rewName)) { + return std::static_pointer_cast(std::make_shared()); + } else { + return std::static_pointer_cast(std::make_shared(f.getRewardAccumulation())); + } + } + + bool RewardAccumulationEliminationVisitor::canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const { + STORM_LOG_THROW(rewardModelName.is_initialized(), storm::exceptions::InvalidPropertyException, "Unable to find transient variable with for unique reward model."); + storm::jani::AssignmentsFinder::ResultType assignmentKinds; + STORM_LOG_THROW(model.hasGlobalVariable(rewardModelName.get()), storm::exceptions::InvalidPropertyException, "Unable to find transient variable with name " << rewardModelName.get() << "."); + storm::jani::Variable const& transientVar = model.getGlobalVariable(rewardModelName.get()); + if (transientVar.getInitExpression().containsVariables() || !storm::utility::isZero(transientVar.getInitExpression().evaluateAsRational())) { + assignmentKinds.hasLocationAssignment = true; + assignmentKinds.hasEdgeAssignment = true; + assignmentKinds.hasEdgeDestinationAssignment = true; + } + assignmentKinds = storm::jani::AssignmentsFinder().find(model, transientVar); + if ((assignmentKinds.hasEdgeAssignment || assignmentKinds.hasEdgeDestinationAssignment) && !accumulation.isStepsSet()) { + return false; + } + if (assignmentKinds.hasLocationAssignment) { + if (model.isDiscreteTimeModel()) { + if (!accumulation.isExitSet()) { + return false; + } + // accumulating over time in discrete time models has no effect, i.e., the value of accumulation.isTimeSet() does not matter here. + } else { + if (accumulation.isExitSet() || !accumulation.isTimeSet()) { + return false; + } + } + } + return true; + } + } +} diff --git a/src/storm/logic/RewardAccumulationEliminationVisitor.h b/src/storm/logic/RewardAccumulationEliminationVisitor.h new file mode 100644 index 000000000..59dbc330d --- /dev/null +++ b/src/storm/logic/RewardAccumulationEliminationVisitor.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include "storm/logic/CloneVisitor.h" +#include "storm/logic/RewardAccumulation.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + +namespace storm { + namespace logic { + + class RewardAccumulationEliminationVisitor : public CloneVisitor { + public: + RewardAccumulationEliminationVisitor(storm::jani::Model const& model); + + /*! + * Eliminates any reward accumulations of the formula, where the presence of the reward accumulation does not change the result of the formula + */ + std::shared_ptr eliminateRewardAccumulations(Formula const& f) const; + + void eliminateRewardAccumulations(std::vector& properties) const; + void eliminateRewardAccumulations(storm::jani::Property& property) const; + + virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; + virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(EventuallyFormula const& f, boost::any const& data) const override; + virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override; + virtual boost::any visit(TotalRewardFormula const& f, boost::any const& data) const override; + + + private: + bool canEliminate(storm::logic::RewardAccumulation const& accumulation, boost::optional rewardModelName) const; + + storm::jani::Model const& model; + }; + + } +} diff --git a/src/storm/logic/RewardModelNameSubstitutionVisitor.cpp b/src/storm/logic/RewardModelNameSubstitutionVisitor.cpp new file mode 100644 index 000000000..314e6c74d --- /dev/null +++ b/src/storm/logic/RewardModelNameSubstitutionVisitor.cpp @@ -0,0 +1,96 @@ +#include "storm/logic/RewardModelNameSubstitutionVisitor.h" +#include "storm/logic/Formulas.h" + +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/traverser/AssignmentsFinder.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/InvalidPropertyException.h" + +namespace storm { + namespace logic { + + RewardModelNameSubstitutionVisitor::RewardModelNameSubstitutionVisitor(std::map const& rewardModelNameMapping) : rewardModelNameMapping(rewardModelNameMapping) { + // Intentionally left empty + } + + std::shared_ptr RewardModelNameSubstitutionVisitor::substitute(Formula const& f) const { + boost::any result = f.accept(*this, boost::any()); + return boost::any_cast>(result); + } + + boost::any RewardModelNameSubstitutionVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const { + std::vector> lowerBounds, upperBounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + if (f.hasLowerBound(i)) { + lowerBounds.emplace_back(TimeBound(f.isLowerBoundStrict(i), f.getLowerBound(i))); + } else { + lowerBounds.emplace_back(); + } + if (f.hasUpperBound(i)) { + upperBounds.emplace_back(TimeBound(f.isUpperBoundStrict(i), f.getUpperBound(i))); + } else { + upperBounds.emplace_back(); + } + auto const& tbr = f.getTimeBoundReference(i); + if (tbr.isRewardBound()) { + timeBoundReferences.emplace_back(getNewName(tbr.getRewardName()), tbr.getOptionalRewardAccumulation()); + } else { + timeBoundReferences.push_back(tbr); + } + } + if (f.hasMultiDimensionalSubformulas()) { + std::vector> leftSubformulas, rightSubformulas; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + leftSubformulas.push_back(boost::any_cast>(f.getLeftSubformula(i).accept(*this, data))); + rightSubformulas.push_back(boost::any_cast>(f.getRightSubformula(i).accept(*this, data))); + } + return std::static_pointer_cast(std::make_shared(leftSubformulas, rightSubformulas, lowerBounds, upperBounds, timeBoundReferences)); + } else { + std::shared_ptr left = boost::any_cast>(f.getLeftSubformula().accept(*this, data)); + std::shared_ptr right = boost::any_cast>(f.getRightSubformula().accept(*this, data)); + return std::static_pointer_cast(std::make_shared(left, right, lowerBounds, upperBounds, timeBoundReferences)); + } + } + + boost::any RewardModelNameSubstitutionVisitor::visit(CumulativeRewardFormula const& f, boost::any const& data) const { + std::vector bounds; + std::vector timeBoundReferences; + for (uint64_t i = 0; i < f.getDimension(); ++i) { + bounds.emplace_back(TimeBound(f.isBoundStrict(i), f.getBound(i))); + storm::logic::TimeBoundReference tbr = f.getTimeBoundReference(i); + if (tbr.isRewardBound()) { + tbr = storm::logic::TimeBoundReference(getNewName(tbr.getRewardName()), tbr.getOptionalRewardAccumulation()); + } + timeBoundReferences.push_back(std::move(tbr)); + } + if (f.hasRewardAccumulation()) { + return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences, f.getRewardAccumulation())); + } else { + return std::static_pointer_cast(std::make_shared(bounds, timeBoundReferences)); + } + } + + boost::any RewardModelNameSubstitutionVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const { + std::shared_ptr subformula = boost::any_cast>(f.getSubformula().accept(*this, data)); + if (f.hasRewardModelName()) { + return std::static_pointer_cast(std::make_shared(subformula, getNewName(f.getRewardModelName()), f.getOperatorInformation())); + } else { + return std::static_pointer_cast(std::make_shared(subformula, boost::none, f.getOperatorInformation())); + } + } + + std::string const& RewardModelNameSubstitutionVisitor::getNewName(std::string const& oldName) const { + auto nameIt = rewardModelNameMapping.find(oldName); + if (nameIt == rewardModelNameMapping.end()) { + return oldName; + } else { + return nameIt->second; + } + } + + + } +} diff --git a/src/storm/logic/RewardModelNameSubstitutionVisitor.h b/src/storm/logic/RewardModelNameSubstitutionVisitor.h new file mode 100644 index 000000000..759238738 --- /dev/null +++ b/src/storm/logic/RewardModelNameSubstitutionVisitor.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "storm/logic/CloneVisitor.h" + +#include "storm/storage/expressions/Expression.h" + +namespace storm { + namespace logic { + + class RewardModelNameSubstitutionVisitor : public CloneVisitor { + public: + RewardModelNameSubstitutionVisitor(std::map const& rewardModelNameMapping); + + std::shared_ptr substitute(Formula const& f) const; + + virtual boost::any visit(BoundedUntilFormula const& f, boost::any const& data) const override; + virtual boost::any visit(CumulativeRewardFormula const& f, boost::any const& data) const override; + virtual boost::any visit(RewardOperatorFormula const& f, boost::any const& data) const override; + + private: + + std::string const& getNewName(std::string const& oldName) const; + + std::map const& rewardModelNameMapping; + }; + + } +} diff --git a/src/storm/logic/TimeBoundType.h b/src/storm/logic/TimeBoundType.h index 0bd6aba0c..149f76215 100644 --- a/src/storm/logic/TimeBoundType.h +++ b/src/storm/logic/TimeBoundType.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include "storm/logic/RewardAccumulation.h" + namespace storm { namespace logic { @@ -13,14 +17,15 @@ namespace storm { class TimeBoundReference { TimeBoundType type; std::string rewardName; - + boost::optional rewardAccumulation; + public: explicit TimeBoundReference(TimeBoundType t) : type(t) { // For rewards, use the other constructor. assert(t != TimeBoundType::Reward); } - explicit TimeBoundReference(std::string const& rewardName) : type(TimeBoundType::Reward), rewardName(rewardName) { + explicit TimeBoundReference(std::string const& rewardName, boost::optional rewardAccumulation = boost::none) : type(TimeBoundType::Reward), rewardName(rewardName), rewardAccumulation(rewardAccumulation) { assert(rewardName != ""); // Empty reward name is reserved. } @@ -44,6 +49,21 @@ namespace storm { assert(isRewardBound()); return rewardName; } + + bool hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& getRewardAccumulation() const { + assert(isRewardBound()); + return rewardAccumulation.get(); + } + + boost::optional const& getOptionalRewardAccumulation() const { + assert(isRewardBound()); + return rewardAccumulation; + } + }; diff --git a/src/storm/logic/TimeOperatorFormula.cpp b/src/storm/logic/TimeOperatorFormula.cpp index 7ae4b7fea..f32568cdc 100644 --- a/src/storm/logic/TimeOperatorFormula.cpp +++ b/src/storm/logic/TimeOperatorFormula.cpp @@ -1,5 +1,5 @@ #include "storm/logic/TimeOperatorFormula.h" - +#include "storm/logic/EventuallyFormula.h" #include "storm/logic/FormulaVisitor.h" #include "storm/utility/macros.h" @@ -8,6 +8,7 @@ namespace storm { namespace logic { TimeOperatorFormula::TimeOperatorFormula(std::shared_ptr const& subformula, OperatorInformation const& operatorInformation, RewardMeasureType rewardMeasureType) : OperatorFormula(subformula, operatorInformation), rewardMeasureType(rewardMeasureType) { + assert(subformula->isTimePathFormula()); // Intentionally left empty. } diff --git a/src/storm/logic/TotalRewardFormula.cpp b/src/storm/logic/TotalRewardFormula.cpp index 18c79cd67..6136581a3 100644 --- a/src/storm/logic/TotalRewardFormula.cpp +++ b/src/storm/logic/TotalRewardFormula.cpp @@ -4,7 +4,7 @@ namespace storm { namespace logic { - TotalRewardFormula::TotalRewardFormula() { + TotalRewardFormula::TotalRewardFormula(boost::optional rewardAccumulation) : rewardAccumulation(rewardAccumulation) { // Intentionally left empty. } @@ -16,6 +16,14 @@ namespace storm { return true; } + bool TotalRewardFormula::hasRewardAccumulation() const { + return rewardAccumulation.is_initialized(); + } + + RewardAccumulation const& TotalRewardFormula::getRewardAccumulation() const { + return rewardAccumulation.get(); + } + boost::any TotalRewardFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const { return visitor.visit(*this, data); } diff --git a/src/storm/logic/TotalRewardFormula.h b/src/storm/logic/TotalRewardFormula.h index 90caee9e7..a11fb3b03 100644 --- a/src/storm/logic/TotalRewardFormula.h +++ b/src/storm/logic/TotalRewardFormula.h @@ -1,15 +1,16 @@ #ifndef STORM_LOGIC_TOTALREWARDFORMULA_H_ #define STORM_LOGIC_TOTALREWARDFORMULA_H_ -#include +#include +#include "storm/logic/RewardAccumulation.h" #include "storm/logic/PathFormula.h" namespace storm { namespace logic { class TotalRewardFormula : public PathFormula { public: - TotalRewardFormula(); + TotalRewardFormula(boost::optional rewardAccumulation = boost::none); virtual ~TotalRewardFormula() { // Intentionally left empty. @@ -17,11 +18,15 @@ namespace storm { virtual bool isTotalRewardFormula() const override; virtual bool isRewardPathFormula() const override; - + bool hasRewardAccumulation() const; + RewardAccumulation const& getRewardAccumulation() const; + virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override; virtual std::ostream& writeToStream(std::ostream& out) const override; - + + private: + boost::optional rewardAccumulation; }; } } diff --git a/src/storm/logic/UnaryPathFormula.cpp b/src/storm/logic/UnaryPathFormula.cpp index fd9dd6ae8..6f3404d4f 100644 --- a/src/storm/logic/UnaryPathFormula.cpp +++ b/src/storm/logic/UnaryPathFormula.cpp @@ -26,6 +26,10 @@ namespace storm { this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); } + void UnaryPathFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getSubformula().gatherUsedVariables(usedVariables); + } + bool UnaryPathFormula::hasQualitativeResult() const { return false; } diff --git a/src/storm/logic/UnaryPathFormula.h b/src/storm/logic/UnaryPathFormula.h index d1fd8e2c9..b78c3d6a3 100644 --- a/src/storm/logic/UnaryPathFormula.h +++ b/src/storm/logic/UnaryPathFormula.h @@ -22,7 +22,8 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; - + virtual void gatherUsedVariables(std::set& usedVariables) const override; + virtual bool hasQualitativeResult() const override; virtual bool hasQuantitativeResult() const override; diff --git a/src/storm/logic/UnaryStateFormula.cpp b/src/storm/logic/UnaryStateFormula.cpp index e46d3f345..b253ead87 100644 --- a/src/storm/logic/UnaryStateFormula.cpp +++ b/src/storm/logic/UnaryStateFormula.cpp @@ -27,6 +27,10 @@ namespace storm { void UnaryStateFormula::gatherReferencedRewardModels(std::set& referencedRewardModels) const { this->getSubformula().gatherReferencedRewardModels(referencedRewardModels); } + + void UnaryStateFormula::gatherUsedVariables(std::set& usedVariables) const { + this->getSubformula().gatherUsedVariables(usedVariables); + } } } diff --git a/src/storm/logic/UnaryStateFormula.h b/src/storm/logic/UnaryStateFormula.h index ae26700a2..490e15d3d 100644 --- a/src/storm/logic/UnaryStateFormula.h +++ b/src/storm/logic/UnaryStateFormula.h @@ -20,6 +20,7 @@ namespace storm { virtual void gatherAtomicExpressionFormulas(std::vector>& atomicExpressionFormulas) const override; virtual void gatherAtomicLabelFormulas(std::vector>& atomicLabelFormulas) const override; virtual void gatherReferencedRewardModels(std::set& referencedRewardModels) const override; + virtual void gatherUsedVariables(std::set& usedVariables) const override; private: std::shared_ptr subformula; diff --git a/src/storm/modelchecker/AbstractModelChecker.cpp b/src/storm/modelchecker/AbstractModelChecker.cpp index 2712b6d4a..42bb2a753 100644 --- a/src/storm/modelchecker/AbstractModelChecker.cpp +++ b/src/storm/modelchecker/AbstractModelChecker.cpp @@ -24,9 +24,16 @@ #include "storm/storage/dd/Add.h" #include "storm/storage/dd/Bdd.h" +#include + namespace storm { namespace modelchecker { + template + std::string AbstractModelChecker::getClassName() const { + return std::string(boost::core::demangled_name(BOOST_CORE_TYPEID(*this))); + } + template std::unique_ptr AbstractModelChecker::check(CheckTask const& checkTask) { Environment env; @@ -36,7 +43,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::check(Environment const& env, CheckTask const& checkTask) { storm::logic::Formula const& formula = checkTask.getFormula(); - STORM_LOG_THROW(this->canHandle(checkTask), storm::exceptions::InvalidArgumentException, "The model checker is not able to check the formula '" << formula << "'."); + STORM_LOG_THROW(this->canHandle(checkTask), storm::exceptions::InvalidArgumentException, "The model checker (" << getClassName() << ") is not able to check the formula '" << formula << "'."); if (formula.isStateFormula()) { return this->checkStateFormula(env, checkTask.substituteFormula(formula.asStateFormula())); } else if (formula.isMultiObjectiveFormula()){ @@ -66,12 +73,12 @@ namespace storm { template std::unique_ptr AbstractModelChecker::computeBoundedUntilProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeConditionalProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -83,17 +90,17 @@ namespace storm { template std::unique_ptr AbstractModelChecker::computeGloballyProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeNextProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -105,6 +112,8 @@ namespace storm { return this->computeInstantaneousRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asInstantaneousRewardFormula())); } else if (rewardFormula.isReachabilityRewardFormula()) { return this->computeReachabilityRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asReachabilityRewardFormula())); + } else if (rewardFormula.isTotalRewardFormula()) { + return this->computeTotalRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asTotalRewardFormula())); } else if (rewardFormula.isLongRunAverageRewardFormula()) { return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula())); } else if (rewardFormula.isConditionalRewardFormula()) { @@ -115,32 +124,37 @@ namespace storm { template std::unique_ptr AbstractModelChecker::computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); + } + + template + std::unique_ptr AbstractModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -149,12 +163,12 @@ namespace storm { if (timeFormula.isReachabilityTimeFormula()) { return this->computeReachabilityTimes(env, rewardMeasureType, checkTask.substituteFormula(timeFormula.asReachabilityTimeFormula())); } - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template std::unique_ptr AbstractModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -194,7 +208,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::checkAtomicLabelFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -220,7 +234,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::checkBooleanLiteralFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } template @@ -294,7 +308,7 @@ namespace storm { template std::unique_ptr AbstractModelChecker::checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker does not support the formula: " << checkTask.getFormula() << "."); + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "This model checker (" << getClassName() << ") does not support the formula: " << checkTask.getFormula() << "."); } /////////////////////////////////////////////// diff --git a/src/storm/modelchecker/AbstractModelChecker.h b/src/storm/modelchecker/AbstractModelChecker.h index 0d391f1d9..44373de03 100644 --- a/src/storm/modelchecker/AbstractModelChecker.h +++ b/src/storm/modelchecker/AbstractModelChecker.h @@ -1,6 +1,7 @@ #ifndef STORM_MODELCHECKER_ABSTRACTMODELCHECKER_H_ #define STORM_MODELCHECKER_ABSTRACTMODELCHECKER_H_ +#include #include #include "storm/modelchecker/CheckTask.h" @@ -24,7 +25,12 @@ namespace storm { } typedef typename ModelType::ValueType ValueType; - + + /*! + * Returns the name of the model checker class (e.g., for display in error messages). + */ + virtual std::string getClassName() const; + /*! * Determines whether the model checker can handle the given verification task. If this method returns * false, the task must not be checked using this model checker. @@ -63,6 +69,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask); // The methods to compute the long-run average probabilities and timing measures. diff --git a/src/storm/modelchecker/CheckTask.h b/src/storm/modelchecker/CheckTask.h index 093c40ca8..45f2a9bc3 100644 --- a/src/storm/modelchecker/CheckTask.h +++ b/src/storm/modelchecker/CheckTask.h @@ -211,7 +211,7 @@ namespace storm { /*! * Sets whether to produce schedulers (if supported). */ - void setProduceSchedulers(bool produceSchedulers) { + void setProduceSchedulers(bool produceSchedulers = true) { this->produceSchedulers = produceSchedulers; } diff --git a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp index 81281a2cd..6e639a8b9 100644 --- a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.cpp @@ -25,9 +25,9 @@ #include "storm/abstraction/StateSet.h" #include "storm/abstraction/SymbolicStateSet.h" #include "storm/abstraction/QualitativeResultMinMax.h" -#include "storm/abstraction/QualitativeMdpResult.h" -#include "storm/abstraction/QualitativeMdpResultMinMax.h" -#include "storm/abstraction/QualitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeMdpResult.h" +#include "storm/abstraction/SymbolicQualitativeMdpResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/AbstractionSettings.h" @@ -332,12 +332,12 @@ namespace storm { } if (isRewardFormula) { - storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, abstractModel, abstractModel.getTransitionMatrix(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybe, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), storm::solver::GeneralSymbolicLinearEquationSolverFactory(), startValues); + storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, abstractModel, abstractModel.getTransitionMatrix(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybe, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), startValues); result.first = std::make_unique>(abstractModel.getReachableStates(), values); result.second = result.first->clone(); } else { - storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, abstractModel, abstractModel.getTransitionMatrix(), maybe, qualitativeResults.getProb1Min().getStates(), storm::solver::GeneralSymbolicLinearEquationSolverFactory(), startValues); + storm::dd::Add values = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, abstractModel, abstractModel.getTransitionMatrix(), maybe, qualitativeResults.getProb1Min().getStates(), startValues); result.first = std::make_unique>(abstractModel.getReachableStates(), values); result.second = result.first->clone(); @@ -371,20 +371,20 @@ namespace storm { uint64_t abstractionPlayer = this->getAbstractionPlayer(); if (isRewardFormula) { - result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), minStartValues); + result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), minStartValues); if (abstractionPlayer == 0) { result.second = result.first->clone(); } else { - result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Max().getStates() && abstractModel.getReachableStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); + result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(), checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin, targetStates.getStates(), !qualitativeResults.getProb1Max().getStates() && abstractModel.getReachableStates(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); } } else { - result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), maybeMin, qualitativeResults.getProb1Min().getStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), minStartValues); + result.first = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel, abstractModel.getTransitionMatrix(), maybeMin, qualitativeResults.getProb1Min().getStates(), minStartValues); if (abstractionPlayer == 0) { result.second = result.first->clone(); } else { - result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), maybeMax, qualitativeResults.getProb1Max().getStates(), storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); + result.second = storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), maybeMax, qualitativeResults.getProb1Max().getStates(), maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult().getValueVector(), abstractModel.getManager().template getAddZero())); } } @@ -470,31 +470,31 @@ namespace storm { template std::unique_ptr AbstractAbstractionRefinementModelChecker::computeQualitativeResult(Environment const& env, storm::models::symbolic::Dtmc const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates) { STORM_LOG_DEBUG("Computing qualitative solution for DTMC."); - std::unique_ptr> result = std::make_unique>(); + std::unique_ptr> result = std::make_unique>(); auto start = std::chrono::high_resolution_clock::now(); bool isRewardFormula = checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward; storm::dd::Bdd transitionMatrixBdd = abstractModel.getTransitionMatrix().notZero(); if (isRewardFormula) { auto prob1 = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob1Min = result->prob1Max = storm::abstraction::QualitativeMdpResult(prob1); + result->prob1Min = result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob1); } else { auto prob01 = storm::utility::graph::performProb01(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Min = result->prob0Max = storm::abstraction::QualitativeMdpResult(prob01.first); - result->prob1Min = result->prob1Max = storm::abstraction::QualitativeMdpResult(prob01.second); + result->prob0Min = result->prob0Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.first); + result->prob1Min = result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.second); } auto end = std::chrono::high_resolution_clock::now(); auto timeInMilliseconds = std::chrono::duration_cast(end - start).count(); STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms."); - return result; + return std::move(result); // move() required by, e.g., clang 3.8 } template std::unique_ptr AbstractAbstractionRefinementModelChecker::computeQualitativeResult(Environment const& env, storm::models::symbolic::Mdp const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates) { STORM_LOG_DEBUG("Computing qualitative solution for MDP."); - std::unique_ptr> result = std::make_unique>(); + std::unique_ptr> result = std::make_unique>(); auto start = std::chrono::high_resolution_clock::now(); bool isRewardFormula = checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward; @@ -505,13 +505,13 @@ namespace storm { bool computedMin = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto states = storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax().getProb1Min().getStates() : storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Min = storm::abstraction::QualitativeMdpResult(states); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(states); computedMin = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto states = storm::utility::graph::performProb1A(abstractModel, transitionMatrixBdd, targetStates.getStates(), storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Max = storm::abstraction::QualitativeMdpResult(states); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(states); if (!computedMin) { result->prob1Min = result->prob1Max; } @@ -523,18 +523,18 @@ namespace storm { bool computedMax = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto states = storm::utility::graph::performProb0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Max = storm::abstraction::QualitativeMdpResult(states); + result->prob0Max = storm::abstraction::SymbolicQualitativeMdpResult(states); states = storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax().getProb1Min().getStates() : storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Max = storm::abstraction::QualitativeMdpResult(states); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(states); computedMax = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto states = storm::utility::graph::performProb1A(abstractModel, transitionMatrixBdd, lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax().getProb1Min().getStates() : targetStates.getStates(), storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Min = storm::abstraction::QualitativeMdpResult(states); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(states); states = storm::utility::graph::performProb0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Min = storm::abstraction::QualitativeMdpResult(states); + result->prob0Min = storm::abstraction::SymbolicQualitativeMdpResult(states); if (!computedMax) { result->prob0Max = result->prob0Min; @@ -550,13 +550,13 @@ namespace storm { bool computedMin = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto prob1 = storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Min = storm::abstraction::QualitativeMdpResult(prob1); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(prob1); computedMin = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto prob1 = storm::utility::graph::performProb1A(abstractModel, transitionMatrixBdd, targetStates.getStates(), storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates())); - result->prob1Max = storm::abstraction::QualitativeMdpResult(prob1); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob1); if (!computedMin) { result->prob1Min = result->prob1Max; } @@ -567,15 +567,15 @@ namespace storm { bool computedMin = false; if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) { auto prob01 = storm::utility::graph::performProb01Min(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Min = storm::abstraction::QualitativeMdpResult(prob01.first); - result->prob1Min = storm::abstraction::QualitativeMdpResult(prob01.second); + result->prob0Min = storm::abstraction::SymbolicQualitativeMdpResult(prob01.first); + result->prob1Min = storm::abstraction::SymbolicQualitativeMdpResult(prob01.second); computedMin = true; } if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) { auto prob01 = storm::utility::graph::performProb01Max(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()); - result->prob0Max = storm::abstraction::QualitativeMdpResult(prob01.first); - result->prob1Max = storm::abstraction::QualitativeMdpResult(prob01.second); + result->prob0Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.first); + result->prob1Max = storm::abstraction::SymbolicQualitativeMdpResult(prob01.second); if (!computedMin) { result->prob0Min = result->prob0Max; result->prob1Min = result->prob1Max; @@ -598,13 +598,13 @@ namespace storm { } STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms."); - return result; + return std::move(result); // move() required by, e.g., clang 3.8 } template std::unique_ptr AbstractAbstractionRefinementModelChecker::computeQualitativeResult(Environment const& env, storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates) { STORM_LOG_DEBUG("Computing qualitative solution for S2PG."); - std::unique_ptr> result; + std::unique_ptr> result; // Obtain the player optimization directions. uint64_t abstractionPlayer = this->getAbstractionPlayer(); @@ -622,7 +622,7 @@ namespace storm { if (this->getReuseQualitativeResults()) { result = computeQualitativeResultReuse(abstractModel, transitionMatrixBdd, constraintStates, targetStates, abstractionPlayer, modelNondeterminismDirection, requiresSchedulers); } else { - result = std::make_unique>(); + result = std::make_unique>(); result->prob0Min = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, requiresSchedulers, requiresSchedulers); result->prob1Min = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection, requiresSchedulers, requiresSchedulers); @@ -644,12 +644,12 @@ namespace storm { auto timeInMilliseconds = std::chrono::duration_cast(end - start).count(); STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms."); - return result; + return std::move(result); // move() required by, e.g., clang 3.8 } template - std::unique_ptr::DdType>> AbstractAbstractionRefinementModelChecker::computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers) { - std::unique_ptr> result = std::make_unique>(); + std::unique_ptr::DdType>> AbstractAbstractionRefinementModelChecker::computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers) { + std::unique_ptr> result = std::make_unique>(); // Depending on the model nondeterminism direction, we choose a different order of operations. if (modelNondeterminismDirection == storm::OptimizationDirection::Minimize) { diff --git a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h index 5fdabe05e..83a2d35a6 100644 --- a/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h +++ b/src/storm/modelchecker/abstraction/AbstractAbstractionRefinementModelChecker.h @@ -41,10 +41,10 @@ namespace storm { class SymbolicQualitativeResultMinMax; template - class QualitativeMdpResultMinMax; + class SymbolicQualitativeMdpResultMinMax; template - class QualitativeGameResultMinMax; + class SymbolicQualitativeGameResultMinMax; class StateSet; @@ -124,7 +124,7 @@ namespace storm { std::unique_ptr computeQualitativeResult(Environment const& env, storm::models::symbolic::Dtmc const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(Environment const& env, storm::models::symbolic::Mdp const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); std::unique_ptr computeQualitativeResult(Environment const& env, storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates); - std::unique_ptr> computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers); + std::unique_ptr> computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame const& abstractModel, storm::dd::Bdd const& transitionMatrixBdd, storm::abstraction::SymbolicStateSet const& constraintStates, storm::abstraction::SymbolicStateSet const& targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers); std::unique_ptr checkForResultAfterQualitativeCheck(storm::models::Model const& abstractModel); std::unique_ptr checkForResultAfterQualitativeCheck(storm::models::symbolic::Model const& abstractModel); diff --git a/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h b/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h index 9af7c3a8b..4fe5af95f 100644 --- a/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h +++ b/src/storm/modelchecker/abstraction/BisimulationAbstractionRefinementModelChecker.h @@ -11,7 +11,7 @@ namespace storm { } namespace dd { - template + template class BisimulationDecomposition; } @@ -47,7 +47,7 @@ namespace storm { ModelType const& model; /// The bisimulation object that maintains and refines the model. - std::unique_ptr> bisimulation; + std::unique_ptr> bisimulation; /// Maintains the last abstract model that was returned. std::shared_ptr> lastAbstractModel; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index 36af17be0..b9623a5ee 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -2,6 +2,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" +#include "storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" #include "storm/models/symbolic/StandardRewardModel.h" #include "storm/models/symbolic/Dtmc.h" @@ -10,7 +11,6 @@ #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/VariableSetPredicateSplitter.h" - #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/EdgeDestination.h" #include "storm/storage/jani/Model.h" @@ -25,14 +25,20 @@ #include "storm/abstraction/prism/PrismMenuGameAbstractor.h" #include "storm/abstraction/jani/JaniMenuGameAbstractor.h" #include "storm/abstraction/MenuGameRefiner.h" +#include "storm/abstraction/ExplicitGameStrategyPair.h" + +#include "storm/abstraction/ExplicitQualitativeGameResultMinMax.h" +#include "storm/abstraction/ExplicitQuantitativeResultMinMax.h" #include "storm/logic/FragmentSpecification.h" #include "storm/solver/SymbolicGameSolver.h" +#include "storm/solver/StandardGameSolver.h" +#include "storm/environment/Environment.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/CoreSettings.h" -#include "storm/settings/modules/AbstractionSettings.h" +#include "storm/settings/modules/GeneralSettings.h" #include "storm/utility/prism.h" #include "storm/utility/macros.h" @@ -46,23 +52,40 @@ namespace storm { namespace modelchecker { - using storm::abstraction::QuantitativeGameResult; - using storm::abstraction::QuantitativeGameResultMinMax; - + using storm::abstraction::SymbolicQuantitativeGameResult; + using storm::abstraction::SymbolicQuantitativeGameResultMinMax; + using storm::abstraction::ExplicitQuantitativeResult; + using storm::abstraction::ExplicitQuantitativeResultMinMax; + using storm::abstraction::ExplicitGameStrategyPair; + using detail::PreviousExplicitResult; + template - GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory) : smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision()), reuseQualitativeResults(false), reuseQuantitativeResults(false) { - model.requireNoUndefinedConstants(); + GameBasedMdpModelChecker::GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, GameBasedMdpModelCheckerOptions const& options, std::shared_ptr const& smtSolverFactory) : options(options), smtSolverFactory(smtSolverFactory), comparator(storm::settings::getModule().getPrecision(), storm::settings::getModule().getRelativeTerminationCriterion()), reuseQualitativeResults(false), reuseQuantitativeResults(false), solveMode(storm::settings::getModule().getSolveMode()), debug(storm::settings::getModule().isDebugSet()) { + + if (model.hasUndefinedConstants()) { + auto undefinedConstants = model.getUndefinedConstants(); + std::vector undefinedConstantNames; + for (auto undefinedConstant : undefinedConstants) { + undefinedConstantNames.emplace_back(undefinedConstant.getName()); + } + + STORM_LOG_WARN_COND(!model.hasUndefinedConstants(), "Model contains undefined constants (" << boost::algorithm::join(undefinedConstantNames, ",") << "). Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these constants. In particular, it may be necessary to constrain the values of the undefined constants."); + } + if (model.isPrismProgram()) { storm::prism::Program const& originalProgram = model.asPrismProgram(); STORM_LOG_THROW(originalProgram.getModelType() == storm::prism::Program::ModelType::DTMC || originalProgram.getModelType() == storm::prism::Program::ModelType::MDP, storm::exceptions::NotSupportedException, "Currently only DTMCs/MDPs are supported by the game-based model checker."); + auto flattenStart = std::chrono::high_resolution_clock::now(); // Flatten the modules if there is more than one. if (originalProgram.getNumberOfModules() > 1) { - preprocessedModel = originalProgram.flattenModules(this->smtSolverFactory); + preprocessedModel = originalProgram.substituteFormulas().flattenModules(this->smtSolverFactory); } else { preprocessedModel = originalProgram; } - + auto flattenEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_INFO("Flattened model in " << std::chrono::duration_cast(flattenEnd - flattenStart).count() << "ms."); + STORM_LOG_TRACE("Game-based model checker got program " << preprocessedModel.asPrismProgram()); } else { storm::jani::Model const& originalModel = model.asJaniModel(); @@ -72,20 +95,24 @@ namespace storm { preprocessedModel = model.asJaniModel().flattenComposition(); } - storm::settings::modules::AbstractionSettings::ReuseMode reuseMode = storm::settings::getModule().getReuseMode(); + auto const& abstractionSettings = storm::settings::getModule(); + storm::settings::modules::AbstractionSettings::ReuseMode reuseMode = abstractionSettings.getReuseMode(); reuseQualitativeResults = reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::All || reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::Qualitative; reuseQuantitativeResults = reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::All || reuseMode == storm::settings::modules::AbstractionSettings::ReuseMode::Quantitative; + maximalNumberOfAbstractions = abstractionSettings.getMaximalAbstractionCount(); + fixPlayer1Strategy = abstractionSettings.isFixPlayer1StrategySet(); + fixPlayer2Strategy = abstractionSettings.isFixPlayer2StrategySet(); } template - bool GameBasedMdpModelChecker::canHandle(CheckTask const& checkTask) const { + bool GameBasedMdpModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); storm::logic::FragmentSpecification fragment = storm::logic::reachability(); return formula.isInFragment(fragment) && checkTask.isOnlyInitialStatesRelevantSet(); } template - std::unique_ptr GameBasedMdpModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { + std::unique_ptr GameBasedMdpModelChecker::computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::UntilFormula const& pathFormula = checkTask.getFormula(); std::map labelToExpressionMapping; if (preprocessedModel.isPrismProgram()) { @@ -102,11 +129,11 @@ namespace storm { storm::expressions::Expression constraintExpression = pathFormula.getLeftSubformula().toExpression(preprocessedModel.getManager(), labelToExpressionMapping); storm::expressions::Expression targetStateExpression = pathFormula.getRightSubformula().toExpression(preprocessedModel.getManager(), labelToExpressionMapping); - return performGameBasedAbstractionRefinement(env, checkTask.substituteFormula(pathFormula), constraintExpression, targetStateExpression); + return performGameBasedAbstractionRefinement(env, checkTask.template substituteFormula(pathFormula), constraintExpression, targetStateExpression); } template - std::unique_ptr GameBasedMdpModelChecker::computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) { + std::unique_ptr GameBasedMdpModelChecker::computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::EventuallyFormula const& pathFormula = checkTask.getFormula(); std::map labelToExpressionMapping; if (preprocessedModel.isPrismProgram()) { @@ -123,15 +150,15 @@ namespace storm { storm::expressions::Expression constraintExpression = preprocessedModel.getManager().boolean(true); storm::expressions::Expression targetStateExpression = pathFormula.getSubformula().toExpression(preprocessedModel.getManager(), labelToExpressionMapping); - return performGameBasedAbstractionRefinement(env, checkTask.substituteFormula(pathFormula), constraintExpression, targetStateExpression); + return performGameBasedAbstractionRefinement(env, checkTask.template substituteFormula(pathFormula), constraintExpression, targetStateExpression); } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& prob0, storm::dd::Bdd const& prob1) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& prob0, storm::dd::Bdd const& prob1) { std::unique_ptr result; if (checkTask.isBoundSet()) { - // Despite having a bound, we create a quanitative result so that the next layer can perform the comparison. + // Despite having a bound, we create a quantitative result so that the next layer can perform the comparison. if (player2Direction == storm::OptimizationDirection::Minimize) { if (storm::logic::isLowerBound(checkTask.getBoundComparisonType())) { @@ -154,13 +181,19 @@ namespace storm { } } } + } else { + if (player2Direction == storm::OptimizationDirection::Minimize && (prob1 && initialStates) == initialStates) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } else if (player2Direction == storm::OptimizationDirection::Maximize && (prob0 && initialStates) == initialStates) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } } return result; } template - std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::dd::Bdd const& initialStates, QualitativeGameResultMinMax const& qualitativeResult) { + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::dd::Bdd const& initialStates, SymbolicQualitativeGameResultMinMax const& qualitativeResult) { // Check whether we can already give the answer based on the current information. std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Minimize, initialStates, qualitativeResult.prob0Min.getPlayer1States(), qualitativeResult.prob1Min.getPlayer1States()); if (result) { @@ -172,9 +205,62 @@ namespace storm { } return result; } + + template + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection player2Direction, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& prob0, storm::storage::BitVector const& prob1) { + std::unique_ptr result; + + if (checkTask.isBoundSet()) { + // Despite having a bound, we create a quantitative result so that the next layer can perform the comparison. + + if (player2Direction == storm::OptimizationDirection::Minimize) { + if (storm::logic::isLowerBound(checkTask.getBoundComparisonType())) { + if (initialStates.isSubsetOf(prob1)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } + } else { + if (!initialStates.isDisjointFrom(prob1)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } + } + } else if (player2Direction == storm::OptimizationDirection::Maximize) { + if (!storm::logic::isLowerBound(checkTask.getBoundComparisonType())) { + if (initialStates.isSubsetOf(prob0)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } + } else { + if (!initialStates.isDisjointFrom(prob0)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } + } + } + } else { + if (player2Direction == storm::OptimizationDirection::Minimize && initialStates.isSubsetOf(prob1)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::one()); + } else if (player2Direction == storm::OptimizationDirection::Maximize && initialStates.isSubsetOf(prob0)) { + result = std::make_unique>(storm::storage::sparse::state_type(0), storm::utility::zero()); + } + } + + return result; + } + + template + std::unique_ptr checkForResultAfterQualitativeCheck(CheckTask const& checkTask, storm::storage::BitVector const& initialStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult) { + // Check whether we can already give the answer based on the current information. + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Minimize, initialStates, qualitativeResult.prob0Min.getPlayer1States(), qualitativeResult.prob1Min.getPlayer1States()); + if (result) { + return result; + } + result = checkForResultAfterQualitativeCheck(checkTask, storm::OptimizationDirection::Maximize, initialStates, qualitativeResult.prob0Max.getPlayer1States(), qualitativeResult.prob1Max.getPlayer1States()); + if (result) { + return result; + } + return result; + } template - std::unique_ptr checkForResultAfterQuantitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection const& player2Direction, std::pair const& initialValueRange) { + std::unique_ptr checkForResultAfterQuantitativeCheck(CheckTask const& checkTask, storm::OptimizationDirection const& player2Direction, std::pair const& initialValueRange) { std::unique_ptr result; // If the minimum value exceeds an upper threshold or the maximum value is below a lower threshold, we can @@ -233,7 +319,7 @@ namespace storm { } template - QuantitativeGameResult solveMaybeStates(Environment const& env, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& prob1States, boost::optional> const& startInfo = boost::none) { + SymbolicQuantitativeGameResult solveMaybeStates(Environment const& env, storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::MenuGame const& game, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& prob1States, boost::optional> const& startInfo = boost::none) { STORM_LOG_TRACE("Performing quantative solution step. Player 1: " << player1Direction << ", player 2: " << player2Direction << "."); @@ -260,14 +346,14 @@ namespace storm { std::unique_ptr> solver = solverFactory.create(submatrix, maybeStates, game.getIllegalPlayer1Mask(), game.getIllegalPlayer2Mask(), game.getRowVariables(), game.getColumnVariables(), game.getRowColumnMetaVariablePairs(), game.getPlayer1Variables(), game.getPlayer2Variables()); solver->setGeneratePlayersStrategies(true); auto values = solver->solveGame(env, player1Direction, player2Direction, startVector, subvector, startInfo ? boost::make_optional(startInfo.get().getPlayer1Strategy()) : boost::none, startInfo ? boost::make_optional(startInfo.get().getPlayer2Strategy()) : boost::none); - return QuantitativeGameResult(std::make_pair(storm::utility::zero(), storm::utility::one()), values, solver->getPlayer1Strategy(), solver->getPlayer2Strategy()); + return SymbolicQuantitativeGameResult(std::make_pair(storm::utility::zero(), storm::utility::one()), values, solver->getPlayer1Strategy(), solver->getPlayer2Strategy()); } template - QuantitativeGameResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::abstraction::MenuGame const& game, QualitativeGameResultMinMax const& qualitativeResult, storm::dd::Add const& initialStatesAdd, storm::dd::Bdd const& maybeStates, boost::optional> const& startInfo = boost::none) { + SymbolicQuantitativeGameResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::abstraction::MenuGame const& game, SymbolicQualitativeGameResultMinMax const& qualitativeResult, storm::dd::Add const& initialStatesAdd, storm::dd::Bdd const& maybeStates, boost::optional> const& startInfo = boost::none) { bool min = player2Direction == storm::OptimizationDirection::Minimize; - QuantitativeGameResult result; + SymbolicQuantitativeGameResult result; // We fix the strategies. That is, we take the decisions of the strategies obtained in the qualitiative // preprocessing if possible. @@ -299,7 +385,7 @@ namespace storm { // Extend the values of the maybe states by the qualitative values. result.values += min ? qualitativeResult.prob1Min.getPlayer1States().template toAdd() : qualitativeResult.prob1Max.getPlayer1States().template toAdd(); } else { - STORM_LOG_TRACE("No maybe states."); + STORM_LOG_TRACE("No " << (player2Direction == storm::OptimizationDirection::Minimize ? "min" : "max") << " maybe states."); // Extend the values of the maybe states by the qualitative values. result.values += min ? qualitativeResult.prob1Min.getPlayer1States().template toAdd() : qualitativeResult.prob1Max.getPlayer1States().template toAdd(); @@ -323,50 +409,202 @@ namespace storm { return result; } + template + ExplicitQuantitativeResult computeQuantitativeResult(Environment const& env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, ExplicitQualitativeGameResultMinMax const& qualitativeResult, storm::storage::BitVector const& maybeStates, ExplicitGameStrategyPair& strategyPair, storm::dd::Odd const& odd, ExplicitQuantitativeResult const* startingQuantitativeResult = nullptr, ExplicitGameStrategyPair const* startingStrategyPair = nullptr, boost::optional> const& previousResult = boost::none) { + + bool player2Min = player2Direction == storm::OptimizationDirection::Minimize; + auto const& player1Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer1States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer1States(); + auto const& player2Prob0States = player2Min ? qualitativeResult.getProb0Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb0Max().asExplicitQualitativeGameResult().getPlayer2States(); + auto const& player2Prob1States = player2Min ? qualitativeResult.getProb1Min().asExplicitQualitativeGameResult().getPlayer2States() : qualitativeResult.getProb1Max().asExplicitQualitativeGameResult().getPlayer2States(); + + ExplicitQuantitativeResult result(maybeStates.size()); + storm::utility::vector::setVectorValues(result.getValues(), player1Prob1States, storm::utility::one()); + + // If there are no maybe states, there is nothing we need to solve. + if (maybeStates.empty()) { + return result; + } + + // If there is a previous result, unpack the previous values with respect to the new ODD. + if (previousResult) { + STORM_LOG_ASSERT(player2Min, "Can only reuse previous values when minimizing."); + previousResult.get().odd.oldToNewIndex(odd, [&previousResult,&result,player2Min,player1Prob1States] (uint64_t oldOffset, uint64_t newOffset) { + if (!player1Prob1States.get(newOffset)) { + result.getValues()[newOffset] = player2Min ? previousResult.get().values.getValues()[oldOffset] : previousResult.get().values.getValues()[oldOffset]; + } + }); + } + + // Otherwise, we need to solve a (sub)game. + STORM_LOG_TRACE("[" << player1Direction << ", " << player2Direction << "]: Solving " << maybeStates.getNumberOfSetBits()<< " maybe states."); + + // Create the game by selecting all maybe player 2 states (non-prob0/1) of all maybe player 1 states. + std::vector subPlayer1Groups(maybeStates.getNumberOfSetBits() + 1); + uint64_t position = 0; + uint64_t previousPlayer2States = 0; + storm::storage::BitVector player2MaybeStates(transitionMatrix.getRowGroupCount()); + for (auto state : maybeStates) { + subPlayer1Groups[position] = previousPlayer2States; + + bool hasMaybePlayer2Successor = false; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (!player2Prob0States.get(player2State) && !player2Prob1States.get(player2State)) { + player2MaybeStates.set(player2State); + hasMaybePlayer2Successor = true; + ++previousPlayer2States; + } + } + STORM_LOG_ASSERT(hasMaybePlayer2Successor, "Player 1 maybe state has no player2 maybe successor."); + ++position; + } + subPlayer1Groups.back() = previousPlayer2States; + + // Create the player 2 matrix using the maybe player 2 states. + storm::storage::SparseMatrix submatrix = transitionMatrix.getSubmatrix(true, player2MaybeStates, maybeStates); + std::vector b = transitionMatrix.getConstrainedRowGroupSumVector(player2MaybeStates, player1Prob1States); + + // Set up game solver. + auto gameSolver = storm::solver::GameSolverFactory().create(env, subPlayer1Groups, submatrix); + + // Prepare the value storage for the maybe states. If the starting values were given, extract them now. + std::vector values(maybeStates.getNumberOfSetBits()); + if (startingQuantitativeResult) { + storm::utility::vector::selectVectorValues(values, maybeStates, startingQuantitativeResult->getValues()); + } + if (previousResult) { + STORM_LOG_ASSERT(!startingQuantitativeResult, "Cannot take two different hints."); + storm::utility::vector::selectVectorValues(values, maybeStates, result.getValues()); + } + + // Prepare scheduler storage. + std::vector player1Scheduler(subPlayer1Groups.size() - 1); + std::vector player2Scheduler(submatrix.getRowGroupCount()); + if (startingStrategyPair) { + // If the starting strategy pair was provided, we need to extract the choices of the maybe states here. + uint64_t maybeStatePosition = 0; + previousPlayer2States = 0; + for (auto state : maybeStates) { + uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state); + + uint64_t previousPlayer2MaybeStatesForState = 0; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (player2MaybeStates.get(player2State)) { + if (player2State == chosenPlayer2State) { + player1Scheduler[maybeStatePosition] = previousPlayer2MaybeStatesForState; + } + + // Copy over the player 2 action (modulo making it local) as all rows for the player 2 state are taken. + if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) { + player2Scheduler[previousPlayer2States] = startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.getRowGroupIndices() + [player2State]; + } else { + player2Scheduler[previousPlayer2States] = 0; + } + + ++previousPlayer2MaybeStatesForState; + ++previousPlayer2States; + } + } + + ++maybeStatePosition; + } + STORM_LOG_ASSERT(previousPlayer2States == submatrix.getRowGroupCount(), "Expected correct number of player 2 states."); + } + + // Solve actual game and track schedulers. + gameSolver->solveGame(env, player1Direction, player2Direction, values, b, &player1Scheduler, &player2Scheduler); + + // Set values according to quantitative result (qualitative result has already been taken care of). + storm::utility::vector::setVectorValues(result.getValues(), maybeStates, values); + + // Obtain strategies from solver and fuse them with the pre-existing strategy pair for the qualitative result. + uint64_t previousPlayer1MaybeStates = 0; + uint64_t previousPlayer2MaybeStates = 0; + for (auto state : maybeStates) { + uint64_t previousPlayer2MaybeStatesForState = 0; + bool madePlayer1Choice = false; + for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) { + if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2MaybeStatesForState) { + strategyPair.getPlayer1Strategy().setChoice(state, player2State); + madePlayer1Choice = true; + } + + if (player2MaybeStates.get(player2State)) { + strategyPair.getPlayer2Strategy().setChoice(player2State, transitionMatrix.getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]); + + ++previousPlayer2MaybeStatesForState; + ++previousPlayer2MaybeStates; + } + } + STORM_LOG_ASSERT(madePlayer1Choice, "[" << player1Direction << "]: player 1 state " << state << " did not make a choice, scheduler: " << player1Scheduler[previousPlayer1MaybeStates] << "."); + + ++previousPlayer1MaybeStates; + } + + return result; + } + template - std::unique_ptr GameBasedMdpModelChecker::performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression) { + std::unique_ptr GameBasedMdpModelChecker::performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression) { STORM_LOG_THROW(checkTask.isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidPropertyException, "The game-based abstraction refinement model checker can only compute the result for the initial states."); // Optimization: do not compute both bounds if not necessary (e.g. if bound given and exceeded, etc.) + totalWatch.start(); // Set up initial predicates. + setupWatch.start(); std::vector initialPredicates = getInitialPredicates(constraintExpression, targetStateExpression); // Derive the optimization direction for player 1 (assuming menu-game abstraction). storm::OptimizationDirection player1Direction = getPlayer1Direction(checkTask); // Create the abstractor. - std::shared_ptr> abstractor; + storm::abstraction::MenuGameAbstractorOptions abstractorOptions(std::move(options.constraints)); if (preprocessedModel.isPrismProgram()) { - abstractor = std::make_shared>(preprocessedModel.asPrismProgram(), smtSolverFactory); + abstractor = std::make_shared>(preprocessedModel.asPrismProgram(), smtSolverFactory, abstractorOptions); } else { - abstractor = std::make_shared>(preprocessedModel.asJaniModel(), smtSolverFactory); + abstractor = std::make_shared>(preprocessedModel.asJaniModel(), smtSolverFactory, abstractorOptions); } + if (!constraintExpression.isTrue()) { + abstractor->addTerminalStates(!constraintExpression); + } + abstractor->addTerminalStates(targetStateExpression); + abstractor->setTargetStates(targetStateExpression); // Create a refiner that can be used to refine the abstraction when needed. - storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager())); - refiner.refine(initialPredicates); - + storm::abstraction::MenuGameRefinerOptions refinerOptions(std::move(options.injectedRefinementPredicates)); + storm::abstraction::MenuGameRefiner refiner(*abstractor, smtSolverFactory->create(preprocessedModel.getManager()), refinerOptions); + refiner.refine(initialPredicates, false); + storm::dd::Bdd globalConstraintStates = abstractor->getStates(constraintExpression); storm::dd::Bdd globalTargetStates = abstractor->getStates(targetStateExpression); + setupWatch.stop(); // Enter the main-loop of abstraction refinement. - boost::optional> previousQualitativeResult = boost::none; - boost::optional> previousMinQuantitativeResult = boost::none; - for (uint_fast64_t iterations = 0; iterations < 10000; ++iterations) { + boost::optional> previousSymbolicQualitativeResult = boost::none; + boost::optional> previousSymbolicMinQuantitativeResult = boost::none; + boost::optional> previousExplicitResult = boost::none; + uint64_t peakPlayer1States = 0; + uint64_t peakTransitions = 0; + for (iteration = 0; iteration < maximalNumberOfAbstractions; ++iteration) { auto iterationStart = std::chrono::high_resolution_clock::now(); - STORM_LOG_TRACE("Starting iteration " << iterations << "."); + STORM_LOG_TRACE("Starting iteration " << iteration << "."); // (1) build the abstraction. - auto abstractionStart = std::chrono::high_resolution_clock::now(); + storm::utility::Stopwatch abstractionWatch(true); storm::abstraction::MenuGame game = abstractor->abstract(); - auto abstractionEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Abstraction in iteration " << iterations << " has " << game.getNumberOfStates() << " (player 1) states and " << game.getNumberOfTransitions() << " transitions (computed in " << std::chrono::duration_cast(abstractionEnd - abstractionStart).count() << "ms)."); + abstractionWatch.stop(); + totalAbstractionWatch.add(abstractionWatch); + + uint64_t numberOfPlayer1States = game.getNumberOfStates(); + peakPlayer1States = std::max(peakPlayer1States, numberOfPlayer1States); + uint64_t numberOfTransitions = game.getNumberOfTransitions(); + peakTransitions = std::max(peakTransitions, numberOfTransitions); + STORM_LOG_INFO("Abstraction in iteration " << iteration << " has " << numberOfPlayer1States << " player 1 states (" << game.getInitialStates().getNonZeroCount() << " initial), " << game.getNumberOfPlayer2States() << " player 2 states, " << numberOfTransitions << " transitions, " << game.getBottomStates().getNonZeroCount() << " bottom states, " << abstractor->getNumberOfPredicates() << " predicate(s), " << game.getTransitionMatrix().getNodeCount() << " nodes (transition matrix) (computed in " << abstractionWatch.getTimeInMilliseconds() << "ms)."); - // (2) Prepare transition matrix BDD and target state BDD for later use. - storm::dd::Bdd transitionMatrixBdd = game.getTransitionMatrix().toBdd(); + // (2) Prepare initial, constraint and target state BDDs for later use. storm::dd::Bdd initialStates = game.getInitialStates(); - STORM_LOG_THROW(initialStates.getNonZeroCount() == 1 || checkTask.isBoundSet(), storm::exceptions::InvalidPropertyException, "Game-based abstraction refinement requires a bound on the formula for model with " << initialStates.getNonZeroCount() << " initial states."); +// STORM_LOG_THROW(initialStates.getNonZeroCount() == 1 || checkTask.isBoundSet(), storm::exceptions::InvalidPropertyException, "Game-based abstraction refinement requires a bound on the formula for model with " << initialStates.getNonZeroCount() << " initial states."); storm::dd::Bdd constraintStates = globalConstraintStates && game.getReachableStates(); storm::dd::Bdd targetStates = globalTargetStates && game.getReachableStates(); if (player1Direction == storm::OptimizationDirection::Minimize) { @@ -374,105 +612,764 @@ namespace storm { } // #ifdef LOCAL_DEBUG - // targetStates.template toAdd().exportToDot("target.dot"); - // abstractor->exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne()); - // game.getReachableStates().template toAdd().exportToDot("reach.dot"); +// initialStates.template toAdd().exportToDot("init" + std::to_string(iteration) + ".dot"); +// targetStates.template toAdd().exportToDot("target" + std::to_string(iteration) + ".dot"); +// abstractor->exportToDot("game" + std::to_string(iteration) + ".dot", targetStates, game.getManager().getBddOne()); +// game.getReachableStates().template toAdd().exportToDot("reach" + std::to_string(iteration) + ".dot"); // #endif - // (3) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). - auto qualitativeStart = std::chrono::high_resolution_clock::now(); - QualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); - std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + std::unique_ptr result; + if (solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Dd) { + result = performSymbolicAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousSymbolicQualitativeResult, previousSymbolicMinQuantitativeResult); + } else { + result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner, previousExplicitResult); + } + if (result) { - printStatistics(*abstractor, game); + totalWatch.stop(); + printStatistics(*abstractor, game, iteration, peakPlayer1States, peakTransitions); return result; } - previousQualitativeResult = qualitativeResult; - auto qualitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative computation completed in " << std::chrono::duration_cast(qualitativeEnd - qualitativeStart).count() << "ms."); - // (4) compute the states for which we have to determine quantitative information. - storm::dd::Bdd maybeMin = !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.getReachableStates(); - storm::dd::Bdd maybeMax = !(qualitativeResult.prob0Max.getPlayer1States() || qualitativeResult.prob1Max.getPlayer1States()) && game.getReachableStates(); + auto iterationEnd = std::chrono::high_resolution_clock::now(); + STORM_LOG_INFO("Iteration " << iteration << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); + } + + totalWatch.stop(); + + // If this point is reached, we have given up on abstraction. + STORM_LOG_WARN("Could not derive result, maximal number of abstractions exceeded."); + return nullptr; + } + + template + std::unique_ptr GameBasedMdpModelChecker::performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult) { + + STORM_LOG_TRACE("Using dd-based solving."); + + // Prepare transition matrix BDD. + storm::dd::Bdd transitionMatrixBdd = game.getTransitionMatrix().toBdd(); + + // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). + storm::utility::Stopwatch qualitativeWatch(true); + SymbolicQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates); + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + if (result) { + return result; + } + previousQualitativeResult = qualitativeResult; + qualitativeWatch.stop(); + totalSolutionWatch.add(qualitativeWatch); + STORM_LOG_INFO("Qualitative computation completed in " << qualitativeWatch.getTimeInMilliseconds() << "ms."); + + // (2) compute the states for which we have to determine quantitative information. + storm::dd::Bdd maybeMin = !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.getReachableStates(); + storm::dd::Bdd maybeMax = !(qualitativeResult.prob0Max.getPlayer1States() || qualitativeResult.prob1Max.getPlayer1States()) && game.getReachableStates(); + + // (3) if the initial states are not maybe states, then we can refine at this point. + storm::dd::Bdd initialMaybeStates = (initialStates && maybeMin) || (initialStates && maybeMax); + bool qualitativeRefinement = false; + if (initialMaybeStates.isZero()) { + // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. + STORM_LOG_TRACE("No initial state is a 'maybe' state."); + + STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << "). Refining abstraction based on qualitative check."); + + // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) + // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. + storm::utility::Stopwatch refinementWatch(true); + qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Qualitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); + } + + // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. + if (!qualitativeRefinement) { + // At this point, we know that we cannot answer the query without further numeric computation. + STORM_LOG_TRACE("Starting numerical solution step."); + + storm::dd::Add initialStatesAdd = initialStates.template toAdd(); + + SymbolicQuantitativeGameResultMinMax quantitativeResult; + + // (7) Solve the min values and check whether we can give the answer already. + storm::utility::Stopwatch quantitativeWatch(true); + quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); + quantitativeWatch.stop(); + previousMinQuantitativeResult = quantitativeResult.min; + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); + if (result) { + totalSolutionWatch.add(quantitativeWatch); + return result; + } + + // (8) Solve the max values and check whether we can give the answer already. + quantitativeWatch.start(); + quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); + quantitativeWatch.stop(); + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); + totalSolutionWatch.add(quantitativeWatch); + if (result) { + return result; + } + + ValueType minVal = quantitativeResult.min.getInitialStatesRange().first; + ValueType maxVal = quantitativeResult.max.getInitialStatesRange().second; + ValueType difference = maxVal - minVal; + if (std::is_same::value) { + std::stringstream differenceStream; + differenceStream.setf(std::ios::fixed, std::ios::floatfield); + differenceStream.precision(15); + differenceStream << difference; + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (difference " << differenceStream.str() << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + } else { + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "], difference " << difference << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + } + + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. + result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); + if (result) { + return result; + } + + // Make sure that all strategies are still valid strategies. + STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); + STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); + STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); + STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); + + // (10) If we arrived at this point, it means that we have all qualitative and quantitative + // information about the game, but we could not yet answer the query. In this case, we need to refine. + storm::utility::Stopwatch refinementWatch(true); + refiner.refine(game, transitionMatrixBdd, quantitativeResult); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Quantitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); + } + + // Return null to indicate no result has been found yet. + return nullptr; + } + + template + void postProcessStrategies(storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQualitativeGameResultMinMax const& qualitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { + + if (!redirectPlayer1 && !redirectPlayer2) { + return; + } + + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + bool isProb0Min = qualitativeResult.getProb0Min().getStates().get(state); + + bool hasMinPlayer1Choice = false; + uint64_t lowerPlayer1Choice = 0; + bool hasMaxPlayer1Choice = false; + uint64_t upperPlayer1Choice = 0; + + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + hasMinPlayer1Choice = true; + lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); + + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (lowerPlayer2Choice == upperPlayer2Choice) { + continue; + } + + bool redirect = true; + if (isProb0Min) { + for (auto const& entry : transitionMatrix.getRow(upperPlayer2Choice)) { + if (!qualitativeResult.getProb0Min().getStates().get(entry.getColumn())) { + redirect = false; + break; + } + } + } + + if (redirectPlayer2 && redirect) { + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + } + } + } + + bool lowerChoiceUnderUpperIsProb0 = false; + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); + + if (lowerPlayer1Choice != upperPlayer1Choice && minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + hasMaxPlayer1Choice = true; + + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (lowerPlayer2Choice == upperPlayer2Choice) { + continue; + } + + lowerChoiceUnderUpperIsProb0 = true; + for (auto const& entry : transitionMatrix.getRow(lowerPlayer2Choice)) { + if (!qualitativeResult.getProb0Min().getStates().get(entry.getColumn())) { + lowerChoiceUnderUpperIsProb0 = false; + break; + } + } + + bool redirect = true; + if (lowerChoiceUnderUpperIsProb0) { + for (auto const& entry : transitionMatrix.getRow(upperPlayer2Choice)) { + if (!qualitativeResult.getProb0Min().getStates().get(entry.getColumn())) { + redirect = false; + break; + } + } + } + + if (redirectPlayer2 && redirect) { + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + } + } + } + + if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) { + if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) { + if (!isProb0Min || lowerChoiceUnderUpperIsProb0) { + minStrategyPair.getPlayer1Strategy().setChoice(state, upperPlayer1Choice); + } + } + } + } + } + + template + class ExplicitGameExporter { + public: + ExplicitGameExporter() : showNonStrategyAlternatives(false) { + // Intentionally left empty. + } + + void exportToJson(std::string const& filename, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + + // Export game as json. + std::ofstream outfile(filename); + exportGame(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); + } + + void setShowNonStrategyAlternatives(bool value) { + showNonStrategyAlternatives = value; + } + + private: + + struct NodeData { + NodeData(uint64_t id, uint64_t player, bool initial, bool target) : id(id), player(player), initial(initial), target(target) { + // Intentionally left empty. + } + + uint64_t id; + uint64_t player; // 0 = probabilistic player, 1 = player 1, 2 = player 2 + bool initial; + bool target; + }; + + struct EdgeData { + EdgeData(uint64_t id, uint64_t source, uint64_t target, ValueType probability, uint64_t label, bool min, bool max) : id(id), source(source), target(target), probability(probability), label(label), min(min), max(max) { + // Intentionally left empty. + } + + uint64_t id; + uint64_t source; + uint64_t target; + ValueType probability; + uint64_t label; + bool min; + bool max; + }; + + void exportEdge(std::ofstream& out, EdgeData const& data, bool& first) { + if (!first) { + out << "," << std::endl; + } else { + first = false; + } + out << "\t\t{" << std::endl; + out << "\t\t\t\"data\": {" << std::endl; + out << "\t\t\t\t\"id\": \"" << data.id << "\"," << std::endl; + if (data.probability != storm::utility::zero()) { + out << "\t\t\t\t\"name\": \"" << data.probability << "\"," << std::endl; + } else { + out << "\t\t\t\t\"name\": \"" << data.label << "\"," << std::endl; + } + out << "\t\t\t\t\"source\": \"" << data.source << "\"," << std::endl; + out << "\t\t\t\t\"target\": \"" << data.target << "\"" << std::endl; + out << "\t\t\t}," << std::endl; + out << "\t\t\t\"classes\": \""; + if (data.min && data.max) { + out << "minMaxEdge"; + } else if (data.min) { + out << "minEdge"; + } else if (data.max) { + out << "maxEdge"; + } else { + out << "edge"; + } + out << "\"" << std::endl; + out << "\t\t}"; + } + + void exportNode(std::ofstream& out, NodeData const& data, ExplicitQuantitativeResultMinMax const* quantitativeResult, bool& first) { + if (!first) { + out << "," << std::endl; + } else { + first = false; + } + out << "\t\t{" << std::endl; + out << "\t\t\t\"data\": {" << std::endl; + out << "\t\t\t\t\"id\": \"" << data.id << "\"," << std::endl; + out << "\t\t\t\t\"name\": \"" << data.id; + if (quantitativeResult && data.player == 1) { + out << " [" << quantitativeResult->getMin().getValues()[data.id] << ", " << quantitativeResult->getMax().getValues()[data.id] << "]"; + } + out << "\"" << std::endl; + out << "\t\t\t}," << std::endl; + out << "\t\t\t\"group\": \"nodes\"," << std::endl; + out << "\t\t\t\"classes\": \""; + if (data.player == 1) { + if (data.initial) { + out << "initialNode"; + } else if (data.target) { + out << "targetNode"; + } else { + out << "node"; + } + } else if (data.player == 2) { + out << "pl2node"; + } else if (data.player == 0) { + out << "plpnode"; + } + out << "\"" << std::endl; + out << "\t\t}"; + } + + void exportGame(std::ofstream& out, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, ExplicitGameStrategyPair const* minStrategyPair, ExplicitGameStrategyPair const* maxStrategyPair) { + + // To export the game as JSON, we build some data structures through a traversal and then emit them. + std::vector nodes; + std::vector edges; + + std::vector stack; + for (auto state : initialStates) { + stack.push_back(state); + } + storm::storage::BitVector reachablePlayer1(player1Groups.size() - 1); - // (5) if the initial states are not maybe states, then we can refine at this point. - storm::dd::Bdd initialMaybeStates = (initialStates && maybeMin) || (initialStates && maybeMax); - bool qualitativeRefinement = false; - if (initialMaybeStates.isZero()) { - // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. - STORM_LOG_TRACE("No initial state is a 'maybe' state."); + uint64_t edgeId = 0; + while (!stack.empty()) { + uint64_t currentState = stack.back(); + stack.pop_back(); + + nodes.emplace_back(currentState, 1, initialStates.get(currentState), targetStates.get(currentState)); - STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states. Refining abstraction based on qualitative check."); + for (uint64_t player2State = player1Groups[currentState]; player2State < player1Groups[currentState + 1]; ++player2State) { + bool emit = (minStrategyPair || maxStrategyPair) ? this->showNonStrategyAlternatives : true; + bool min = false; + bool max = false; + + if (minStrategyPair && minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState) && minStrategyPair->getPlayer1Strategy().getChoice(currentState) == player2State) { + emit = true; + min = true; + } + if (maxStrategyPair && maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState) && maxStrategyPair->getPlayer1Strategy().getChoice(currentState) == player2State) { + emit = true; + max = true; + } + + if (emit) { + nodes.emplace_back(player2State, 2, false, false); + edges.emplace_back(edgeId++, currentState, player2State, storm::utility::zero(), player2State - player1Groups[currentState], min, max); + + for (uint64_t playerPState = player2Groups[player2State]; playerPState < player2Groups[player2State + 1]; ++playerPState) { + emit = (minStrategyPair || maxStrategyPair) ? this->showNonStrategyAlternatives : true; + min = false; + max = false; + + if (minStrategyPair && minStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State) && minStrategyPair->getPlayer2Strategy().getChoice(player2State) == playerPState) { + emit = true; + min = true; + } + if (maxStrategyPair && maxStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State) && maxStrategyPair->getPlayer2Strategy().getChoice(player2State) == playerPState) { + emit = true; + max = true; + } + + if (emit) { + nodes.emplace_back(playerPState, 0, false, false); + edges.emplace_back(edgeId++, player2State, playerPState, storm::utility::zero(), playerPState - player2Groups[player2State], min, max); + + for (auto const& entry : transitionMatrix.getRow(playerPState)) { + auto player1Successor = entry.getColumn(); + if (!reachablePlayer1.get(player1Successor)) { + reachablePlayer1.set(player1Successor); + stack.push_back(player1Successor); + } + + edges.emplace_back(edgeId++, playerPState, player1Successor, entry.getValue(), 0, false, false); + } + } + } + } + } + } + + // Finally, export the data structures we built. + + // Export nodes. + out << "{\n\t\"nodes\": [" << std::endl; + bool first = true; + for (auto const& node : nodes) { + exportNode(out, node, &quantitativeResult, first); + } + out << "\n\t]," << std::endl; + + // Export edges. + first = true; + out << "\t\"edges\": [" << std::endl; + for (auto const& edge : edges) { + exportEdge(out, edge, first); + } + out << "\n\t]\n}" << std::endl; + } + + bool showNonStrategyAlternatives; + }; + + template + void postProcessStrategies(uint64_t iteration, storm::OptimizationDirection const& player1Direction, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair, std::vector const& player1Groups, std::vector const& player2Groups, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& initialStates, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, ExplicitQuantitativeResultMinMax const& quantitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck) { + + if (redirectPlayer1 || redirectPlayer2) { + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + STORM_LOG_ASSERT(targetStates.get(state) || minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected lower player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(targetStates.get(state) || maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected upper player 1 choice in state " << state << "."); - // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) - // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. - auto qualitativeRefinementStart = std::chrono::high_resolution_clock::now(); - qualitativeRefinement = refiner.refine(game, transitionMatrixBdd, qualitativeResult); - auto qualitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Qualitative refinement completed in " << std::chrono::duration_cast(qualitativeRefinementEnd - qualitativeRefinementStart).count() << "ms."); - } else if (initialMaybeStates == initialStates && checkTask.isQualitativeSet()) { - // If all initial states are 'maybe' states and the property we needed to check is a qualitative one, - // we can return the result here. - return std::make_unique>(storm::storage::sparse::state_type(0), ValueType(0.5)); - } - - // (6) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. - if (!qualitativeRefinement) { - // At this point, we know that we cannot answer the query without further numeric computation. - - storm::dd::Add initialStatesAdd = initialStates.template toAdd(); + bool hasMinPlayer1Choice = false; + uint64_t lowerPlayer1Choice = 0; + ValueType lowerValueUnderMinChoicePlayer1 = storm::utility::zero(); + bool hasMaxPlayer1Choice = false; + uint64_t upperPlayer1Choice = 0; + ValueType lowerValueUnderMaxChoicePlayer1 = storm::utility::zero(); - STORM_LOG_TRACE("Starting numerical solution step."); - auto quantitativeStart = std::chrono::high_resolution_clock::now(); - - QuantitativeGameResultMinMax quantitativeResult; + if (minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + hasMinPlayer1Choice = true; + lowerPlayer1Choice = minStrategyPair.getPlayer1Strategy().getChoice(state); + + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice), "Expected lower player 2 choice for state " << state << " (lower player 1 choice " << lowerPlayer1Choice << ")."); + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + lowerValueUnderMinChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + + if (maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(lowerPlayer1Choice)) { + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(lowerPlayer1Choice); + + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { + lowerValueUnderMinChoicePlayer1 = lowerValueUnderUpperChoicePlayer2; + minStrategyPair.getPlayer2Strategy().setChoice(lowerPlayer1Choice, upperPlayer2Choice); + } + } + } + } - // (7) Solve the min values and check whether we can give the answer already. - quantitativeResult.min = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult : boost::none); - previousMinQuantitativeResult = quantitativeResult.min; - result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange()); - if (result) { - printStatistics(*abstractor, game); - return result; + if (maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state)) { + upperPlayer1Choice = maxStrategyPair.getPlayer1Strategy().getChoice(state); + + if (upperPlayer1Choice != lowerPlayer1Choice && minStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice)) { + hasMaxPlayer1Choice = true; + + uint64_t lowerPlayer2Choice = minStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + ValueType lowerValueUnderLowerChoicePlayer2 = transitionMatrix.multiplyRowWithVector(lowerPlayer2Choice, quantitativeResult.getMin().getValues()); + lowerValueUnderMaxChoicePlayer1 = lowerValueUnderLowerChoicePlayer2; + + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(upperPlayer1Choice), "Expected upper player 2 choice for state " << state << " (upper player 1 choice " << upperPlayer1Choice << ")."); + uint64_t upperPlayer2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(upperPlayer1Choice); + + if (lowerPlayer2Choice != upperPlayer2Choice) { + ValueType lowerValueUnderUpperChoicePlayer2 = transitionMatrix.multiplyRowWithVector(upperPlayer2Choice, quantitativeResult.getMin().getValues()); + + if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) { + minStrategyPair.getPlayer2Strategy().setChoice(upperPlayer1Choice, upperPlayer2Choice); + } + } + } } - // (8) Solve the max values and check whether we can give the answer already. - quantitativeResult.max = computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min)); - result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange()); - if (result) { - printStatistics(*abstractor, game); - return result; + if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) { + if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) { + if (lowerValueUnderMaxChoicePlayer1 <= lowerValueUnderMinChoicePlayer1) { + minStrategyPair.getPlayer1Strategy().setChoice(state, upperPlayer1Choice); + } + } + } + } + } + + if (sanityCheck) { + storm::utility::ConstantsComparator sanityComparator( 1e-6, true); + + ///////// SANITY CHECK: apply lower strategy, obtain DTMC matrix and model check it. the values should + ///////// still be the lower ones. + storm::storage::SparseMatrixBuilder dtmcMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + if (targetStates.get(state)) { + dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); + } else { + STORM_LOG_ASSERT(minStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected min player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(minStrategyPair.getPlayer2Strategy().hasDefinedChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)), "Expected max player 2 choice in state " << state << " with player 2 choice " << maxStrategyPair.getPlayer1Strategy().getChoice(state) << "."); + uint64_t player2Choice = minStrategyPair.getPlayer2Strategy().getChoice(minStrategyPair.getPlayer1Strategy().getChoice(state)); + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + } + } + } + auto dtmcMatrix = dtmcMatrixBuilder.build(); + std::vector sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + + ValueType maxDiff = storm::utility::zero(); + uint64_t maxState = 0; + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + ValueType diff = storm::utility::abs(ValueType(sanityValues[state] - quantitativeResult.getMin().getValues()[state])); + if (diff > maxDiff) { + maxState = state; + maxDiff = diff; } + } + STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); + STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMin().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); - auto quantitativeEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Obtained quantitative bounds [" << quantitativeResult.min.getInitialStatesRange().first << ", " << quantitativeResult.max.getInitialStatesRange().second << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); - - // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. - result = checkForResultAfterQuantitativeCheck(quantitativeResult.min.getInitialStatesRange().first, quantitativeResult.max.getInitialStatesRange().second, comparator); - if (result) { - printStatistics(*abstractor, game); - return result; + ///////// SANITY CHECK: apply upper strategy, obtain DTMC matrix and model check it. the values should + ///////// still be the upper ones. + dtmcMatrixBuilder = storm::storage::SparseMatrixBuilder(player1Groups.size() - 1, player1Groups.size() - 1); + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + if (targetStates.get(state)) { + dtmcMatrixBuilder.addNextValue(state, state, storm::utility::one()); + } else { + STORM_LOG_ASSERT(maxStrategyPair.getPlayer1Strategy().hasDefinedChoice(state), "Expected max player 1 choice in state " << state << "."); + STORM_LOG_ASSERT(maxStrategyPair.getPlayer2Strategy().hasDefinedChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)), "Expected max player 2 choice in state " << state << " with player 2 choice " << maxStrategyPair.getPlayer1Strategy().getChoice(state) << "."); + uint64_t player2Choice = maxStrategyPair.getPlayer2Strategy().getChoice(maxStrategyPair.getPlayer1Strategy().getChoice(state)); + + for (auto const& entry : transitionMatrix.getRow(player2Choice)) { + dtmcMatrixBuilder.addNextValue(state, entry.getColumn(), entry.getValue()); + } + } + } + dtmcMatrix = dtmcMatrixBuilder.build(); + sanityValues = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(Environment(), storm::solver::SolveGoal(), dtmcMatrix, dtmcMatrix.transpose(), constraintStates, targetStates, false); + + maxDiff = storm::utility::zero(); + maxState = 0; + for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) { + ValueType diff = storm::utility::abs(ValueType(sanityValues[state] - quantitativeResult.getMax().getValues()[state])); + if (diff > maxDiff) { + maxState = state; + maxDiff = diff; } + } + STORM_LOG_TRACE("Got maximal deviation of " << maxDiff << "."); + STORM_LOG_WARN_COND(sanityComparator.isZero(maxDiff), "Deviation " << maxDiff << " between computed value (" << quantitativeResult.getMax().getValues()[maxState] << ") and sanity check value (" << sanityValues[maxState] << ") in state " << maxState << " appears to be too high. (Obtained bounds were [" << quantitativeResult.getMin().getValues()[maxState] << ", " << quantitativeResult.getMax().getValues()[maxState] << "].)"); + } + } + + template + std::unique_ptr GameBasedMdpModelChecker::performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStatesBdd, storm::dd::Bdd const& constraintStatesBdd, storm::dd::Bdd const& targetStatesBdd, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult) { + STORM_LOG_TRACE("Using sparse solving."); - // Make sure that all strategies are still valid strategies. - STORM_LOG_ASSERT(quantitativeResult.min.getPlayer1Strategy().isZero() || quantitativeResult.min.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); - STORM_LOG_ASSERT(quantitativeResult.max.getPlayer1Strategy().isZero() || quantitativeResult.max.getPlayer1Strategy().template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); - STORM_LOG_ASSERT(quantitativeResult.min.getPlayer2Strategy().isZero() || quantitativeResult.min.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); - STORM_LOG_ASSERT(quantitativeResult.max.getPlayer2Strategy().isZero() || quantitativeResult.max.getPlayer2Strategy().template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); + // (0) Start by transforming the necessary symbolic elements to explicit ones. + storm::utility::Stopwatch translationWatch(true); + storm::dd::Odd odd = game.getReachableStates().createOdd(); + + std::vector> labelingVariableSets = {game.getPlayer1Variables(), game.getPlayer2Variables()}; + typename storm::dd::Add::MatrixAndLabeling matrixAndLabeling = game.getTransitionMatrix().toLabeledMatrix(game.getRowVariables(), game.getColumnVariables(), game.getNondeterminismVariables(), odd, odd, labelingVariableSets); + auto& transitionMatrix = matrixAndLabeling.matrix; + auto& player1Labeling = matrixAndLabeling.labelings.front(); + auto& player2Labeling = matrixAndLabeling.labelings.back(); + + // Create the player 2 row grouping from the labeling. + std::vector tmpPlayer2RowGrouping; + for (uint64_t player1State = 0; player1State < transitionMatrix.getRowGroupCount(); ++player1State) { + uint64_t lastLabel = std::numeric_limits::max(); + for (uint64_t row = transitionMatrix.getRowGroupIndices()[player1State]; row < transitionMatrix.getRowGroupIndices()[player1State + 1]; ++row) { + if (player1Labeling[row] != lastLabel) { + tmpPlayer2RowGrouping.emplace_back(row); + lastLabel = player1Labeling[row]; + } + } + } + tmpPlayer2RowGrouping.emplace_back(player1Labeling.size()); + + std::vector player1RowGrouping = transitionMatrix.swapRowGroupIndices(std::move(tmpPlayer2RowGrouping)); + auto const& player2RowGrouping = transitionMatrix.getRowGroupIndices(); - auto quantitativeRefinementStart = std::chrono::high_resolution_clock::now(); - // (10) If we arrived at this point, it means that we have all qualitative and quantitative - // information about the game, but we could not yet answer the query. In this case, we need to refine. - refiner.refine(game, transitionMatrixBdd, quantitativeResult); - auto quantitativeRefinementEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Quantitative refinement completed in " << std::chrono::duration_cast(quantitativeRefinementEnd - quantitativeRefinementStart).count() << "ms."); + // Create the player 1 groups and backward transitions (for both players). + std::vector player1Groups(player1RowGrouping.size()); + storm::storage::SparseMatrix player1BackwardTransitions = transitionMatrix.transpose(true); + std::vector player2BackwardTransitions(transitionMatrix.getRowGroupCount()); + uint64_t player2State = 0; + for (uint64_t player1State = 0; player1State < player1RowGrouping.size() - 1; ++player1State) { + while (player1RowGrouping[player1State + 1] > player2RowGrouping[player2State]) { + player2BackwardTransitions[player2State] = player1State; + ++player2State; } - auto iterationEnd = std::chrono::high_resolution_clock::now(); - STORM_LOG_DEBUG("Iteration " << iterations << " took " << std::chrono::duration_cast(iterationEnd - iterationStart).count() << "ms."); + + player1Groups[player1State + 1] = player2State; } + + // Lift the player 1 labeling from rows to row groups (player 2 states). + for (uint64_t player1State = 0; player1State < player1Groups.size() - 1; ++player1State) { + for (uint64_t player2State = player1Groups[player1State]; player2State < player1Groups[player1State + 1]; ++player2State) { + player1Labeling[player2State] = player1Labeling[player2RowGrouping[player2State]]; + } + } + player1Labeling.resize(player2RowGrouping.size() - 1); + + // Create explicit representations of important state sets. + storm::storage::BitVector initialStates = initialStatesBdd.toVector(odd); + storm::storage::BitVector constraintStates = constraintStatesBdd.toVector(odd); + storm::storage::BitVector targetStates = targetStatesBdd.toVector(odd); + translationWatch.stop(); + totalTranslationWatch.add(translationWatch); + STORM_LOG_INFO("Translation to explicit representation completed in " << translationWatch.getTimeInMilliseconds() << "ms."); + + // Prepare the two strategies. + abstraction::ExplicitGameStrategyPair minStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); + abstraction::ExplicitGameStrategyPair maxStrategyPair(initialStates.size(), transitionMatrix.getRowGroupCount()); + + // (1) compute all states with probability 0/1 wrt. to the two different player 2 goals (min/max). + storm::utility::Stopwatch qualitativeWatch(true); + ExplicitQualitativeGameResultMinMax qualitativeResult = computeProb01States(previousResult, odd, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, minStrategyPair, maxStrategyPair); + qualitativeWatch.stop(); + totalSolutionWatch.add(qualitativeWatch); + STORM_LOG_INFO("Qualitative computation completed in " << qualitativeWatch.getTimeInMilliseconds() << "ms."); + + std::unique_ptr result = checkForResultAfterQualitativeCheck(checkTask, initialStates, qualitativeResult); + if (result) { + return result; + } + + // (2) compute the states for which we have to determine quantitative information. + storm::storage::BitVector maybeMin = ~(qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates()); + storm::storage::BitVector maybeMax = ~(qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates()); + + // (3) if the initial states are not maybe states, then we can refine at this point. + storm::storage::BitVector initialMaybeStates = initialStates & (maybeMin | maybeMax); + bool qualitativeRefinement = false; + if (initialMaybeStates.empty()) { + // In this case, we know the result for the initial states for both player 2 minimizing and maximizing. + STORM_LOG_TRACE("No initial state is a 'maybe' state."); + + STORM_LOG_INFO("Obtained qualitative bounds [0, 1] on the actual value for the initial states (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << "). Refining abstraction based on qualitative check."); + + // Post-process strategies for better refinements. + storm::utility::Stopwatch strategyProcessingWatch(true); + postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates, targetStates, qualitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); + strategyProcessingWatch.stop(); + totalStrategyProcessingWatch.add(strategyProcessingWatch); + STORM_LOG_DEBUG("Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() << "ms."); + + // If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1) + // depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine. + storm::utility::Stopwatch refinementWatch(true); + qualitativeRefinement = refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, qualitativeResult, minStrategyPair, maxStrategyPair); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Qualitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); + } + + ExplicitQuantitativeResultMinMax quantitativeResult; - STORM_LOG_ASSERT(false, "This point must not be reached."); + // (4) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. + if (!qualitativeRefinement) { + // At this point, we know that we cannot answer the query without further numeric computation. + STORM_LOG_TRACE("Starting numerical solution step."); + + // (7) Solve the min values and check whether we can give the answer already. + storm::utility::Stopwatch quantitativeWatch(true); + quantitativeResult.setMin(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix, player1Groups, qualitativeResult, maybeMin, minStrategyPair, odd, nullptr, nullptr, this->reuseQuantitativeResults ? previousResult : boost::none)); + + // Dispose of previous result as we now reused it. + if (previousResult) { + previousResult.get().clear(); + } + quantitativeWatch.stop(); + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.getMin().getRange(initialStates)); + if (result) { + totalSolutionWatch.add(quantitativeWatch); + return result; + } + + // (8) Solve the max values and check whether we can give the answer already. + quantitativeWatch.start(); + quantitativeResult.setMax(computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups, qualitativeResult, maybeMax, maxStrategyPair, odd, &quantitativeResult.getMin(), &minStrategyPair)); + quantitativeWatch.stop(); + result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.getMax().getRange(initialStates)); + totalSolutionWatch.add(quantitativeWatch); + if (result) { + return result; + } + + ValueType minVal = quantitativeResult.getMin().getRange(initialStates).first; + ValueType maxVal = quantitativeResult.getMax().getRange(initialStates).second; + ValueType difference = maxVal - minVal; + if (std::is_same::value) { + std::stringstream differenceStream; + differenceStream.setf(std::ios::fixed, std::ios::floatfield); + differenceStream.precision(15); + differenceStream << difference; + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (difference " << differenceStream.str() << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + } else { + STORM_LOG_INFO("Obtained quantitative bounds [" << minVal << ", " << maxVal << "] (approx. [" << storm::utility::convertNumber(minVal) << ", " << storm::utility::convertNumber(maxVal) << "], difference " << difference << ") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds() << "ms (after " << totalWatch.getTimeInMilliseconds() << "ms in iteration " << this->iteration << ")."); + } + + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. + result = checkForResultAfterQuantitativeCheck(quantitativeResult.getMin().getRange(initialStates).first, quantitativeResult.getMax().getRange(initialStates).second, comparator); + if (result) { + return result; + } + + // Post-process strategies for better refinements. + storm::utility::Stopwatch strategyProcessingWatch(true); + postProcessStrategies(this->iteration, player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug); + strategyProcessingWatch.stop(); + totalStrategyProcessingWatch.add(strategyProcessingWatch); + STORM_LOG_DEBUG("Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() << "ms."); + + + // Make sure that all strategies are still valid strategies. + STORM_LOG_ASSERT(minStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << minStrategyPair.getNumberOfUndefinedPlayer1States() << "."); + STORM_LOG_ASSERT(maxStrategyPair.getNumberOfUndefinedPlayer1States() <= targetStates.getNumberOfSetBits(), "Expected at most " << targetStates.getNumberOfSetBits() << " (number of target states) player 1 states with undefined choice but got " << maxStrategyPair.getNumberOfUndefinedPlayer1States() << "."); + + // (10) If we arrived at this point, it means that we have all qualitative and quantitative + // information about the game, but we could not yet answer the query. In this case, we need to refine. + storm::utility::Stopwatch refinementWatch(true); + refiner.refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair, maxStrategyPair); + refinementWatch.stop(); + totalRefinementWatch.add(refinementWatch); + STORM_LOG_INFO("Quantitative refinement completed in " << refinementWatch.getTimeInMilliseconds() << "ms."); + + if (this->reuseQuantitativeResults) { + PreviousExplicitResult nextPreviousResult; + nextPreviousResult.values = std::move(quantitativeResult.getMin()); + nextPreviousResult.odd = odd; + previousResult = std::move(nextPreviousResult); + STORM_LOG_TRACE("Prepared next previous result to reuse values."); + } + } + return nullptr; } @@ -499,7 +1396,7 @@ namespace storm { } template - storm::OptimizationDirection GameBasedMdpModelChecker::getPlayer1Direction(CheckTask const& checkTask) { + storm::OptimizationDirection GameBasedMdpModelChecker::getPlayer1Direction(CheckTask const& checkTask) { if (preprocessedModel.getModelType() == storm::storage::SymbolicModelDescription::ModelType::DTMC) { return storm::OptimizationDirection::Maximize; } else if (checkTask.isOptimizationDirectionSet()) { @@ -512,7 +1409,7 @@ namespace storm { } template - bool checkQualitativeStrategies(bool prob0, QualitativeGameResult const& result, storm::dd::Bdd const& targetStates) { + bool checkQualitativeStrategies(bool prob0, SymbolicQualitativeGameResult const& result, storm::dd::Bdd const& targetStates) { if (prob0) { STORM_LOG_ASSERT(result.hasPlayer1Strategy() && (result.getPlayer1States().isZero() || !result.getPlayer1Strategy().isZero()), "Unable to proceed without strategy."); } else { @@ -525,7 +1422,7 @@ namespace storm { } template - bool checkQualitativeStrategies(QualitativeGameResultMinMax const& qualitativeResult, storm::dd::Bdd const& targetStates) { + bool checkQualitativeStrategies(SymbolicQualitativeGameResultMinMax const& qualitativeResult, storm::dd::Bdd const& targetStates) { bool result = true; result &= checkQualitativeStrategies(true, qualitativeResult.prob0Min, targetStates); result &= checkQualitativeStrategies(false, qualitativeResult.prob1Min, targetStates); @@ -535,9 +1432,27 @@ namespace storm { } template - QualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates) { + ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional> const& previousResult, storm::dd::Odd const& odd, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1Groups, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair) { + + ExplicitQualitativeGameResultMinMax result; + +// ExplicitQualitativeGameResult problematicStates = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize); + + result.prob0Min = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); + result.prob1Min = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair); + result.prob0Max = storm::utility::graph::performProb0(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); + result.prob1Max = storm::utility::graph::performProb1(transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair); + + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNumberOfSetBits()<< " 'no', " << result.prob1Min.player1States.getNumberOfSetBits() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNumberOfSetBits() << " 'no', " << result.prob1Max.player1States.getNumberOfSetBits() << " 'yes'."); - QualitativeGameResultMinMax result; + return result; + } + + template + SymbolicQualitativeGameResultMinMax GameBasedMdpModelChecker::computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates) { + + SymbolicQualitativeGameResultMinMax result; if (reuseQualitativeResults) { // Depending on the player 1 direction, we choose a different order of operations. @@ -590,24 +1505,57 @@ namespace storm { result.prob1Max = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, storm::OptimizationDirection::Maximize, true, true); } - STORM_LOG_TRACE("Qualitative precomputation completed."); - STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); - STORM_LOG_TRACE("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Minimize << "]: " << result.prob0Min.player1States.getNonZeroCount() << " 'no', " << result.prob1Min.player1States.getNonZeroCount() << " 'yes'."); + STORM_LOG_INFO("[" << player1Direction << ", " << storm::OptimizationDirection::Maximize << "]: " << result.prob0Max.player1States.getNonZeroCount() << " 'no', " << result.prob1Max.player1States.getNonZeroCount() << " 'yes'."); + +// this->abstractor->exportToDot("lower_game" + std::to_string(iteration) + ".dot", result.prob1Max.getStates(), (result.prob0Min.getPlayer1Strategy() && result.prob0Min.getPlayer2Strategy()) || (result.prob1Min.getPlayer1Strategy() && result.prob1Min.getPlayer2Strategy())); +// this->abstractor->exportToDot("upper_game" + std::to_string(iteration) + ".dot", targetStates, (result.prob0Max.getPlayer1Strategy() && result.prob0Max.getPlayer2Strategy()) || (result.prob1Max.getPlayer1Strategy() && result.prob1Max.getPlayer2Strategy())); +// this->abstractor->exportToDot("lower_game" + std::to_string(iteration) + ".dot", targetStates, game.getManager().getBddOne()); +// this->abstractor->exportToDot("upper_game" + std::to_string(iteration) + ".dot", targetStates, game.getManager().getBddOne()); +// exit(-1); STORM_LOG_ASSERT(checkQualitativeStrategies(result, targetStates), "Qualitative strategies appear to be broken."); return result; } template - void GameBasedMdpModelChecker::printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const { + void GameBasedMdpModelChecker::printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements, uint64_t peakPlayer1States, uint64_t peakTransitions) const { if (storm::settings::getModule().isShowStatisticsSet()) { storm::abstraction::AbstractionInformation const& abstractionInformation = abstractor.getAbstractionInformation(); + std::streamsize originalPrecision = std::cout.precision(); + std::cout << std::fixed << std::setprecision(2); + std::cout << std::endl; std::cout << "Statistics:" << std::endl; - std::cout << " * player 1 states (final game): " << game.getReachableStates().getNonZeroCount() << std::endl; - std::cout << " * transitions (final game): " << game.getTransitionMatrix().getNonZeroCount() << std::endl; - std::cout << " * predicates used in abstraction: " << abstractionInformation.getNumberOfPredicates() << std::endl; + std::cout << " * size of final game: " << game.getReachableStates().getNonZeroCount() << " player 1 states, " << game.getTransitionMatrix().getNonZeroCount() << " transitions" << std::endl; + std::cout << " * peak size of game: " << peakPlayer1States << " player 1 states, " << peakTransitions << " transitions" << std::endl; + std::cout << " * refinements: " << refinements << std::endl; + std::cout << " * predicates: " << abstractionInformation.getNumberOfPredicates() << std::endl << std::endl; + + uint64_t totalAbstractionTimeMillis = totalAbstractionWatch.getTimeInMilliseconds(); + uint64_t totalTranslationTimeMillis = totalTranslationWatch.getTimeInMilliseconds(); + uint64_t totalStrategyProcessingTimeMillis = totalStrategyProcessingWatch.getTimeInMilliseconds(); + uint64_t totalSolutionTimeMillis = totalSolutionWatch.getTimeInMilliseconds(); + uint64_t totalRefinementTimeMillis = totalRefinementWatch.getTimeInMilliseconds(); + uint64_t setupTime = setupWatch.getTimeInMilliseconds(); + uint64_t totalTimeMillis = totalWatch.getTimeInMilliseconds(); + + std::cout << "Time breakdown:" << std::endl; + std::cout << " * setup: " << setupTime << "ms (" << 100 * static_cast(setupTime)/totalTimeMillis << "%)" << std::endl; + std::cout << " * abstraction: " << totalAbstractionTimeMillis << "ms (" << 100 * static_cast(totalAbstractionTimeMillis)/totalTimeMillis << "%)" << std::endl; + if (this->solveMode == storm::settings::modules::AbstractionSettings::SolveMode::Sparse) { + std::cout << " * translation: " << totalTranslationTimeMillis << "ms (" << 100 * static_cast(totalTranslationTimeMillis)/totalTimeMillis << "%)" << std::endl; + if (fixPlayer1Strategy || fixPlayer2Strategy) { + std::cout << " * strategy processing: " << totalStrategyProcessingTimeMillis << "ms (" << 100 * static_cast(totalStrategyProcessingTimeMillis)/totalTimeMillis << "%)" << std::endl; + } + } + std::cout << " * solution: " << totalSolutionTimeMillis << "ms (" << 100 * static_cast(totalSolutionTimeMillis)/totalTimeMillis << "%)" << std::endl; + std::cout << " * refinement: " << totalRefinementTimeMillis << "ms (" << 100 * static_cast(totalRefinementTimeMillis)/totalTimeMillis << "%)" << std::endl; + std::cout << " ---------------------------------------------" << std::endl; + std::cout << " * total: " << totalTimeMillis << "ms" << std::endl << std::endl; + + std::cout << std::defaultfloat << std::setprecision(originalPrecision); } } @@ -629,5 +1577,8 @@ namespace storm { template class GameBasedMdpModelChecker>; template class GameBasedMdpModelChecker>; template class GameBasedMdpModelChecker>; + + template class GameBasedMdpModelChecker>; + template class GameBasedMdpModelChecker>; } } diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h index 8c105cfc4..513b688e4 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.h @@ -3,20 +3,32 @@ #include "storm/modelchecker/AbstractModelChecker.h" +#include + #include "storm/storage/prism/Program.h" #include "storm/storage/dd/DdType.h" +#include "storm/storage/dd/Odd.h" #include "storm/storage/SymbolicModelDescription.h" -#include "storm/abstraction/QualitativeGameResult.h" -#include "storm/abstraction/QualitativeGameResultMinMax.h" +#include "storm/abstraction/SymbolicQualitativeGameResult.h" +#include "storm/abstraction/SymbolicQualitativeGameResultMinMax.h" +#include "storm/abstraction/ExplicitQuantitativeResult.h" #include "storm/logic/Bound.h" +#include "storm/settings/modules/AbstractionSettings.h" + +#include "storm-parsers/parser/ExpressionParser.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" + #include "storm/utility/ConstantsComparator.h" #include "storm/utility/solver.h" #include "storm/utility/graph.h" +#include "storm/utility/Stopwatch.h" namespace storm { namespace abstraction { @@ -25,12 +37,57 @@ namespace storm { template class MenuGameAbstractor; + + template + class MenuGameRefiner; + + template + class SymbolicQualitativeGameResultMinMax; + + template + class SymbolicQuantitativeGameResult; + + class ExplicitQualitativeGameResult; + class ExplicitQualitativeGameResultMinMax; + + template + class ExplicitQuantitativeResultMinMax; + + class ExplicitGameStrategy; + class ExplicitGameStrategyPair; } namespace modelchecker { - using storm::abstraction::QualitativeGameResult; - using storm::abstraction::QualitativeGameResultMinMax; + using storm::abstraction::SymbolicQualitativeGameResult; + using storm::abstraction::SymbolicQualitativeGameResultMinMax; + using storm::abstraction::ExplicitQualitativeGameResult; + using storm::abstraction::ExplicitQualitativeGameResultMinMax; + using storm::abstraction::ExplicitQuantitativeResult; + using storm::abstraction::ExplicitQuantitativeResultMinMax; + + namespace detail { + template + struct PreviousExplicitResult { + ExplicitQuantitativeResult values; + storm::dd::Odd odd; + + void clear() { + odd = storm::dd::Odd(); + values = ExplicitQuantitativeResult(); + } + }; + } + + struct GameBasedMdpModelCheckerOptions { + GameBasedMdpModelCheckerOptions() = default; + GameBasedMdpModelCheckerOptions(std::vector const& constraints, std::vector> const& injectedRefinementPredicates) : constraints(constraints), injectedRefinementPredicates(injectedRefinementPredicates) { + // Intentionally left empty. + } + + std::vector constraints; + std::vector> injectedRefinementPredicates; + }; template class GameBasedMdpModelChecker : public AbstractModelChecker { @@ -42,21 +99,25 @@ namespace storm { * verification calls will be answererd with respect to this model. * * @param model The model description that (symbolically) specifies the model to check. + * @param options Additional options for the abstraction-refinement process. * @param smtSolverFactory A factory used to create SMT solver when necessary. */ - explicit GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, std::shared_ptr const& smtSolverFactory = std::make_shared()); + explicit GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const& model, GameBasedMdpModelCheckerOptions const& options = GameBasedMdpModelCheckerOptions(), std::shared_ptr const& smtSolverFactory = std::make_shared()); /// Overridden methods from super class. - virtual bool canHandle(CheckTask const& checkTask) const override; - virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; - virtual std::unique_ptr computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) override; - + virtual bool canHandle(CheckTask const& checkTask) const override; + virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityProbabilities(Environment const& env, CheckTask const& checkTask) override; + private: /*! * Performs the core part of the abstraction-refinement loop. */ - std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); + std::unique_ptr performGameBasedAbstractionRefinement(Environment const& env, CheckTask const& checkTask, storm::expressions::Expression const& constraintExpression, storm::expressions::Expression const& targetStateExpression); + std::unique_ptr performSymbolicAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousQualitativeResult, boost::optional>& previousMinQuantitativeResult); + std::unique_ptr performExplicitAbstractionSolutionStep(Environment const& env, CheckTask const& checkTask, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& initialStates, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates, storm::abstraction::MenuGameRefiner const& refiner, boost::optional>& previousResult); + /*! * Retrieves the initial predicates for the abstraction. */ @@ -65,21 +126,26 @@ namespace storm { /*! * Derives the optimization direction of player 1. */ - storm::OptimizationDirection getPlayer1Direction(CheckTask const& checkTask); + storm::OptimizationDirection getPlayer1Direction(CheckTask const& checkTask); /*! * Performs a qualitative check on the the given game to compute the (player 1) states that have probability * 0 or 1, respectively, to reach a target state and only visiting constraint states before. */ - QualitativeGameResultMinMax computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates); + SymbolicQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousQualitativeResult, storm::abstraction::MenuGame const& game, storm::OptimizationDirection player1Direction, storm::dd::Bdd const& transitionMatrixBdd, storm::dd::Bdd const& constraintStates, storm::dd::Bdd const& targetStates); - void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game) const; + ExplicitQualitativeGameResultMinMax computeProb01States(boost::optional> const& previousResult, storm::dd::Odd const& odd, storm::OptimizationDirection player1Direction, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& player1RowGrouping, storm::storage::SparseMatrix const& player1BackwardTransitions, std::vector const& player2BackwardTransitions, storm::storage::BitVector const& constraintStates, storm::storage::BitVector const& targetStates, abstraction::ExplicitGameStrategyPair& minStrategyPair, abstraction::ExplicitGameStrategyPair& maxStrategyPair); + + void printStatistics(storm::abstraction::MenuGameAbstractor const& abstractor, storm::abstraction::MenuGame const& game, uint64_t refinements, uint64_t peakPlayer1States, uint64_t peakTransitions) const; /* * Retrieves the expression characterized by the formula. The formula needs to be propositional. */ storm::expressions::Expression getExpression(storm::logic::Formula const& formula); + /// The options customizing the abstraction-refinement process. + GameBasedMdpModelCheckerOptions options; + /// The preprocessed model that contains only one module/automaton and otherwhise corresponds to the semantics /// of the original model description. storm::storage::SymbolicModelDescription preprocessedModel; @@ -95,6 +161,36 @@ namespace storm { /// A flag indicating whether to reuse the quantitative results. bool reuseQuantitativeResults; + + /// The maximal number of abstractions to perform. + uint64_t maximalNumberOfAbstractions; + + /// The mode selected for solving the abstraction. + storm::settings::modules::AbstractionSettings::SolveMode solveMode; + + /// The currently used abstractor. + std::shared_ptr> abstractor; + + /// The performed number of refinement iterations. + uint64_t iteration; + + /// A flag indicating whether to fix player 1 strategies. + bool fixPlayer1Strategy; + + /// A flag indicating whether to fix player 2 strategies. + bool fixPlayer2Strategy; + + /// A flag that indicates whether debug mode is enabled. + bool debug; + + /// Data stored for statistics. + storm::utility::Stopwatch totalAbstractionWatch; + storm::utility::Stopwatch totalSolutionWatch; + storm::utility::Stopwatch totalRefinementWatch; + storm::utility::Stopwatch totalTranslationWatch; + storm::utility::Stopwatch totalStrategyProcessingWatch; + storm::utility::Stopwatch setupWatch; + storm::utility::Stopwatch totalWatch; }; } } diff --git a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp index dd6b2e8c1..4d2507288 100644 --- a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.cpp @@ -17,12 +17,7 @@ namespace storm { namespace modelchecker { template - HybridCtmcCslModelChecker::HybridCtmcCslModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - HybridCtmcCslModelChecker::HybridCtmcCslModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { + HybridCtmcCslModelChecker::HybridCtmcCslModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } @@ -53,7 +48,7 @@ namespace storm { SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -72,7 +67,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -95,7 +90,7 @@ namespace storm { upperBound = storm::utility::infinity(); } - return storm::modelchecker::helper::HybridCtmcCslHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), lowerBound, upperBound, *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), lowerBound, upperBound); } template @@ -103,7 +98,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(!rewardPathFormula.isStepBounded(), storm::exceptions::NotImplementedException, "Currently step-bounded properties on CTMCs are not supported."); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -111,7 +106,7 @@ namespace storm { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.getTimeBoundReference().isTimeBound(), storm::exceptions::NotImplementedException, "Currently step-bounded and reward-bounded properties on CTMCs are not supported."); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template @@ -120,12 +115,12 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector()); } template std::unique_ptr HybridCtmcCslModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), *linearEquationSolverFactory); + return storm::modelchecker::helper::HybridCtmcCslHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel("")); } // Explicitly instantiate the model checker. diff --git a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h index 19189f361..f66f3c10e 100644 --- a/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/HybridCtmcCslModelChecker.h @@ -20,7 +20,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridCtmcCslModelChecker(ModelType const& model); - explicit HybridCtmcCslModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -41,8 +40,6 @@ namespace storm { template::SupportsExponential, int>::type = 0> bool canHandleImplementation(CheckTask const& checkTask) const; - // An object that is used for solving linear equations and performing matrix-vector multiplication. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp index c9467b9fe..3cedc1fab 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.cpp @@ -24,12 +24,7 @@ namespace storm { namespace modelchecker { template - SparseCtmcCslModelChecker::SparseCtmcCslModelChecker(SparseCtmcModelType const& model) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - SparseCtmcCslModelChecker::SparseCtmcCslModelChecker(SparseCtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { + SparseCtmcCslModelChecker::SparseCtmcCslModelChecker(SparseCtmcModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } @@ -42,14 +37,14 @@ namespace storm { template::SupportsExponential, int>::type> bool SparseCtmcCslModelChecker::canHandleImplementation(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true)); + return formula.isInFragment(storm::logic::csrl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTotalRewardFormulasAllowed(true)); } template template::SupportsExponential, int>::type> bool SparseCtmcCslModelChecker::canHandleImplementation(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setGloballyFormulasAllowed(false).setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeAllowed(true).setTotalRewardFormulasAllowed(true)); } template @@ -72,7 +67,7 @@ namespace storm { upperBound = storm::utility::infinity(); } - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), this->getModel().getExitRateVector(), checkTask.isQualitativeSet(), lowerBound, upperBound, *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), this->getModel().getExitRateVector(), checkTask.isQualitativeSet(), lowerBound, upperBound); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -81,7 +76,7 @@ namespace storm { storm::logic::NextFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -92,7 +87,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -100,7 +95,7 @@ namespace storm { std::unique_ptr SparseCtmcCslModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(!rewardPathFormula.isStepBounded(), storm::exceptions::NotImplementedException, "Currently step-bounded properties on CTMCs are not supported."); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -108,7 +103,7 @@ namespace storm { std::unique_ptr SparseCtmcCslModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.getTimeBoundReference().isTimeBound(), storm::exceptions::NotImplementedException, "Currently step-bounded and reward-bounded properties on CTMCs are not supported."); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -118,7 +113,13 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } + + template + std::unique_ptr SparseCtmcCslModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -129,14 +130,14 @@ namespace storm { ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); storm::storage::SparseMatrix probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper::computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, subResult.getTruthValuesVector(), &this->getModel().getExitRateVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseCtmcCslModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { storm::storage::SparseMatrix probabilityMatrix = storm::modelchecker::helper::SparseCtmcCslHelper::computeProbabilityMatrix(this->getModel().getTransitionMatrix(), this->getModel().getExitRateVector()); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), &this->getModel().getExitRateVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), probabilityMatrix, checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), &this->getModel().getExitRateVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -146,7 +147,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRateVector(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } diff --git a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h index 86a43778e..5bf4735d0 100644 --- a/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseCtmcCslModelChecker.h @@ -20,7 +20,6 @@ namespace storm { typedef typename SparseCtmcModelType::RewardModelType RewardModelType; explicit SparseCtmcCslModelChecker(SparseCtmcModelType const& model); - explicit SparseCtmcCslModelChecker(SparseCtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -34,6 +33,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; private: template::SupportsExponential, int>::type = 0> @@ -42,8 +42,6 @@ namespace storm { template::SupportsExponential, int>::type = 0> bool canHandleImplementation(CheckTask const& checkTask) const; - // An object that is used for solving linear equations and performing matrix-vector multiplication. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp index 026c1fa5c..929ea8721 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.cpp @@ -22,19 +22,14 @@ namespace storm { namespace modelchecker { template - SparseMarkovAutomatonCslModelChecker::SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model, std::unique_ptr>&& minMaxLinearEquationSolverFactory) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::move(minMaxLinearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - SparseMarkovAutomatonCslModelChecker::SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::make_unique>()) { + SparseMarkovAutomatonCslModelChecker::SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } template bool SparseMarkovAutomatonCslModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if(formula.isInFragment(storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true))) { + if(formula.isInFragment(storm::logic::csl().setGloballyFormulasAllowed(false).setNextFormulasAllowed(false).setRewardOperatorsAllowed(true).setReachabilityRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setTimeAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setLongRunAverageRewardFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula @@ -66,7 +61,7 @@ namespace storm { upperBound = storm::utility::infinity(); } - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), rightResult.getTruthValuesVector(), std::make_pair(lowerBound, upperBound)); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -78,7 +73,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -90,11 +85,20 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } - + + template + std::unique_ptr SparseMarkovAutomatonCslModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute reachability rewards in non-closed Markov automaton."); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeTotalRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel("")); + + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); + } + template std::unique_ptr SparseMarkovAutomatonCslModelChecker::computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) { storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); @@ -103,7 +107,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -111,7 +115,7 @@ namespace storm { std::unique_ptr SparseMarkovAutomatonCslModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(this->getModel().isClosed(), storm::exceptions::InvalidPropertyException, "Unable to compute long run average rewards in non-closed Markov automaton."); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } @@ -123,7 +127,7 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMarkovAutomatonCslHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), this->getModel().getExitRates(), this->getModel().getMarkovianStates(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } diff --git a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h index 57b1a63a6..3bd557dd4 100644 --- a/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h +++ b/src/storm/modelchecker/csl/SparseMarkovAutomatonCslModelChecker.h @@ -17,7 +17,6 @@ namespace storm { typedef typename SparseMarkovAutomatonModelType::ValueType ValueType; typedef typename SparseMarkovAutomatonModelType::RewardModelType RewardModelType; - explicit SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model, std::unique_ptr>&& minMaxLinearEquationSolver); explicit SparseMarkovAutomatonCslModelChecker(SparseMarkovAutomatonModelType const& model); // The implemented methods of the AbstractModelChecker interface. @@ -25,14 +24,12 @@ namespace storm { virtual std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeUntilProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices. - std::unique_ptr> minMaxLinearEquationSolverFactory; }; } } diff --git a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp index 7713719ed..d76a28884 100644 --- a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.cpp @@ -18,6 +18,8 @@ #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" +#include "storm/utility/Stopwatch.h" + #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/InvalidOperationException.h" @@ -27,9 +29,9 @@ namespace storm { namespace helper { template - std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative) { - return HybridDtmcPrctlHelper::computeReachabilityRewards(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), rewardModel.divideStateRewardVector(exitRateVector), targetStates, qualitative, linearEquationSolverFactory); + return HybridDtmcPrctlHelper::computeReachabilityRewards(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), rewardModel.divideStateRewardVector(exitRateVector), targetStates, qualitative); } template @@ -38,16 +40,16 @@ namespace storm { } template - std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return HybridDtmcPrctlHelper::computeUntilProbabilities(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), phiStates, psiStates, qualitative, linearEquationSolverFactory); + std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative) { + return HybridDtmcPrctlHelper::computeUntilProbabilities(env, model, computeProbabilityMatrix(rateMatrix, exitRateVector), phiStates, psiStates, qualitative); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound) { // If the time bounds are [0, inf], we rather call untimed reachability. if (storm::utility::isZero(lowerBound) && upperBound == storm::utility::infinity()) { - return computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative, linearEquationSolverFactory); + return computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative); } // From this point on, we know that we have to solve a more complicated problem [t, t'] with either t != 0 @@ -79,16 +81,20 @@ namespace storm { // Compute the vector that is to be added as a compensation for removing the absorbing states. storm::dd::Add b = (statesWithProbabilityGreater0NonPsi.template toAdd() * rateMatrix * psiStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd()).sumAbstract(model.getColumnVariables()) / model.getManager().getConstant(uniformizationRate); + storm::utility::Stopwatch conversionWatch(true); + // Create an ODD for the translation to an explicit representation. storm::dd::Odd odd = statesWithProbabilityGreater0NonPsi.createOdd(); // Convert the symbolic parts to their explicit representation. storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); std::vector explicitB = b.toVector(odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); // Finally compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); - std::vector subresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound, uniformizationRate, values); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), (psiStates || !statesWithProbabilityGreater0) && model.getReachableStates(), @@ -98,7 +104,7 @@ namespace storm { // Start by computing the (unbounded) reachability probabilities of reaching psi states while // staying in phi states. - std::unique_ptr unboundedResult = computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative, linearEquationSolverFactory); + std::unique_ptr unboundedResult = computeUntilProbabilities(env, model, rateMatrix, exitRateVector, phiStates, psiStates, qualitative); // Compute the set of relevant states. storm::dd::Bdd relevantStates = statesWithProbabilityGreater0 && phiStates; @@ -106,12 +112,18 @@ namespace storm { // Filter the unbounded result such that it only contains values for the relevant states. unboundedResult->filter(SymbolicQualitativeCheckResult(model.getReachableStates(), relevantStates)); + storm::utility::Stopwatch conversionWatch; + // Build an ODD for the relevant states. + conversionWatch.start(); storm::dd::Odd odd = relevantStates.createOdd(); + conversionWatch.stop(); std::vector result; if (unboundedResult->isHybridQuantitativeCheckResult()) { + conversionWatch.start(); std::unique_ptr explicitUnboundedResult = unboundedResult->asHybridQuantitativeCheckResult().toExplicitQuantitativeCheckResult(); + conversionWatch.stop(); result = std::move(explicitUnboundedResult->asExplicitQuantitativeCheckResult().getValueVector()); } else { STORM_LOG_THROW(unboundedResult->isSymbolicQuantitativeCheckResult(), storm::exceptions::InvalidStateException, "Expected check result of different type."); @@ -123,10 +135,13 @@ namespace storm { // Compute the uniformized matrix. storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, relevantStates, uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Compute the transient probabilities. - result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, result, linearEquationSolverFactory); + result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, result); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !relevantStates && model.getReachableStates(), model.getManager().template getAddZero(), relevantStates, odd, result)); } else { @@ -146,13 +161,15 @@ namespace storm { storm::dd::Add b = (statesWithProbabilityGreater0NonPsi.template toAdd() * rateMatrix * psiStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd()).sumAbstract(model.getColumnVariables()) / model.getManager().getConstant(uniformizationRate); // Build an ODD for the relevant states and translate the symbolic parts to their explicit representation. + storm::utility::Stopwatch conversionWatch(true); storm::dd::Odd odd = statesWithProbabilityGreater0NonPsi.createOdd(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); std::vector explicitB = b.toVector(odd); - + conversionWatch.stop(); + // Compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNonZeroCount(), storm::utility::zero()); - std::vector subResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound - lowerBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, &explicitB, upperBound - lowerBound, uniformizationRate, values); // Transform the explicit result to a hybrid check result, so we can easily convert it to // a symbolic qualitative format. @@ -164,13 +181,15 @@ namespace storm { // Filter the unbounded result such that it only contains values for the relevant states. hybridResult.filter(SymbolicQualitativeCheckResult(model.getReachableStates(), relevantStates)); - + // Build an ODD for the relevant states. + conversionWatch.start(); odd = relevantStates.createOdd(); std::unique_ptr explicitResult = hybridResult.toExplicitQuantitativeCheckResult(); + conversionWatch.stop(); std::vector newSubresult = std::move(explicitResult->asExplicitQuantitativeCheckResult().getValueVector()); - + // Then compute the transient probabilities of being in such a state after t time units. For this, // we must re-uniformize the CTMC, so we need to compute the second uniformized matrix. uniformizationRate = 1.02 * (relevantStates.template toAdd() * exitRateVector).getMax(); @@ -185,19 +204,26 @@ namespace storm { // Finally, we compute the second set of transient probabilities. uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, relevantStates, uniformizationRate); + conversionWatch.start(); explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - - newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !relevantStates && model.getReachableStates(), model.getManager().template getAddZero(), relevantStates, odd, newSubresult)); } else { // In this case, the interval is of the form [t, t] with t != 0, t != inf. + storm::utility::Stopwatch conversionWatch; + // Build an ODD for the relevant states. + conversionWatch.start(); storm::dd::Odd odd = statesWithProbabilityGreater0.createOdd(); - + std::vector newSubresult = psiStates.template toAdd().toVector(odd); - + conversionWatch.stop(); + // Then compute the transient probabilities of being in such a state after t time units. For this, // we must re-uniformize the CTMC, so we need to compute the second uniformized matrix. ValueType uniformizationRate = 1.02 * (statesWithProbabilityGreater0.template toAdd() * exitRateVector).getMax(); @@ -205,9 +231,12 @@ namespace storm { // Finally, we compute the second set of transient probabilities. storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, statesWithProbabilityGreater0, uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - - newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + newSubresult = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), !statesWithProbabilityGreater0 && model.getReachableStates(), model.getManager().template getAddZero(), statesWithProbabilityGreater0, odd, newSubresult)); } @@ -219,18 +248,22 @@ namespace storm { } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + storm::utility::Stopwatch conversionWatch; + // Create ODD for the translation. + conversionWatch.start(); storm::dd::Odd odd = model.getReachableStates().createOdd(); + conversionWatch.stop(); // Initialize result to state rewards of the model. std::vector result = rewardModel.getStateRewardVector().toVector(odd); @@ -242,20 +275,24 @@ namespace storm { storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, model.getReachableStates(), uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); - result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, result, linearEquationSolverFactory); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, result); } return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, result)); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing instantaneous rewards is unsupported for this value type."); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -270,55 +307,72 @@ namespace storm { ValueType uniformizationRate = 1.02 * exitRateVector.getMax(); STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); + storm::utility::Stopwatch conversionWatch; + // Create ODD for the translation. + conversionWatch.start(); storm::dd::Odd odd = model.getReachableStates().createOdd(); + conversionWatch.stop(); // Compute the uniformized matrix. storm::dd::Add uniformizedMatrix = computeUniformizedMatrix(model, rateMatrix, exitRateVector, model.getReachableStates(), uniformizationRate); + conversionWatch.start(); storm::storage::SparseMatrix explicitUniformizedMatrix = uniformizedMatrix.toMatrix(odd, odd); + conversionWatch.stop(); // Then compute the state reward vector to use in the computation. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, model.getColumnVariables(), exitRateVector, false); + conversionWatch.start(); std::vector explicitTotalRewardVector = totalRewardVector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Finally, compute the transient probabilities. - std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, explicitTotalRewardVector, linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeTransientProbabilities(env, explicitUniformizedMatrix, nullptr, timeBound, uniformizationRate, explicitTotalRewardVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } template::SupportsExponential, int>::type> - std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing cumulative rewards is unsupported for this value type."); } template - std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates) { storm::dd::Add probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector explicitExitRateVector = exitRateVector.toVector(odd); - - std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, psiStates.toVector(odd), &explicitExitRateVector, linearEquationSolverFactory); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, psiStates.toVector(odd), &explicitExitRateVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } template - std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel) { STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); storm::dd::Add probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); + storm::utility::Stopwatch conversionWatch(true); + // Create ODD for the translation. storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = probabilityMatrix.toMatrix(odd, odd); std::vector explicitExitRateVector = exitRateVector.toVector(odd); - - std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, model.getColumnVariables(), exitRateVector, true).toVector(odd), &explicitExitRateVector, linearEquationSolverFactory); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + std::vector result = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, model.getColumnVariables(), exitRateVector, true).toVector(odd), &explicitExitRateVector); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } @@ -349,50 +403,50 @@ namespace storm { // Explicit instantiations. // Cudd, double. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, double uniformizationRate); // Sylvan, double. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, double uniformizationRate); // Sylvan, rational number. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, storm::RationalNumber uniformizationRate); // Sylvan, rational function. - template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); + template std::unique_ptr HybridCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); + template std::unique_ptr HybridCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template std::unique_ptr HybridCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); - template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::unique_ptr HybridCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); template storm::dd::Add HybridCtmcCslHelper::computeProbabilityMatrix(storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector); template storm::dd::Add HybridCtmcCslHelper::computeUniformizedMatrix(storm::models::symbolic::Ctmc const& model, storm::dd::Add const& transitionMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& maybeStates, storm::RationalFunction uniformizationRate); diff --git a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h index 5e27a0709..8814ca9a7 100644 --- a/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h +++ b/src/storm/modelchecker/csl/helper/HybridCtmcCslHelper.h @@ -21,37 +21,37 @@ namespace storm { class HybridCtmcCslHelper { public: template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, double lowerBound, double upperBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template::SupportsExponential, int>::type = 0> - static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, double timeBound); template - static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); template - static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); template - static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& psiStates); template static std::unique_ptr computeNextProbabilities(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, storm::dd::Bdd const& nextStates); template - static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Ctmc const& model, storm::dd::Add const& rateMatrix, storm::dd::Add const& exitRateVector, typename storm::models::symbolic::Model::RewardModelType const& rewardModel); /*! * Converts the given rate-matrix into a time-abstract probability matrix. diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp index 90d556133..634eaf806 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.cpp @@ -9,6 +9,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" @@ -29,13 +30,13 @@ namespace storm { namespace modelchecker { namespace helper { template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound) { uint_fast64_t numberOfStates = rateMatrix.getRowCount(); // If the time bounds are [0, inf], we rather call untimed reachability. if (storm::utility::isZero(lowerBound) && upperBound == storm::utility::infinity()) { - return computeUntilProbabilities(env, std::move(goal), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative, linearEquationSolverFactory); + return computeUntilProbabilities(env, std::move(goal), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative); } // From this point on, we know that we have to solve a more complicated problem [t, t'] with either t != 0 @@ -80,7 +81,7 @@ namespace storm { // Finally compute the transient probabilities. std::vector values(statesWithProbabilityGreater0NonPsi.getNumberOfSetBits(), storm::utility::zero()); - std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound, uniformizationRate, values); result = std::vector(numberOfStates, storm::utility::zero()); storm::utility::vector::setVectorValues(result, statesWithProbabilityGreater0NonPsi, subresult); @@ -90,7 +91,7 @@ namespace storm { // Start by computing the (unbounded) reachability probabilities of reaching psi states while // staying in phi states. - result = computeUntilProbabilities(env, storm::solver::SolveGoal(), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative, linearEquationSolverFactory); + result = computeUntilProbabilities(env, storm::solver::SolveGoal(), rateMatrix, backwardTransitions, exitRates, phiStates, psiStates, qualitative); // Determine the set of states that must be considered further. storm::storage::BitVector relevantStates = statesWithProbabilityGreater0 & phiStates; @@ -108,7 +109,7 @@ namespace storm { storm::storage::SparseMatrix uniformizedMatrix = computeUniformizedMatrix(rateMatrix, relevantStates, uniformizationRate, exitRates); // Compute the transient probabilities. - subResult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, subResult, linearEquationSolverFactory); + subResult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, subResult); // Fill in the correct values. storm::utility::vector::setVectorValues(result, ~relevantStates, storm::utility::zero()); @@ -138,7 +139,7 @@ namespace storm { // Start by computing the transient probabilities of reaching a psi state in time t' - t. std::vector values(statesWithProbabilityGreater0NonPsi.getNumberOfSetBits(), storm::utility::zero()); - std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound - lowerBound, uniformizationRate, values, linearEquationSolverFactory); + std::vector subresult = computeTransientProbabilities(env, uniformizedMatrix, &b, upperBound - lowerBound, uniformizationRate, values); storm::storage::BitVector relevantStates = statesWithProbabilityGreater0 & phiStates; std::vector newSubresult = std::vector(relevantStates.getNumberOfSetBits()); @@ -156,7 +157,7 @@ namespace storm { // Finally, we compute the second set of transient probabilities. uniformizedMatrix = computeUniformizedMatrix(rateMatrix, relevantStates, uniformizationRate, exitRates); - newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); // Fill in the correct values. result = std::vector(numberOfStates, storm::utility::zero()); @@ -179,7 +180,7 @@ namespace storm { // Finally, we compute the second set of transient probabilities. storm::storage::SparseMatrix uniformizedMatrix = computeUniformizedMatrix(rateMatrix, statesWithProbabilityGreater0, uniformizationRate, exitRates); - newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult, linearEquationSolverFactory); + newSubresult = computeTransientProbabilities(env, uniformizedMatrix, nullptr, lowerBound, uniformizationRate, newSubresult); // Fill in the correct values. result = std::vector(numberOfStates, storm::utility::zero()); @@ -196,22 +197,22 @@ namespace storm { } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::storage::BitVector const&, storm::storage::BitVector const&, std::vector const&, bool, double, double, storm::solver::LinearEquationSolverFactory const&) { + std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::storage::BitVector const&, storm::storage::BitVector const&, std::vector const&, bool, double, double) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } template - std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseDtmcPrctlHelper::computeUntilProbabilities(env, std::move(goal), computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, phiStates, psiStates, qualitative, linearEquationSolverFactory); + std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative) { + return SparseDtmcPrctlHelper::computeUntilProbabilities(env, std::move(goal), computeProbabilityMatrix(rateMatrix, exitRateVector), backwardTransitions, phiStates, psiStates, qualitative); } template - std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseDtmcPrctlHelper::computeNextProbabilities(env, computeProbabilityMatrix(rateMatrix, exitRateVector), nextStates, linearEquationSolverFactory); + std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates) { + return SparseDtmcPrctlHelper::computeNextProbabilities(env, computeProbabilityMatrix(rateMatrix, exitRateVector), nextStates); } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -230,19 +231,19 @@ namespace storm { STORM_LOG_THROW(uniformizationRate > 0, storm::exceptions::InvalidStateException, "The uniformization rate must be positive."); storm::storage::SparseMatrix uniformizedMatrix = computeUniformizedMatrix(rateMatrix, storm::storage::BitVector(numberOfStates, true), uniformizationRate, exitRateVector); - result = computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, result, linearEquationSolverFactory); + result = computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, result); } return result; } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double, storm::solver::LinearEquationSolverFactory const&) { + std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing instantaneous rewards is unsupported for this value type."); } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -269,16 +270,16 @@ namespace storm { std::vector totalRewardVector = rewardModel.getTotalRewardVector(rateMatrix, exitRateVector); // Finally, compute the transient probabilities. - return computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, totalRewardVector, linearEquationSolverFactory); + return computeTransientProbabilities(env, uniformizedMatrix, nullptr, timeBound, uniformizationRate, totalRewardVector); } template ::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double, storm::solver::LinearEquationSolverFactory const&) { + std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const&, std::vector const&, RewardModelType const&, double) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing cumulative rewards is unsupported for this value type."); } template - std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative) { // Compute expected time on CTMC by reduction to DTMC with rewards. storm::storage::SparseMatrix probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); @@ -294,11 +295,11 @@ namespace storm { } } - return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative, linearEquationSolverFactory); + return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative); } template - std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative) { STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); storm::storage::SparseMatrix probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); @@ -325,11 +326,43 @@ namespace storm { totalRewardVector = rewardModel.getStateActionRewardVector(); } - return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative, linearEquationSolverFactory); + return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, totalRewardVector, targetStates, qualitative); + } + + template + std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, bool qualitative) { + STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + + storm::storage::SparseMatrix probabilityMatrix = computeProbabilityMatrix(rateMatrix, exitRateVector); + + std::vector totalRewardVector; + if (rewardModel.hasStateRewards()) { + totalRewardVector = rewardModel.getStateRewardVector(); + typename std::vector::const_iterator it2 = exitRateVector.begin(); + for (typename std::vector::iterator it1 = totalRewardVector.begin(), ite1 = totalRewardVector.end(); it1 != ite1; ++it1, ++it2) { + *it1 /= *it2; + } + if (rewardModel.hasStateActionRewards()) { + storm::utility::vector::addVectors(totalRewardVector, rewardModel.getStateActionRewardVector(), totalRewardVector); + } + if (rewardModel.hasTransitionRewards()) { + storm::utility::vector::addVectors(totalRewardVector, probabilityMatrix.getPointwiseProductRowSumVector(rewardModel.getTransitionRewardMatrix()), totalRewardVector); + } + } else if (rewardModel.hasTransitionRewards()) { + totalRewardVector = probabilityMatrix.getPointwiseProductRowSumVector(rewardModel.getTransitionRewardMatrix()); + if (rewardModel.hasStateActionRewards()) { + storm::utility::vector::addVectors(totalRewardVector, rewardModel.getStateActionRewardVector(), totalRewardVector); + } + } else { + totalRewardVector = rewardModel.getStateActionRewardVector(); + } + + RewardModelType dtmcRewardModel(std::move(totalRewardVector)); + return storm::modelchecker::helper::SparseDtmcPrctlHelper::computeTotalRewards(env, std::move(goal), probabilityMatrix, backwardTransitions, dtmcRewardModel, qualitative); } template - std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector) { // If there are no goal states, we avoid the computation and directly return zero. uint_fast64_t numberOfStates = probabilityMatrix.getRowCount(); @@ -352,30 +385,28 @@ namespace storm { } return zero; }, - exitRateVector, - linearEquationSolverFactory); + exitRateVector); } template - std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector) { // Only compute the result if the model has a state-based reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); - return computeLongRunAverageRewards(env, std::move(goal), probabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, *exitRateVector), exitRateVector, linearEquationSolverFactory); + return computeLongRunAverageRewards(env, std::move(goal), probabilityMatrix, rewardModel.getTotalRewardVector(probabilityMatrix, *exitRateVector), exitRateVector); } template - std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector) { return computeLongRunAverages(env, std::move(goal), probabilityMatrix, [&stateRewardVector] (storm::storage::sparse::state_type const& state) -> ValueType { return stateRewardVector[state]; }, - exitRateVector, - linearEquationSolverFactory); + exitRateVector); } template - std::vector SparseCtmcCslHelper::computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory){ + std::vector SparseCtmcCslHelper::computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector){ uint_fast64_t numberOfStates = probabilityMatrix.getRowCount(); // Start by decomposing the CTMC into its BSCCs. @@ -447,35 +478,56 @@ namespace storm { } } + // Build a different system depending on the problem format of the equation solver. + // Check solver requirements. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; + auto requirements = linearEquationSolverFactory.getRequirements(env); + requirements.clearLowerBounds(); + requirements.clearUpperBounds(); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); + + bool fixedPointSystem = false; + if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::FixedPointSystem) { + fixedPointSystem = true; + } + // Now build the final equation system matrix, the initial guess and the right-hand side in one go. std::vector bsccEquationSystemRightSide(bsccEquationSystem.getColumnCount(), zero); storm::storage::SparseMatrixBuilder builder; for (uint_fast64_t row = 0; row < bsccEquationSystem.getRowCount(); ++row) { - + // If the current row is the first one belonging to a BSCC, we substitute it by the constraint that the // values for states of this BSCC must sum to one. However, in order to have a non-zero value on the // diagonal, we add the constraint of the BSCC that produces a 1 on the diagonal. if (firstStatesInBsccs.get(row)) { uint_fast64_t requiredBscc = stateToBsccIndexMap[row]; storm::storage::StronglyConnectedComponent const& bscc = bsccDecomposition[requiredBscc]; - - for (auto const& state : bscc) { - builder.addNextValue(row, indexInStatesInBsccs[state], one); + + if (fixedPointSystem) { + for (auto const& state : bscc) { + if (row == indexInStatesInBsccs[state]) { + builder.addNextValue(row, indexInStatesInBsccs[state], zero); + } else { + builder.addNextValue(row, indexInStatesInBsccs[state], -one); + } + } + } else { + for (auto const& state : bscc) { + builder.addNextValue(row, indexInStatesInBsccs[state], one); + } } bsccEquationSystemRightSide[row] = one; - } else { - // Otherwise, we copy the row, and subtract 1 from the diagonal. + // Otherwise, we copy the row, and subtract 1 from the diagonal (only for the equation solver format). for (auto& entry : bsccEquationSystem.getRow(row)) { - if (entry.getColumn() == row) { - builder.addNextValue(row, entry.getColumn(), entry.getValue() - one); - } else { + if (fixedPointSystem || entry.getColumn() != row) { builder.addNextValue(row, entry.getColumn(), entry.getValue()); + } else { + builder.addNextValue(row, entry.getColumn(), entry.getValue() - one); } } } - } // Create the initial guess for the LRAs. We take a uniform distribution over all states in a BSCC. @@ -489,13 +541,10 @@ namespace storm { } bsccEquationSystem = builder.build(); - { - // Check solver requirements - STORM_LOG_THROW(linearEquationSolverFactory.getRequirements(env).empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); - // Check whether we have the right input format for the solver. - STORM_LOG_THROW(linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem, storm::exceptions::FormatUnsupportedBySolverException, "The selected solver does not support the required format."); std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(bsccEquationSystem)); + solver->setLowerBound(storm::utility::zero()); + solver->setUpperBound(storm::utility::one()); solver->solveEquations(env, bsccEquationSystemSolution, bsccEquationSystemRightSide); } @@ -563,8 +612,10 @@ namespace storm { rewardSolution = std::vector(rewardEquationSystemMatrix.getColumnCount(), one); { + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; // Check solver requirements - STORM_LOG_THROW(linearEquationSolverFactory.getRequirements(env).empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + auto requirements = linearEquationSolverFactory.getRequirements(env); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); // Check whether we have the right input format for the solver. STORM_LOG_THROW(linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem, storm::exceptions::FormatUnsupportedBySolverException, "The selected solver does not support the required format."); std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(rewardEquationSystemMatrix)); @@ -622,7 +673,7 @@ namespace storm { } template::SupportsExponential, int>::type> - std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values) { ValueType lambda = timeBound * uniformizationRate; @@ -671,18 +722,16 @@ namespace storm { } } - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(uniformizedMatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->setCachingEnabled(true); - + auto multiplier = storm::solver::MultiplierFactory().create(env, uniformizedMatrix); if (!useMixedPoissonProbabilities && foxGlynnResult.left > 1) { // Perform the matrix-vector multiplications (without adding). - solver->repeatedMultiply(values, addVector, foxGlynnResult.left - 1); + multiplier->repeatedMultiply(env, values, addVector, foxGlynnResult.left - 1); } else if (useMixedPoissonProbabilities) { std::function addAndScale = [&uniformizationRate] (ValueType const& a, ValueType const& b) { return a + b / uniformizationRate; }; // For the iterations below the left truncation point, we need to add and scale the result with the uniformization rate. for (uint_fast64_t index = 1; index < startingIteration; ++index) { - solver->repeatedMultiply(values, nullptr, 1); + multiplier->multiply(env, values, nullptr, values); storm::utility::vector::applyPointwise(result, values, result, addAndScale); } } @@ -692,7 +741,7 @@ namespace storm { ValueType weight = 0; std::function addAndScale = [&weight] (ValueType const& a, ValueType const& b) { return a + weight * b; }; for (uint_fast64_t index = startingIteration; index <= foxGlynnResult.right; ++index) { - solver->repeatedMultiply(values, addVector, 1); + multiplier->multiply(env, values, addVector, values); weight = foxGlynnResult.weights[index - foxGlynnResult.left]; storm::utility::vector::applyPointwise(result, values, result, addAndScale); @@ -721,7 +770,7 @@ namespace storm { for (uint_fast64_t row = 0; row < generatorMatrix.getRowCount(); ++row) { for (auto& entry : generatorMatrix.getRow(row)) { if (entry.getColumn() == row) { - entry.setValue(-exitRates[row]); + entry.setValue(-exitRates[row] + entry.getValue()); } } } @@ -730,58 +779,63 @@ namespace storm { } - template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); - template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); + + template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); - template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative); - template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); template storm::storage::SparseMatrix SparseCtmcCslHelper::computeUniformizedMatrix(storm::storage::SparseMatrix const& rateMatrix, storm::storage::BitVector const& maybeStates, double uniformizationRate, std::vector const& exitRates); - template std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, double timeBound, double uniformizationRate, std::vector values, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, double timeBound, double uniformizationRate, std::vector values); #ifdef STORM_HAVE_CARL - template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); + template std::vector SparseCtmcCslHelper::computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); + + template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); + template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); - template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); + template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); - template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); + template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); - template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative); + template std::vector SparseCtmcCslHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative); - template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); + template std::vector SparseCtmcCslHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); - template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); - template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); + template std::vector SparseCtmcCslHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::models::sparse::StandardRewardModel const& rewardModel, double timeBound); template storm::storage::SparseMatrix SparseCtmcCslHelper::computeProbabilityMatrix(storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRates); template storm::storage::SparseMatrix SparseCtmcCslHelper::computeProbabilityMatrix(storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRates); diff --git a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h index e1e6f3c43..b6e7b508c 100644 --- a/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseCtmcCslHelper.h @@ -19,43 +19,46 @@ namespace storm { class SparseCtmcCslHelper { public: template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, std::vector const& exitRates, bool qualitative, double lowerBound, double upperBound); template - static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); template - static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& nextStates); template ::SupportsExponential, int>::type = 0> - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template ::SupportsExponential, int>::type = 0> - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, std::vector const& exitRateVector, RewardModelType const& rewardModel, double timeBound); template - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative); + + template + static std::vector computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, RewardModelType const& rewardModel, bool qualitative); template - static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, storm::storage::BitVector const& psiStates, std::vector const* exitRateVector); template - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, RewardModelType const& rewardModel, std::vector const* exitRateVector); template - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::vector const& stateRewardVector, std::vector const* exitRateVector); template - static std::vector computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& rateMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& targetStates, bool qualitative); /*! * Computes the matrix representing the transitions of the uniformized CTMC. @@ -84,7 +87,7 @@ namespace storm { * @return The vector of transient probabilities. */ template::SupportsExponential, int>::type = 0> - static std::vector computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeTransientProbabilities(Environment const& env, storm::storage::SparseMatrix const& uniformizedMatrix, std::vector const* addVector, ValueType timeBound, ValueType uniformizationRate, std::vector values); /*! * Converts the given rate-matrix into a time-abstract probability matrix. @@ -108,7 +111,7 @@ namespace storm { private: template - static std::vector computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverages(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& probabilityMatrix, std::function const& valueGetter, std::vector const* exitRateVector); }; } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index ad3db92f0..6e6a39acf 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -21,8 +21,6 @@ #include "storm/storage/expressions/Expression.h" #include "storm/storage/expressions/ExpressionManager.h" -#include "storm/utility/numerical.h" - #include "storm/solver/MinMaxLinearEquationSolver.h" #include "storm/solver/LpSolver.h" @@ -34,9 +32,353 @@ namespace storm { namespace modelchecker { namespace helper { + + template + void calculateUnifPlusVector(Environment const& env, uint64_t k, uint64_t state, uint64_t const kind, ValueType lambda, uint64_t numberOfProbabilisticChoices, std::vector> const & relativeReachability, OptimizationDirection dir, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const& poisson, bool cycleFree) { + + if (unifVectors[kind][k][state] != -1) { + // Result already calculated. + return; + } + + auto numberOfStates = fullTransitionMatrix.getRowGroupCount(); + uint64_t N = unifVectors[kind].size() - 1; + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + ValueType res; + + // First case, k==N, independent from kind of state. + if (k == N) { + unifVectors[kind][k][state] = storm::utility::zero(); + return; + } + + // Goal state, independent from kind of state. + if (psiStates[state]) { + if (kind == 0) { + // Vd + res = storm::utility::zero(); + for (uint64_t i = k; i < N; ++i){ + if (i >= poisson.left && i <= poisson.right) { + ValueType between = poisson.weights[i - poisson.left]; + res += between; + } + } + unifVectors[kind][k][state] = res; + } else { + // WU + unifVectors[kind][k][state] = storm::utility::one(); + } + return; + } + + // Markovian non-goal state. + if (markovianStates[state]) { + res = storm::utility::zero(); + for (auto const& element : fullTransitionMatrix.getRow(rowGroupIndices[state])) { + uint64_t to = element.getColumn(); + if (unifVectors[kind][k+1][to] == -1) { + calculateUnifPlusVector(env, k+1, to, kind, lambda, numberOfProbabilisticChoices, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + } + res += element.getValue()*unifVectors[kind][k+1][to]; + } + unifVectors[kind][k][state]=res; + return; + } + + // Probabilistic non-goal state. + if (cycleFree) { + // If the model is cycle free, do "slight value iteration". (What is that?) + res = -1; + for (uint64_t i = rowGroupIndices[state]; i < rowGroupIndices[state + 1]; ++i) { + auto row = fullTransitionMatrix.getRow(i); + ValueType between = 0; + for (auto const& element : row) { + uint64_t successor = element.getColumn(); + + // This should never happen, right? The model has no cycles, and therefore also no self-loops. + if (successor == state) { + continue; + } + + if (unifVectors[kind][k][successor] == -1) { + calculateUnifPlusVector(env, k, successor, kind, lambda, numberOfProbabilisticChoices, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + } + between += element.getValue() * unifVectors[kind][k][successor]; + } + if (maximize(dir)) { + res = storm::utility::max(res, between); + } else { + if (res != -1) { + res = storm::utility::min(res, between); + } else { + res = between; + } + } + } + unifVectors[kind][k][state] = res; + return; + } + + // If we arrived at this point, the model is not cycle free. Use the solver to solve the unterlying equation system. + uint64_t numberOfProbabilisticStates = numberOfStates - markovianStates.getNumberOfSetBits(); + std::vector b(numberOfProbabilisticChoices, storm::utility::zero()); + std::vector x(numberOfProbabilisticStates, storm::utility::zero()); + + // Compute right-hand side vector b. + uint64_t row = 0; + for (uint64_t i = 0; i < numberOfStates; ++i) { + if (markovianStates[i]) { + continue; + } - template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + for (auto j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; j++) { + uint64_t stateCount = 0; + res = storm::utility::zero(); + for (auto const& element : fullTransitionMatrix.getRow(j)) { + auto successor = element.getColumn(); + if (!markovianStates[successor]) { + continue; + } + + if (unifVectors[kind][k][successor] == -1) { + calculateUnifPlusVector(env, k, successor, kind, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + } + res = res + relativeReachability[j][stateCount] * unifVectors[kind][k][successor]; + ++stateCount; + } + + b[row] = res; + ++row; + } + } + + // Solve the equation system. + solver->solveEquations(env, dir, x, b); + + // Expand the solution for the probabilistic states to all states. + storm::utility::vector::setVectorValues(unifVectors[kind][k], ~markovianStates, x); + } + + template + void calculateVu(Environment const& env, std::vector> const& relativeReachability, OptimizationDirection dir, uint64_t k, uint64_t state, uint64_t const kind, ValueType lambda, uint64_t numberOfProbabilisticStates, std::vector>>& unifVectors, storm::storage::SparseMatrix const& fullTransitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::unique_ptr> const& solver, storm::utility::numerical::FoxGlynnResult const & poisson, bool cycleFree) { + + // Avoiding multiple computation of the same value. + if (unifVectors[1][k][state] != -1) { + return; + } + uint64_t N = unifVectors[1].size() - 1; + + ValueType res = storm::utility::zero(); + for (uint64_t i = k; i < N; ++i) { + if (unifVectors[2][N-1-(i-k)][state] == -1) { + calculateUnifPlusVector(env, N-1-(i-k), state, 2, lambda, numberOfProbabilisticStates, relativeReachability, dir, unifVectors, fullTransitionMatrix, markovianStates, psiStates, solver, poisson, cycleFree); + } + if (i >= poisson.left && i <= poisson.right) { + res += poisson.weights[i - poisson.left] * unifVectors[2][N-1-(i-k)][state]; + } + } + unifVectors[1][k][state] = res; + } + + template + void eliminateProbabilisticSelfLoops(storm::storage::SparseMatrix& transitionMatrix, storm::storage::BitVector const& markovianStates) { + auto const& rowGroupIndices = transitionMatrix.getRowGroupIndices(); + + for (uint64_t i = 0; i < transitionMatrix.getRowGroupCount(); ++i) { + if (markovianStates[i]) { + continue; + } + + for (uint64_t j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; j++) { + ValueType selfLoop = storm::utility::zero(); + for (auto const& element: transitionMatrix.getRow(j)){ + if (element.getColumn() == i) { + selfLoop += element.getValue(); + } + } + + if (storm::utility::isZero(selfLoop)) { + continue; + } + + for (auto& element : transitionMatrix.getRow(j)) { + if (element.getColumn() != i) { + if (!storm::utility::isOne(selfLoop)) { + element.setValue(element.getValue() / (storm::utility::one() - selfLoop)); + } + } else { + element.setValue(storm::utility::zero()); + } + } + } + } + } + + template + std::vector computeBoundedUntilProbabilitiesUnifPlus(Environment const& env, OptimizationDirection dir, std::pair const& boundsPair, std::vector const& exitRateVector, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates) { + STORM_LOG_TRACE("Using UnifPlus to compute bounded until probabilities."); + + // Obtain bit vectors to identify different kind of states. + storm::storage::BitVector allStates(markovianStates.size(), true); + storm::storage::BitVector probabilisticStates = ~markovianStates; + + // Searching for SCCs in probabilistic fragment to decide which algorithm is applied. + storm::storage::StronglyConnectedComponentDecomposition sccDecomposition(transitionMatrix, probabilisticStates, true, false); + bool cycleFree = sccDecomposition.empty(); + + // Vectors to store computed vectors. + std::vector>> unifVectors(3); + + // Transitions from goal states will be ignored. However, we mark them as non-probabilistic to make sure + // we do not apply the MDP algorithm to them. + storm::storage::BitVector markovianAndGoalStates = markovianStates | psiStates; + probabilisticStates &= ~psiStates; + + std::vector mutableExitRates = exitRateVector; + + // Extend the transition matrix with diagonal entries so we can change them easily during the uniformization step. + typename storm::storage::SparseMatrix fullTransitionMatrix = transitionMatrix.getSubmatrix(true, allStates, allStates, true); + + // Eliminate self-loops of probabilistic states. Is this really needed for the "slight value iteration" process? + eliminateProbabilisticSelfLoops(fullTransitionMatrix, markovianAndGoalStates); + typename storm::storage::SparseMatrix probMatrix; + uint64_t numberOfProbabilisticChoices = 0; + if (!probabilisticStates.empty()) { + probMatrix = fullTransitionMatrix.getSubmatrix(true, probabilisticStates, probabilisticStates, true); + numberOfProbabilisticChoices = probMatrix.getRowCount(); + } + + // Get row grouping of transition matrix. + auto const& rowGroupIndices = fullTransitionMatrix.getRowGroupIndices(); + + // (1) define/declare horizon, epsilon, kappa, N, lambda, maxNorm + uint64_t numberOfStates = fullTransitionMatrix.getRowGroupCount(); + double T = boundsPair.second; + // TODO: make kappa a parameter. + ValueType kappa = storm::utility::one() / 10; + ValueType epsilon = storm::settings::getModule().getPrecision(); + ValueType lambda = exitRateVector[0]; + for (ValueType const& rate : exitRateVector) { + lambda = std::max(rate, lambda); + } + STORM_LOG_TRACE("Initial lambda is " << lambda << "."); + uint64_t N; + ValueType maxNorm = storm::utility::zero(); + + // Compute the relative reachability vectors and create solver for models with SCCs. + std::vector> relativeReachabilities(transitionMatrix.getRowCount()); + std::unique_ptr> solver; + if (!cycleFree) { + for (uint64_t i = 0; i < numberOfStates; i++) { + if (markovianAndGoalStates[i]) { + continue; + } + + for (auto j = rowGroupIndices[i]; j < rowGroupIndices[i + 1]; ++j) { + for (auto const& element : fullTransitionMatrix.getRow(j)) { + if (markovianAndGoalStates[element.getColumn()]) { + relativeReachabilities[j].push_back(element.getValue()); + } + } + } + } + + // Create solver. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, 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->setBounds(storm::utility::zero(), storm::utility::one()); + solver->setRequirementsChecked(); + solver->setCachingEnabled(true); + } + } + + // Loop until result is within precision bound. + std::vector init(numberOfStates, -1); + do { + maxNorm = storm::utility::zero(); + + // (2) update parameter + N = storm::utility::ceil(lambda * T * std::exp(2) - storm::utility::log(kappa * epsilon)); + + // (3) uniform - just applied to Markovian states. + for (uint64_t i = 0; i < fullTransitionMatrix.getRowGroupCount(); i++) { + if (!markovianAndGoalStates[i] || psiStates[i]) { + continue; + } + + // As the current state is Markovian, its branching probabilities are stored within one row. + uint64_t markovianRowIndex = rowGroupIndices[i]; + + if (mutableExitRates[i] == lambda) { + // Already uniformized. + continue; + } + + auto markovianRow = fullTransitionMatrix.getRow(markovianRowIndex); + ValueType oldExitRate = mutableExitRates[i]; + ValueType newExitRate = lambda; + for (auto& v : markovianRow) { + if (v.getColumn() == i) { + ValueType newSelfLoop = newExitRate - oldExitRate + v.getValue() * oldExitRate; + ValueType newRate = newSelfLoop / newExitRate; + v.setValue(newRate); + } else { + ValueType oldProbability = v.getValue(); + ValueType newProbability = oldProbability * oldExitRate / newExitRate; + v.setValue(newProbability); + } + } + mutableExitRates[i] = newExitRate; + } + + // Compute poisson distribution. + storm::utility::numerical::FoxGlynnResult foxGlynnResult = storm::utility::numerical::foxGlynn(lambda * T, epsilon * kappa / 100); + + // Scale the weights so they sum to one. + for (auto& element : foxGlynnResult.weights) { + element /= foxGlynnResult.totalWeight; + } + + // (4) Define vectors/matrices. + std::vector> v = std::vector>(N + 1, init); + + unifVectors[0] = v; + unifVectors[1] = v; + unifVectors[2] = v; + + // Define 0=vd, 1=vu, 2=wu. + // (5) Compute vectors and maxNorm. + for (uint64_t i = 0; i < numberOfStates; ++i) { + for (uint64_t k = N; k <= N; --k) { + calculateUnifPlusVector(env, k, i, 0, lambda, numberOfProbabilisticChoices, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); + calculateUnifPlusVector(env, k, i, 2, lambda, numberOfProbabilisticChoices, relativeReachabilities, dir, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); + calculateVu(env, relativeReachabilities, dir, k, i, 1, lambda, numberOfProbabilisticChoices, unifVectors, fullTransitionMatrix, markovianAndGoalStates, psiStates, solver, foxGlynnResult, cycleFree); + } + } + + // Only iterate over result vector, as the results can only get more precise. + for (uint64_t i = 0; i < numberOfStates; i++){ + ValueType diff = storm::utility::abs(unifVectors[0][0][i] - unifVectors[1][0][i]); + maxNorm = std::max(maxNorm, diff); + } + + // (6) Double lambda. + lambda *= 2; + STORM_LOG_TRACE("Increased lambda to " << lambda << ", max diff is " << maxNorm << "."); + + } while (maxNorm > epsilon * (1 - kappa)); + + return unifVectors[0][0]; + } + + template + void computeBoundedReachabilityProbabilitiesImca(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps) { // Start by computing four sparse matrices: // * a matrix aMarkovian with all (discretized) transitions from Markovian non-goal states to all Markovian non-goal states. @@ -101,13 +443,14 @@ namespace storm { } } } - + // Check for requirements of the solver. // The solution is unique as we assume non-zeno MAs. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir, true); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); - + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); + std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, aProbabilistic); solver->setHasUniqueSolution(); solver->setBounds(storm::utility::zero(), storm::utility::one()); @@ -126,10 +469,10 @@ namespace storm { // Start by (re-)computing bProbabilistic = bProbabilisticFixed + aProbabilisticToMarkovian * vMarkovian. aProbabilisticToMarkovian.multiplyWithVector(markovianNonGoalValues, bProbabilistic); storm::utility::vector::addVectors(bProbabilistic, bProbabilisticFixed, bProbabilistic); - + // Now perform the inner value iteration for probabilistic states. solver->solveEquations(env, dir, probabilisticNonGoalValues, bProbabilistic); - + // (Re-)compute bMarkovian = bMarkovianFixed + aMarkovianToProbabilistic * vProbabilistic. aMarkovianToProbabilistic.multiplyWithVector(probabilisticNonGoalValues, bMarkovian); storm::utility::vector::addVectors(bMarkovian, bMarkovianFixed, bMarkovian); @@ -151,21 +494,17 @@ namespace storm { solver->solveEquations(env, dir, probabilisticNonGoalValues, bProbabilistic); } } - - template ::SupportsExponential, int>::type> - void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { - STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded reachability probabilities is unsupported for this value type."); - } + + template + std::vector computeBoundedUntilProbabilitiesImca(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair) { + STORM_LOG_TRACE("Using IMCA's technique to compute bounded until probabilities."); - template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { - uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); - + // 'Unpack' the bounds to make them more easily accessible. double lowerBound = boundsPair.first; double upperBound = boundsPair.second; - + // (1) Compute the accuracy we need to achieve the required error bound. ValueType maxExitRate = 0; for (auto value : exitRateVector) { @@ -185,7 +524,7 @@ namespace storm { std::vector vProbabilistic(probabilisticNonGoalStates.getNumberOfSetBits()); std::vector vMarkovian(markovianNonGoalStates.getNumberOfSetBits()); - computeBoundedReachabilityProbabilities(env, dir, transitionMatrix, exitRateVector, psiStates, markovianNonGoalStates, probabilisticNonGoalStates, vMarkovian, vProbabilistic, delta, numberOfSteps, minMaxLinearEquationSolverFactory); + computeBoundedReachabilityProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, psiStates, markovianNonGoalStates, probabilisticNonGoalStates, vMarkovian, vProbabilistic, delta, numberOfSteps); // (4) If the lower bound of interval was non-zero, we need to take the current values as the starting values for a subsequent value iteration. if (lowerBound != storm::utility::zero()) { @@ -203,7 +542,7 @@ namespace storm { STORM_LOG_INFO("Performing " << numberOfSteps << " iterations (delta=" << delta << ") for interval [0, " << lowerBound << "]." << std::endl); // Compute the bounded reachability for interval [0, b-a]. - computeBoundedReachabilityProbabilities(env, dir, transitionMatrix, exitRateVector, storm::storage::BitVector(numberOfStates), markovianStates, ~markovianStates, vAllMarkovian, vAllProbabilistic, delta, numberOfSteps, minMaxLinearEquationSolverFactory); + computeBoundedReachabilityProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, storm::storage::BitVector(numberOfStates), markovianStates, ~markovianStates, vAllMarkovian, vAllProbabilistic, delta, numberOfSteps); // Create the result vector out of vAllProbabilistic and vAllMarkovian and return it. std::vector result(numberOfStates, storm::utility::zero()); @@ -220,20 +559,46 @@ namespace storm { return result; } } + + template ::SupportsExponential, int>::type> + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair) { + + auto const& settings = storm::settings::getModule(); + if (settings.getMarkovAutomatonBoundedReachabilityMethod() == storm::settings::modules::MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::Imca) { + return computeBoundedUntilProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair); + } else { + STORM_LOG_ASSERT(settings.getMarkovAutomatonBoundedReachabilityMethod() == storm::settings::modules::MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::UnifPlus, "Unknown solution method."); + + return computeBoundedUntilProbabilitiesUnifPlus(env, dir, boundsPair, exitRateVector, transitionMatrix, markovianStates, psiStates); + } + } template ::SupportsExponential, int>::type> - std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair) { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type."); } - template - std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { - return std::move(storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, dir, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, false, minMaxLinearEquationSolverFactory).values); + std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative) { + return std::move(storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, dir, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, false).values); + } + + template + std::vector SparseMarkovAutomatonCslHelper::computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel) { + + // Get a reward model where the state rewards are scaled accordingly + std::vector stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero()); + for (auto const markovianState : markovianStates) { + stateRewardWeights[markovianState] = storm::utility::one() / exitRateVector[markovianState]; + } + std::vector totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights); + RewardModelType scaledRewardModel(boost::none, std::move(totalRewardVector)); + + return SparseMdpPrctlHelper::computeTotalRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, false, false).values; } template - std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates) { // Get a reward model where the state rewards are scaled accordingly std::vector stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero()); @@ -243,11 +608,11 @@ namespace storm { std::vector totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights); RewardModelType scaledRewardModel(boost::none, std::move(totalRewardVector)); - return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values; + return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false, false).values; } template - std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -267,12 +632,12 @@ namespace storm { storm::utility::vector::setVectorValues(stateRewards, markovianStates & psiStates, storm::utility::one()); storm::models::sparse::StandardRewardModel rewardModel(std::move(stateRewards)); - return computeLongRunAverageRewards(env, dir, transitionMatrix, backwardTransitions, exitRateVector, markovianStates, rewardModel, minMaxLinearEquationSolverFactory); + return computeLongRunAverageRewards(env, dir, transitionMatrix, backwardTransitions, exitRateVector, markovianStates, rewardModel); } template - std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -301,7 +666,7 @@ namespace storm { } // Compute the LRA value for the current MEC. - lraValuesForEndComponents.push_back(computeLraForMaximalEndComponent(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec, minMaxLinearEquationSolverFactory)); + lraValuesForEndComponents.push_back(computeLraForMaximalEndComponent(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec)); } // For fast transition rewriting, we build some auxiliary data structures. @@ -403,9 +768,10 @@ namespace storm { std::vector x(numberOfSspStates); // Check for requirements of the solver. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir, true); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, sspMatrix); solver->setHasUniqueSolution(); @@ -429,7 +795,7 @@ namespace storm { } template - std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates) { // Get a reward model representing expected sojourn times std::vector rewardValues(transitionMatrix.getRowCount(), storm::utility::zero()); @@ -438,11 +804,11 @@ namespace storm { } storm::models::sparse::StandardRewardModel rewardModel(boost::none, std::move(rewardValues)); - return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false, false, minMaxLinearEquationSolverFactory).values; + return SparseMdpPrctlHelper::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false, false).values; } template - ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // If the mec only consists of a single state, we compute the LRA value directly if (++mec.begin() == mec.end()) { @@ -462,7 +828,7 @@ namespace storm { if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMaximalEndComponentLP(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec); } else if (method == storm::solver::LraMethod::ValueIteration) { - return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec, minMaxLinearEquationSolverFactory); + return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } @@ -534,7 +900,7 @@ namespace storm { } template - ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // Initialize data about the mec @@ -616,9 +982,10 @@ namespace storm { // Check for requirements of the solver. // The solution is unique as we assume non-zeno MAs. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir, true); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); requirements.clearLowerBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); auto solver = minMaxLinearEquationSolverFactory.create(env, std::move(aProbabilistic)); solver->setLowerBound(storm::utility::zero()); @@ -661,45 +1028,45 @@ namespace storm { } - template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); - template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates); + + template std::vector SparseMarkovAutomatonCslHelper::computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - - template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, double delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - - template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); + + template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template double SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); - template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); + + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel); - template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - - template void SparseMarkovAutomatonCslHelper::computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, storm::RationalNumber delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMarkovAutomatonCslHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); - template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template storm::RationalNumber SparseMarkovAutomatonCslHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); } } diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h index 655f6ebf2..6b6a94a50 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.h @@ -1,6 +1,6 @@ -#ifndef STORM_MODELCHECKER_SPARSE_MARKOVAUTOMATON_CSL_MODELCHECKER_HELPER_H_ -#define STORM_MODELCHECKER_SPARSE_MARKOVAUTOMATON_CSL_MODELCHECKER_HELPER_H_ +#pragma once +#include #include "storm/storage/BitVector.h" #include "storm/storage/MaximalEndComponent.h" #include "storm/solver/OptimizationDirection.h" @@ -16,36 +16,32 @@ namespace storm { class SparseMarkovAutomatonCslHelper { public: - + template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - + static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); + template ::SupportsExponential, int>::type = 0> - static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, std::pair const& boundsPair); template - static std::vector computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative); template - static std::vector computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - + static std::vector computeTotalRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel); + template + static std::vector computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates); + template - static std::vector computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); template - static std::vector computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel); template - static std::vector computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates); private: - template ::SupportsExponential, int>::type = 0> - static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - - template ::SupportsExponential, int>::type = 0> - static void computeBoundedReachabilityProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRates, storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates, storm::storage::BitVector const& probabilisticNonGoalStates, std::vector& markovianNonGoalValues, std::vector& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - /*! * Computes the long-run average value for the given maximal end component of a Markov automaton. * @@ -59,20 +55,17 @@ namespace storm { * @param rewardModel The considered reward model * @param actionRewards The action rewards (earned instantaneously). * @param mec The maximal end component to consider for computing the long-run average. - * @param minMaxLinearEquationSolverFactory The factory for creating MinMaxLinearEquationSolvers (if needed by the performed method * @return The long-run average of being in a goal state for the given MEC. */ template - static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template static ValueType computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template - static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& exitRateVector, storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); }; } } } - -#endif /* STORM_MODELCHECKER_SPARSE_MARKOVAUTOMATON_CSL_MODELCHECKER_HELPER_H_ */ diff --git a/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp b/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp index c5dc5e036..f59dafb4c 100644 --- a/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp +++ b/src/storm/modelchecker/exploration/SparseExplorationModelChecker.cpp @@ -37,7 +37,7 @@ namespace storm { namespace modelchecker { template - SparseExplorationModelChecker::SparseExplorationModelChecker(storm::prism::Program const& program) : program(program.substituteConstants()), randomGenerator(std::chrono::system_clock::now().time_since_epoch().count()), comparator(storm::settings::getModule().getPrecision()) { + SparseExplorationModelChecker::SparseExplorationModelChecker(storm::prism::Program const& program) : program(program.substituteConstantsFormulas()), randomGenerator(std::chrono::system_clock::now().time_since_epoch().count()), comparator(storm::settings::getModule().getPrecision()) { // Intentionally left empty. } @@ -341,7 +341,7 @@ namespace storm { }); } else if (explorationInformation.useProbabilityHeuristic()) { std::transform(row.begin(), row.end(), probabilities.begin(), - [&bounds, &explorationInformation] (storm::storage::MatrixEntry const& entry) { + [] (storm::storage::MatrixEntry const& entry) { return entry.getValue(); }); } diff --git a/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp b/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp index 710fd92d3..5a65bd502 100644 --- a/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp +++ b/src/storm/modelchecker/multiobjective/constraintbased/SparseCbAchievabilityQuery.cpp @@ -9,6 +9,7 @@ #include "storm/utility/vector.h" #include "storm/utility/solver.h" #include "storm/utility/Stopwatch.h" +#include "storm/utility/ExpressionHelper.h" #include "storm/settings/SettingsManager.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" @@ -99,11 +100,13 @@ namespace storm { for (auto& var : expectedChoiceVariables) { solver->add(var.getExpression() >= zero); } - storm::expressions::Expression bottomStateSum = zero; + std::vector bottomStateVarsAsExpression; + bottomStateVarsAsExpression.reserve(bottomStateVariables.size()); for (auto& var : bottomStateVariables) { solver->add(var.getExpression() >= zero); - bottomStateSum = bottomStateSum + var.getExpression(); + bottomStateVarsAsExpression.push_back(var.getExpression()); } + auto bottomStateSum = storm::utility::ExpressionHelper(this->expressionManager).sum(std::move(bottomStateVarsAsExpression)); solver->add(bottomStateSum == one); // assert that the "incoming" value of each state equals the "outgoing" value @@ -138,25 +141,15 @@ namespace storm { STORM_LOG_THROW(obj.formula->hasBound(), storm::exceptions::InvalidOperationException, "Invoked achievability query but no bound was specified for at least one objective."); STORM_LOG_THROW(obj.formula->asRewardOperatorFormula().hasRewardModelName(), storm::exceptions::InvalidOperationException, "Expected reward operator with a reward model name. Got " << *obj.formula << " instead."); std::vector rewards = getActionBasedExpectedRewards(obj.formula->asRewardOperatorFormula().getRewardModelName()); + + // Get the sum of all objective values std::vector objectiveValues; for (uint_fast64_t choice = 0; choice < rewards.size(); ++choice) { if (!storm::utility::isZero(rewards[choice])) { objectiveValues.push_back(this->expressionManager->rational(rewards[choice]) * expectedChoiceVariables[choice].getExpression()); } } - - // Get the sum of all objective values - // As the sum can potentially have many summands, we want to make sure that the formula tree is (roughly balanced) - auto vIt = objectiveValues.begin(); - while (objectiveValues.size() > 1) { - if (vIt == objectiveValues.end() || vIt == objectiveValues.end() - 1) { - vIt = objectiveValues.begin(); - } - *vIt = *vIt + objectiveValues.back(); - objectiveValues.pop_back(); - ++vIt; - } - storm::expressions::Expression objValue = objectiveValues.empty() ? zero : objectiveValues.front(); + auto objValue = storm::utility::ExpressionHelper(this->expressionManager).sum(std::move(objectiveValues)); // We need to actually evaluate the threshold as rational number. Otherwise a threshold like '<=16/9' might be considered as 1 due to integer division storm::expressions::Expression threshold = this->expressionManager->rational(obj.formula->getThreshold().evaluateAsRational()); diff --git a/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp b/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp index 10276ffa6..bb18e9385 100644 --- a/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp +++ b/src/storm/modelchecker/multiobjective/multiObjectiveModelChecking.cpp @@ -1,7 +1,7 @@ #include "storm/modelchecker/multiobjective/multiObjectiveModelChecking.h" #include "storm/utility/macros.h" - +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" #include "storm/models/sparse/Mdp.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" @@ -74,8 +74,8 @@ namespace storm { result = query->check(env); - if(storm::settings::getModule().isExportPlotSet()) { - query->exportPlotOfCurrentApproximation(storm::settings::getModule().getExportPlotDirectory()); + if (env.modelchecker().multi().isExportPlotSet()) { + query->exportPlotOfCurrentApproximation(env); } break; } diff --git a/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp index cc748983d..f5137b0a7 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/RewardBoundedMdpPcaaWeightVectorChecker.cpp @@ -295,7 +295,7 @@ namespace storm { cachedData.linEqSolver->setUpperBound(*obj.upperResultBound); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); cachedData.linEqSolver->solveEquations(env, x, cachedData.bLinEq); auto resultIt = result.begin(); for (auto const& state : epochModel.epochInStates) { @@ -331,7 +331,7 @@ namespace storm { cachedData.minMaxSolver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); cachedData.minMaxSolver->setRequirementsChecked(true); cachedData.minMaxSolver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp index 409bd9ba9..b8ac5fe2d 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaAchievabilityQuery.cpp @@ -7,9 +7,8 @@ #include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/GeneralSettings.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" + #include "storm/exceptions/InvalidOperationException.h" @@ -57,7 +56,7 @@ namespace storm { template bool SparsePcaaAchievabilityQuery::checkAchievability(Environment const& env) { // repeatedly refine the over/ under approximation until the threshold point is either in the under approx. or not in the over approx. - while(!this->maxStepsPerformed()){ + while(!this->maxStepsPerformed(env)){ WeightVector separatingVector = this->findSeparatingVector(thresholds); this->updateWeightedPrecision(separatingVector); this->performRefinementStep(env, std::move(separatingVector)); diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp index fe7a7b367..93c04e527 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaParetoQuery.cpp @@ -7,10 +7,7 @@ #include "storm/modelchecker/results/ExplicitParetoCurveCheckResult.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" -#include "storm/settings/modules/GeneralSettings.h" - +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" namespace storm { namespace modelchecker { @@ -19,20 +16,19 @@ namespace storm { template SparsePcaaParetoQuery::SparsePcaaParetoQuery(SparseMultiObjectivePreprocessorResult& preprocessorResult) : SparsePcaaQuery(preprocessorResult) { STORM_LOG_ASSERT(preprocessorResult.queryType==SparseMultiObjectivePreprocessorResult::QueryType::Pareto, "Invalid query Type"); + } + + template + std::unique_ptr SparsePcaaParetoQuery::check(Environment const& env) { // Set the precision of the weight vector checker - typename SparseModelType::ValueType weightedPrecision = storm::utility::convertNumber(storm::settings::getModule().getPrecision()); + typename SparseModelType::ValueType weightedPrecision = storm::utility::convertNumber(env.modelchecker().multi().getPrecision()); weightedPrecision /= storm::utility::sqrt(storm::utility::convertNumber(this->objectives.size())); // multiobjPrecision / sqrt(numObjectives) is the largest possible value for which termination is guaranteed. // Lets be a little bit more precise to reduce the number of required iterations. weightedPrecision *= storm::utility::convertNumber(0.9); this->weightVectorChecker->setWeightedPrecision(weightedPrecision); - - } - - template - std::unique_ptr SparsePcaaParetoQuery::check(Environment const& env) { - + // refine the approximation exploreSetOfAchievablePoints(env); @@ -55,13 +51,13 @@ namespace storm { void SparsePcaaParetoQuery::exploreSetOfAchievablePoints(Environment const& env) { //First consider the objectives individually - for(uint_fast64_t objIndex = 0; objIndexobjectives.size() && !this->maxStepsPerformed(); ++objIndex) { + for(uint_fast64_t objIndex = 0; objIndexobjectives.size() && !this->maxStepsPerformed(env); ++objIndex) { WeightVector direction(this->objectives.size(), storm::utility::zero()); direction[objIndex] = storm::utility::one(); this->performRefinementStep(env, std::move(direction)); } - while(!this->maxStepsPerformed()) { + while(!this->maxStepsPerformed(env)) { // Get the halfspace of the underApproximation with maximal distance to a vertex of the overApproximation std::vector> underApproxHalfspaces = this->underApproximation->getHalfspaces(); std::vector overApproxVertices = this->overApproximation->getVertices(); @@ -76,7 +72,7 @@ namespace storm { } } } - if(farestDistance < storm::utility::convertNumber(storm::settings::getModule().getPrecision())) { + if(farestDistance < storm::utility::convertNumber(env.modelchecker().multi().getPrecision())) { // Goal precision reached! return; } diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp index 538752ab2..4df353cdd 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.cpp @@ -8,9 +8,7 @@ #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" -#include "storm/settings/modules/GeneralSettings.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" #include "storm/exceptions/InvalidOperationException.h" @@ -99,7 +97,7 @@ namespace storm { // We don't care for the optimizing objective at this point this->diracWeightVectorsToBeChecked.set(indexOfOptimizingObjective, false); - while(!this->maxStepsPerformed()){ + while(!this->maxStepsPerformed(env)){ WeightVector separatingVector = this->findSeparatingVector(thresholds); this->updateWeightedPrecisionInAchievabilityPhase(separatingVector); this->performRefinementStep(env, std::move(separatingVector)); @@ -150,10 +148,10 @@ namespace storm { // the supremum over all strategies. Hence, one could combine a scheduler inducing the optimum value (but possibly violating strict // thresholds) and (with very low probability) a scheduler that satisfies all (possibly strict) thresholds. GeometryValueType result = storm::utility::zero(); - while(!this->maxStepsPerformed()) { + while(!this->maxStepsPerformed(env)) { if (this->refinementSteps.empty()) { // We did not make any refinement steps during the checkAchievability phase (e.g., because there is only one objective). - this->weightVectorChecker->setWeightedPrecision(storm::utility::convertNumber(storm::settings::getModule().getPrecision())); + this->weightVectorChecker->setWeightedPrecision(storm::utility::convertNumber(env.modelchecker().multi().getPrecision())); WeightVector separatingVector = directionOfOptimizingObjective; this->performRefinementStep(env, std::move(separatingVector)); } @@ -165,7 +163,7 @@ namespace storm { optimizationRes = this->overApproximation->intersection(thresholdsAsPolytope)->optimize(directionOfOptimizingObjective); if (optimizationRes.second) { GeometryValueType precisionOfResult = optimizationRes.first[indexOfOptimizingObjective] - result; - if (precisionOfResult < storm::utility::convertNumber(storm::settings::getModule().getPrecision())) { + if (precisionOfResult < storm::utility::convertNumber(env.modelchecker().multi().getPrecision())) { // Goal precision reached! return result; } else { @@ -176,7 +174,7 @@ namespace storm { thresholds[indexOfOptimizingObjective] = result + storm::utility::one(); } WeightVector separatingVector = this->findSeparatingVector(thresholds); - this->updateWeightedPrecisionInImprovingPhase(separatingVector); + this->updateWeightedPrecisionInImprovingPhase(env, separatingVector); this->performRefinementStep(env, std::move(separatingVector)); } STORM_LOG_ERROR("Could not reach the desired precision: Exceeded maximum number of refinement steps"); @@ -185,11 +183,11 @@ namespace storm { template - void SparsePcaaQuantitativeQuery::updateWeightedPrecisionInImprovingPhase(WeightVector const& weights) { + void SparsePcaaQuantitativeQuery::updateWeightedPrecisionInImprovingPhase(Environment const& env, WeightVector const& weights) { STORM_LOG_THROW(!storm::utility::isZero(weights[this->indexOfOptimizingObjective]), exceptions::UnexpectedException, "The chosen weight-vector gives zero weight for the objective that is to be optimized."); // If weighs[indexOfOptimizingObjective] is low, the computation of the weightVectorChecker needs to be more precise. // Our heuristic ensures that if p is the new vertex of the under-approximation, then max{ eps | p' = p + (0..0 eps 0..0) is in the over-approximation } <= multiobjective_precision/0.9 - GeometryValueType weightedPrecision = weights[this->indexOfOptimizingObjective] * storm::utility::convertNumber(storm::settings::getModule().getPrecision()); + GeometryValueType weightedPrecision = weights[this->indexOfOptimizingObjective] * storm::utility::convertNumber(env.modelchecker().multi().getPrecision()); // Normalize by division with the Euclidean Norm of the weight-vector weightedPrecision /= storm::utility::sqrt(storm::utility::vector::dotProduct(weights, weights)); weightedPrecision *= storm::utility::convertNumber(0.9); diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h index 164a87f21..234e6f291 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuantitativeQuery.h @@ -45,7 +45,7 @@ namespace storm { * Updates the precision of the weightVectorChecker w.r.t. the provided weights */ void updateWeightedPrecisionInAchievabilityPhase(WeightVector const& weights); - void updateWeightedPrecisionInImprovingPhase(WeightVector const& weights); + void updateWeightedPrecisionInImprovingPhase(Environment const& env, WeightVector const& weights); /* * Given that the thresholds are achievable, this function further refines the approximations and returns the optimized value diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp index 2164665e0..ef7e50d80 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.cpp @@ -5,8 +5,7 @@ #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/modelchecker/multiobjective/Objective.h" -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/environment/modelchecker/MultiObjectiveModelCheckerEnvironment.h" #include "storm/storage/geometry/Hyperrectangle.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" @@ -126,9 +125,9 @@ namespace storm { } template - bool SparsePcaaQuery::maxStepsPerformed() const { - return storm::settings::getModule().isMaxStepsSet() && - this->refinementSteps.size() >= storm::settings::getModule().getMaxSteps(); + bool SparsePcaaQuery::maxStepsPerformed(Environment const& env) const { + return env.modelchecker().multi().isMaxStepsSet() && + this->refinementSteps.size() >= env.modelchecker().multi().getMaxSteps(); } @@ -191,7 +190,7 @@ namespace storm { } template - void SparsePcaaQuery::exportPlotOfCurrentApproximation(std::string const& destinationDir) const { + void SparsePcaaQuery::exportPlotOfCurrentApproximation(Environment const& env) const { STORM_LOG_ERROR_COND(objectives.size()==2, "Exporting plot requested but this is only implemented for the two-dimensional case."); @@ -223,35 +222,33 @@ namespace storm { std::vector columnHeaders = {"x", "y"}; std::vector> pointsForPlotting; - underApproxVertices = transformedUnderApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); - pointsForPlotting.reserve(underApproxVertices.size()); - for(auto const& v : underApproxVertices) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); - } - storm::utility::exportDataToCSVFile(destinationDir + "underapproximation.csv", pointsForPlotting, columnHeaders); - - pointsForPlotting.clear(); - overApproxVertices = transformedOverApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); - pointsForPlotting.reserve(overApproxVertices.size()); - for(auto const& v : overApproxVertices) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + if (env.modelchecker().multi().getPlotPathUnderApproximation()) { + underApproxVertices = transformedUnderApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); + pointsForPlotting.reserve(underApproxVertices.size()); + for(auto const& v : underApproxVertices) { + pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + } + storm::utility::exportDataToCSVFile(env.modelchecker().multi().getPlotPathUnderApproximation().get(), pointsForPlotting, columnHeaders); } - storm::utility::exportDataToCSVFile(destinationDir + "overapproximation.csv", pointsForPlotting, columnHeaders); - pointsForPlotting.clear(); - pointsForPlotting.reserve(paretoPoints.size()); - for(auto const& v : paretoPoints) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + if (env.modelchecker().multi().getPlotPathOverApproximation()) { + pointsForPlotting.clear(); + overApproxVertices = transformedOverApprox->intersection(boundariesAsPolytope)->getVerticesInClockwiseOrder(); + pointsForPlotting.reserve(overApproxVertices.size()); + for(auto const& v : overApproxVertices) { + pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + } + storm::utility::exportDataToCSVFile(env.modelchecker().multi().getPlotPathOverApproximation().get(), pointsForPlotting, columnHeaders); } - storm::utility::exportDataToCSVFile(destinationDir + "paretopoints.csv", pointsForPlotting, columnHeaders); - pointsForPlotting.clear(); - auto boundVertices = boundariesAsPolytope->getVerticesInClockwiseOrder(); - pointsForPlotting.reserve(4); - for(auto const& v : boundVertices) { - pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + if (env.modelchecker().multi().getPlotPathParetoPoints()) { + pointsForPlotting.clear(); + pointsForPlotting.reserve(paretoPoints.size()); + for(auto const& v : paretoPoints) { + pointsForPlotting.push_back(storm::utility::vector::convertNumericVector(v)); + } + storm::utility::exportDataToCSVFile(env.modelchecker().multi().getPlotPathParetoPoints().get(), pointsForPlotting, columnHeaders); } - storm::utility::exportDataToCSVFile(destinationDir + "boundaries.csv", pointsForPlotting, columnHeaders); } #ifdef STORM_HAVE_CARL diff --git a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h index d92f0ccee..630503a08 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h +++ b/src/storm/modelchecker/multiobjective/pcaa/SparsePcaaQuery.h @@ -38,7 +38,7 @@ namespace storm { * Note that the approximations will be intersected with a (sufficiently large) hyperrectangle in order to ensure that the polytopes are bounded * This only works for 2 dimensional queries. */ - void exportPlotOfCurrentApproximation(std::string const& destinationDir) const; + void exportPlotOfCurrentApproximation(Environment const& env) const; protected: @@ -87,7 +87,7 @@ namespace storm { /* * Returns true iff the maximum number of refinement steps (as possibly specified in the settings) has been reached */ - bool maxStepsPerformed() const; + bool maxStepsPerformed(Environment const& env) const; /* * Transforms the given point (or polytope) to values w.r.t. the original model/formula (e.g. negates values for minimizing objectives). diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp index 8505ab035..d43db0d5c 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardMaPcaaWeightVectorChecker.cpp @@ -303,7 +303,7 @@ namespace storm { result->solver->setHasUniqueSolution(true); result->solver->setTrackScheduler(true); result->solver->setCachingEnabled(true); - auto req = result->solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, true); + auto req = result->solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, false); boost::optional lowerBound = this->computeWeightedResultBound(true, weightVector, storm::storage::BitVector(weightVector.size(), true)); if (lowerBound) { result->solver->setLowerBound(lowerBound.get()); @@ -314,7 +314,7 @@ namespace storm { result->solver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the MinMaxSolver was not met."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); result->solver->setRequirementsChecked(true); result->solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp index bd93a44ef..3dd8e8988 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.cpp @@ -179,22 +179,21 @@ namespace storm { solver->setTrackScheduler(true); solver->setHasUniqueSolution(true); solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize); - auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize, true); - setBoundsToSolver(*solver, req.requiresLowerBounds(), req.requiresUpperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix, ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues); + auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize); + setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix, ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues); if (solver->hasLowerBound()) { req.clearLowerBounds(); } if (solver->hasUpperBound()) { req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solver->setRequirementsChecked(true); // Use the (0...0) vector as initial guess for the solution. std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero()); solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues); - this->weightedResult = std::vector(transitionMatrix.getRowGroupCount()); transformReducedSolutionToOriginalModel(ecQuotient->matrix, ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecQuotient->ecqToOriginalChoiceMapping, ecQuotient->originalToEcqStateMapping, this->weightedResult, this->optimalChoices); @@ -267,17 +266,15 @@ namespace storm { solver->clearBounds(); storm::storage::BitVector submatrixRowsWithSumLessOne = deterministicMatrix.getRowFilter(maybeStates, maybeStates) % maybeStates; submatrixRowsWithSumLessOne.complement(); - this->setBoundsToSolver(*solver, req.requiresLowerBounds(), req.requiresUpperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b); + this->setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b); if (solver->hasLowerBound()) { req.clearLowerBounds(); } if (solver->hasUpperBound()) { req.clearUpperBounds(); } - - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the LinearEquationSolver was not met."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); solver->solveEquations(env, x, b); - // Set the result for this objective accordingly storm::utility::vector::setVectorValues(objectiveResults[objIndex], maybeStates, x); } diff --git a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h index 2f0a27f33..b28a80ac6 100644 --- a/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h +++ b/src/storm/modelchecker/multiobjective/pcaa/StandardPcaaWeightVectorChecker.h @@ -37,8 +37,6 @@ namespace storm { StandardPcaaWeightVectorChecker(SparseMultiObjectivePreprocessorResult const& preprocessorResult); - virtual ~StandardPcaaWeightVectorChecker() = default; - /*! * - computes the optimal expected reward w.r.t. the weighted sum of the rewards of the individual objectives * - extracts the scheduler that induces this optimum diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp index 208dfcfd4..0654a9788 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.cpp @@ -26,19 +26,14 @@ namespace storm { namespace modelchecker { template - HybridDtmcPrctlModelChecker::HybridDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - HybridDtmcPrctlModelChecker::HybridDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + HybridDtmcPrctlModelChecker::HybridDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } template bool HybridDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -48,7 +43,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -56,7 +51,7 @@ namespace storm { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -76,21 +71,21 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); } template std::unique_ptr HybridDtmcPrctlModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template std::unique_ptr HybridDtmcPrctlModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -98,7 +93,16 @@ namespace storm { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } + + template + std::unique_ptr HybridDtmcPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeReachabilityTimes(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } @@ -108,12 +112,12 @@ namespace storm { std::unique_ptr subResultPointer = this->check(env, stateFormula); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); } template std::unique_ptr HybridDtmcPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridDtmcPrctlHelper::computeLongRunAverageRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel("")); } template class HybridDtmcPrctlModelChecker>; diff --git a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h index 2b69dda58..854fae195 100644 --- a/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridDtmcPrctlModelChecker.h @@ -18,7 +18,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridDtmcPrctlModelChecker(ModelType const& model); - explicit HybridDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -32,10 +31,8 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp index 12524aed6..9af47c767 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.cpp @@ -32,19 +32,14 @@ namespace storm { namespace modelchecker { template - HybridMdpPrctlModelChecker::HybridMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - HybridMdpPrctlModelChecker::HybridMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + HybridMdpPrctlModelChecker::HybridMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } template bool HybridMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if(formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false))) { + if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula @@ -64,7 +59,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -73,7 +68,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -95,7 +90,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); } template @@ -103,7 +98,7 @@ namespace storm { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template @@ -111,7 +106,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -120,7 +115,16 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + } + + template + std::unique_ptr HybridMdpPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + return storm::modelchecker::helper::HybridMdpPrctlHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template diff --git a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h index cff28c1ca..68eb12baa 100644 --- a/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/HybridMdpPrctlModelChecker.h @@ -25,7 +25,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit HybridMdpPrctlModelChecker(ModelType const& model); - explicit HybridMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -36,11 +35,9 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp index 36e6eb9a2..f561d3e98 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.cpp @@ -24,19 +24,14 @@ namespace storm { namespace modelchecker { template - SparseDtmcPrctlModelChecker::SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - SparseDtmcPrctlModelChecker::SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model) : SparsePropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + SparseDtmcPrctlModelChecker::SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } template bool SparseDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setConditionalRewardFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -49,7 +44,7 @@ namespace storm { opInfo.bound = checkTask.getBound(); } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), opInfo); - auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula, *linearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(!pathFormula.hasLowerBound() && pathFormula.hasUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have single upper time bound."); @@ -58,7 +53,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *linearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), checkTask.getHint()); std::unique_ptr result = std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); return result; } @@ -69,7 +64,7 @@ namespace storm { storm::logic::NextFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeNextProbabilities(env, this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -80,7 +75,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -89,7 +84,7 @@ namespace storm { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -103,11 +98,11 @@ namespace storm { opInfo.bound = checkTask.getBound(); } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), checkTask.getRewardModel(), opInfo); - auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula, *linearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeRewardBoundedValues(env, this->getModel(), formula); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } @@ -116,7 +111,7 @@ namespace storm { std::unique_ptr SparseDtmcPrctlModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -125,7 +120,22 @@ namespace storm { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } + + template + std::unique_ptr SparseDtmcPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.getHint()); + return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); + } + + template + std::unique_ptr SparseDtmcPrctlModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -134,15 +144,14 @@ namespace storm { storm::logic::StateFormula const& stateFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), nullptr, *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), nullptr); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseDtmcPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { - std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), nullptr, *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseCtmcCslHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), nullptr); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); - } template @@ -156,7 +165,7 @@ namespace storm { ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -171,7 +180,7 @@ namespace storm { ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *linearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeConditionalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } diff --git a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h index c4284218a..1aafc0efb 100644 --- a/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h @@ -17,7 +17,6 @@ namespace storm { typedef typename SparseDtmcModelType::RewardModelType RewardModelType; explicit SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model); - explicit SparseDtmcPrctlModelChecker(SparseDtmcModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -31,12 +30,10 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeConditionalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp index bb51f372d..b78ad3856 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.cpp @@ -31,19 +31,14 @@ namespace storm { namespace modelchecker { template - SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(SparseMdpModelType const& model) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(SparseMdpModelType const& model, std::unique_ptr>&& minMaxLinearEquationSolverFactory) : SparsePropositionalModelChecker(model), minMaxLinearEquationSolverFactory(std::move(minMaxLinearEquationSolverFactory)) { + SparseMdpPrctlModelChecker::SparseMdpPrctlModelChecker(SparseMdpModelType const& model) : SparsePropositionalModelChecker(model) { // Intentionally left empty. } template bool SparseMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true))) { + if (formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(true).setLongRunAverageProbabilitiesAllowed(true).setConditionalProbabilityFormulasAllowed(true).setOnlyEventuallyFormuluasInConditionalFormulasAllowed(true).setTotalRewardFormulasAllowed(true).setRewardBoundedUntilFormulasAllowed(true).setRewardBoundedCumulativeRewardFormulasAllowed(true).setMultiDimensionalBoundedUntilFormulasAllowed(true).setMultiDimensionalCumulativeRewardFormulasAllowed(true).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true))) { return true; } else { // Check whether we consider a multi-objective formula @@ -67,7 +62,7 @@ namespace storm { } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), opInfo); helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); - auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates(), *minMaxLinearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(!pathFormula.hasLowerBound() && pathFormula.hasUpperBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have single upper time bound."); @@ -76,7 +71,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *minMaxLinearEquationSolverFactory, checkTask.getHint()); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), checkTask.getHint()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } @@ -87,7 +82,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeNextProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeNextProbabilities(env, checkTask.getOptimizationDirection(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -99,7 +94,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), *minMaxLinearEquationSolverFactory, checkTask.getHint()); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeUntilProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); @@ -113,7 +108,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *minMaxLinearEquationSolverFactory); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeGloballyProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(ret))); } @@ -130,7 +125,7 @@ namespace storm { ExplicitQualitativeCheckResult const& leftResult = leftResultPointer->asExplicitQualitativeCheckResult(); ExplicitQualitativeCheckResult const& rightResult = rightResultPointer->asExplicitQualitativeCheckResult(); - return storm::modelchecker::helper::SparseMdpPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + return storm::modelchecker::helper::SparseMdpPrctlHelper::computeConditionalProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector()); } template @@ -146,11 +141,11 @@ namespace storm { } auto formula = std::make_shared(checkTask.getFormula().asSharedPointer(), checkTask.getRewardModel(), opInfo); helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(this->getModel(), formula); - auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates(), *minMaxLinearEquationSolverFactory); + auto numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeRewardBoundedValues(env, checkTask.getOptimizationDirection(), rewardUnfolding, this->getModel().getInitialStates()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } else { STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeCumulativeRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } } @@ -160,7 +155,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeInstantaneousRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } @@ -170,7 +165,32 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), *minMaxLinearEquationSolverFactory, checkTask.getHint()); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + if (checkTask.isProduceSchedulersSet() && ret.scheduler) { + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + } + return result; + } + + template + std::unique_ptr SparseMdpPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeReachabilityTimes(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); + std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); + if (checkTask.isProduceSchedulersSet() && ret.scheduler) { + result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); + } + return result; + } + + template + std::unique_ptr SparseMdpPrctlModelChecker::computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + auto ret = storm::modelchecker::helper::SparseMdpPrctlHelper::computeTotalRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), checkTask.isQualitativeSet(), checkTask.isProduceSchedulersSet(), checkTask.getHint()); std::unique_ptr result(new ExplicitQuantitativeCheckResult(std::move(ret.values))); if (checkTask.isProduceSchedulersSet() && ret.scheduler) { result->asExplicitQuantitativeCheckResult().setScheduler(std::move(ret.scheduler)); @@ -184,14 +204,14 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, stateFormula); ExplicitQualitativeCheckResult const& subResult = subResultPointer->asExplicitQualitativeCheckResult(); - std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector(), *minMaxLinearEquationSolverFactory); + std::vector numericResult = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), subResult.getTruthValuesVector()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(numericResult))); } template std::unique_ptr SparseMdpPrctlModelChecker::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); - std::vector result = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel(), *minMaxLinearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseMdpPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(this->getModel(), checkTask), this->getModel().getTransitionMatrix(), this->getModel().getBackwardTransitions(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getUniqueRewardModel()); return std::unique_ptr(new ExplicitQuantitativeCheckResult(std::move(result))); } diff --git a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h index 84c6d7ddc..19c2cc6a1 100644 --- a/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h @@ -17,7 +17,6 @@ namespace storm { typedef typename SparseMdpModelType::RewardModelType RewardModelType; explicit SparseMdpPrctlModelChecker(SparseMdpModelType const& model); - explicit SparseMdpPrctlModelChecker(SparseMdpModelType const& model, std::unique_ptr>&& MinMaxLinearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -28,14 +27,13 @@ namespace storm { virtual std::unique_ptr computeConditionalProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeTotalRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, CheckTask const& checkTask) override; virtual std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr checkMultiObjectiveFormula(Environment const& env, CheckTask const& checkTask) override; - private: - // An object that is used for retrieving solvers for systems of linear equations that are the result of nondeterministic choices. - std::unique_ptr> minMaxLinearEquationSolverFactory; }; } // namespace modelchecker } // namespace storm diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp index ec61ae28d..a6a099833 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.cpp @@ -23,19 +23,14 @@ namespace storm { namespace modelchecker { template - SymbolicDtmcPrctlModelChecker::SymbolicDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - SymbolicDtmcPrctlModelChecker::SymbolicDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::make_unique>()) { + SymbolicDtmcPrctlModelChecker::SymbolicDtmcPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } template bool SymbolicDtmcPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -45,7 +40,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } @@ -54,7 +49,7 @@ namespace storm { storm::logic::GloballyFormula const& pathFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeGloballyProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } @@ -76,7 +71,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(env, this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); return std::unique_ptr>(new SymbolicQuantitativeCheckResult(this->getModel().getReachableStates(), numericResult)); } @@ -84,7 +79,7 @@ namespace storm { std::unique_ptr SymbolicDtmcPrctlModelChecker::computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeCumulativeRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); return std::unique_ptr>(new SymbolicQuantitativeCheckResult(this->getModel().getReachableStates(), numericResult)); } @@ -92,7 +87,7 @@ namespace storm { std::unique_ptr SymbolicDtmcPrctlModelChecker::computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeInstantaneousRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } @@ -101,7 +96,17 @@ namespace storm { storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityRewards(env, this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); + return std::make_unique>(this->getModel().getReachableStates(), numericResult); + } + + + template + std::unique_ptr SymbolicDtmcPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + storm::dd::Add numericResult = storm::modelchecker::helper::SymbolicDtmcPrctlHelper::computeReachabilityTimes(env, this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); return std::make_unique>(this->getModel().getReachableStates(), numericResult); } diff --git a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h index f0f09d965..1186c0271 100644 --- a/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicDtmcPrctlModelChecker.h @@ -16,7 +16,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit SymbolicDtmcPrctlModelChecker(ModelType const& model); - explicit SymbolicDtmcPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -27,10 +26,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp index e80ebaec8..713ce3295 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.cpp @@ -21,20 +21,16 @@ namespace storm { namespace modelchecker { - template - SymbolicMdpPrctlModelChecker::SymbolicMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } template - SymbolicMdpPrctlModelChecker::SymbolicMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model), linearEquationSolverFactory(new storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory()) { + SymbolicMdpPrctlModelChecker::SymbolicMdpPrctlModelChecker(ModelType const& model) : SymbolicPropositionalModelChecker(model) { // Intentionally left empty. } template bool SymbolicMdpPrctlModelChecker::canHandle(CheckTask const& checkTask) const { storm::logic::Formula const& formula = checkTask.getFormula(); - return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false)); + return formula.isInFragment(storm::logic::prctl().setLongRunAverageRewardFormulasAllowed(false).setTimeOperatorsAllowed(true).setReachbilityTimeFormulasAllowed(true)); } template @@ -45,7 +41,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -54,7 +50,7 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, pathFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeGloballyProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector(), checkTask.isQualitativeSet()); } template @@ -76,7 +72,7 @@ namespace storm { std::unique_ptr rightResultPointer = this->check(env, pathFormula.getRightSubformula()); SymbolicQualitativeCheckResult const& leftResult = leftResultPointer->asSymbolicQualitativeCheckResult(); SymbolicQualitativeCheckResult const& rightResult = rightResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), leftResult.getTruthValuesVector(), rightResult.getTruthValuesVector(), pathFormula.getNonStrictUpperBound()); } template @@ -84,7 +80,7 @@ namespace storm { storm::logic::CumulativeRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeCumulativeRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getNonStrictBound()); } template @@ -92,7 +88,7 @@ namespace storm { storm::logic::InstantaneousRewardFormula const& rewardPathFormula = checkTask.getFormula(); STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidArgumentException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); STORM_LOG_THROW(rewardPathFormula.hasIntegerBound(), storm::exceptions::InvalidPropertyException, "Formula needs to have a discrete time bound."); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeInstantaneousRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), rewardPathFormula.getBound()); } template @@ -101,7 +97,16 @@ namespace storm { STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); - return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector(), *this->linearEquationSolverFactory); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityRewards(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), checkTask.isRewardModelSet() ? this->getModel().getRewardModel(checkTask.getRewardModel()) : this->getModel().getRewardModel(""), subResult.getTruthValuesVector()); + } + + template + std::unique_ptr SymbolicMdpPrctlModelChecker::computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType, CheckTask const& checkTask) { + storm::logic::EventuallyFormula const& eventuallyFormula = checkTask.getFormula(); + STORM_LOG_THROW(checkTask.isOptimizationDirectionSet(), storm::exceptions::InvalidPropertyException, "Formula needs to specify whether minimal or maximal values are to be computed on nondeterministic model."); + std::unique_ptr subResultPointer = this->check(env, eventuallyFormula.getSubformula()); + SymbolicQualitativeCheckResult const& subResult = subResultPointer->asSymbolicQualitativeCheckResult(); + return storm::modelchecker::helper::SymbolicMdpPrctlHelper::computeReachabilityTimes(env, checkTask.getOptimizationDirection(), this->getModel(), this->getModel().getTransitionMatrix(), subResult.getTruthValuesVector()); } template class SymbolicMdpPrctlModelChecker>; diff --git a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h index a36358ba8..bf259e8b7 100644 --- a/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h +++ b/src/storm/modelchecker/prctl/SymbolicMdpPrctlModelChecker.h @@ -17,7 +17,6 @@ namespace storm { static const storm::dd::DdType DdType = ModelType::DdType; explicit SymbolicMdpPrctlModelChecker(ModelType const& model); - explicit SymbolicMdpPrctlModelChecker(ModelType const& model, std::unique_ptr>&& linearEquationSolverFactory); // The implemented methods of the AbstractModelChecker interface. virtual bool canHandle(CheckTask const& checkTask) const override; @@ -28,11 +27,7 @@ namespace storm { virtual std::unique_ptr computeCumulativeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; virtual std::unique_ptr computeReachabilityRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; - - - private: - // An object that is used for retrieving linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; + virtual std::unique_ptr computeReachabilityTimes(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask const& checkTask) override; }; } // namespace modelchecker diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp index 280c5aaff..ce5bf4467 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.cpp @@ -3,6 +3,7 @@ #include "storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/storage/dd/DdManager.h" #include "storm/storage/dd/Add.h" @@ -19,17 +20,18 @@ #include "storm/modelchecker/results/SymbolicQuantitativeCheckResult.h" #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" +#include "storm/utility/Stopwatch.h" + #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/exceptions/UncheckedRequirementException.h" - namespace storm { namespace modelchecker { namespace helper { template - std::unique_ptr HybridDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. STORM_LOG_TRACE("Found " << phiStates.getNonZeroCount() << " phi states and " << psiStates.getNonZeroCount() << " psi states."); @@ -45,8 +47,12 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -62,10 +68,11 @@ namespace storm { storm::dd::Add subvector = submatrix * prob1StatesAsColumn; subvector = subvector.sumAbstract(model.getColumnVariables()); + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; auto req = linearEquationSolverFactory.getRequirements(env); req.clearLowerBounds(); req.clearUpperBounds(); - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); // Check whether we need to create an equation system. bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; @@ -81,9 +88,12 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::convertNumber(0.5)); // Translate the symbolic matrix/vector to their explicit representations and solve the equation system. + conversionWatch.start(); storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitSubmatrix)); solver->setBounds(storm::utility::zero(), storm::utility::one()); solver->solveEquations(env, x, b); @@ -97,8 +107,8 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - std::unique_ptr result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + std::unique_ptr HybridDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + std::unique_ptr result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result->asQuantitativeCheckResult().oneMinus(); return result; } @@ -110,7 +120,7 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0 = storm::utility::graph::performProbGreater0(model, transitionMatrix.notZero(), phiStates, psiStates, stepBound); @@ -120,8 +130,12 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -142,12 +156,15 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::zero()); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitSubmatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(x, &b, stepBound); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitSubmatrix); + multiplier->repeatedMultiply(env, x, &b, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new storm::modelchecker::HybridQuantitativeCheckResult(model.getReachableStates(), model.getReachableStates() && !maybeStates, psiStates.template toAdd(), maybeStates, odd, x)); } else { @@ -156,10 +173,12 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + storm::utility::Stopwatch conversionWatch(true); + // Create the ODD for the translation between symbolic and explicit storage. storm::dd::Odd odd = model.getReachableStates().createOdd(); @@ -168,36 +187,42 @@ namespace storm { // Translate the symbolic matrix to its explicit representations. storm::storage::SparseMatrix explicitMatrix = transitionMatrix.toMatrix(odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitMatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(x, nullptr, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); + multiplier->repeatedMultiply(env, x, nullptr, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); } template - std::unique_ptr HybridDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Compute the reward vector to add in each step based on the available reward models. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd odd = model.getReachableStates().createOdd(); - // Create the solution vector. std::vector x(model.getNumberOfStates(), storm::utility::zero()); + + storm::utility::Stopwatch conversionWatch(true); + + // Create the ODD for the translation between symbolic and explicit storage. + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Translate the symbolic matrix/vector to their explicit representations. storm::storage::SparseMatrix explicitMatrix = transitionMatrix.toMatrix(odd, odd); std::vector b = totalRewardVector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitMatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(x, &b, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); + multiplier->repeatedMultiply(env, x, &b, stepBound); // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); @@ -217,7 +242,7 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -237,8 +262,12 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -253,16 +282,17 @@ namespace storm { // Check the requirements of a linear equation solver // We might need to compute upper reward bounds for which the oneStepTargetProbabilities are needed. boost::optional> oneStepTargetProbs; + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; auto req = linearEquationSolverFactory.getRequirements(env); req.clearLowerBounds(); - if (req.requiresUpperBounds()) { + if (req.upperBounds()) { storm::dd::Add targetStatesAsColumn = targetStates.template toAdd(); targetStatesAsColumn = targetStatesAsColumn.swapVariables(model.getRowColumnMetaVariablePairs()); oneStepTargetProbs = submatrix * targetStatesAsColumn; oneStepTargetProbs = oneStepTargetProbs->sumAbstract(model.getColumnVariables()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement of the linear equation solver could not be matched."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); // Check whether we need to create an equation system. bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; @@ -278,9 +308,12 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::convertNumber(0.5)); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); storm::storage::SparseMatrix explicitSubmatrix = submatrix.toMatrix(odd, odd); std::vector b = subvector.toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Create the upper bounds vector if one was requested. boost::optional> upperBounds; if (oneStepTargetProbs) { @@ -306,22 +339,34 @@ namespace storm { } template - std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, targetStates, qualitative); + } + + template + std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates) { // Create ODD for the translation. + storm::utility::Stopwatch conversionWatch(true); storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = model.getTransitionMatrix().toMatrix(odd, odd); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); - std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, targetStates.toVector(odd), linearEquationSolverFactory); + std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, targetStates.toVector(odd)); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } template - std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel) { // Create ODD for the translation. + storm::utility::Stopwatch conversionWatch(true); storm::dd::Odd odd = model.getReachableStates().createOdd(); storm::storage::SparseMatrix explicitProbabilityMatrix = model.getTransitionMatrix().toMatrix(odd, odd); - - std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(model.getTransitionMatrix(), model.getColumnVariables()).toVector(odd), linearEquationSolverFactory); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + std::vector result = storm::modelchecker::helper::SparseDtmcPrctlHelper::computeLongRunAverageRewards(env, storm::solver::SolveGoal(), explicitProbabilityMatrix, rewardModel.getTotalRewardVector(model.getTransitionMatrix(), model.getColumnVariables()).toVector(odd)); return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), std::move(odd), std::move(result))); } diff --git a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h index 7bbee1795..9e20c5e2c 100644 --- a/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/HybridDtmcPrctlHelper.h @@ -23,23 +23,25 @@ namespace storm { public: typedef typename storm::models::symbolic::Model::RewardModelType RewardModelType; - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static std::unique_ptr computeNextProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); - static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative); - static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeLongRunAverageProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates); + + static std::unique_ptr computeLongRunAverageRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel); }; diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp index ad1903d1c..7cb054574 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp @@ -21,6 +21,9 @@ #include "storm/modelchecker/results/HybridQuantitativeCheckResult.h" #include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" + +#include "storm/utility/Stopwatch.h" #include "storm/exceptions/InvalidPropertyException.h" #include "storm/exceptions/UncheckedRequirementException.h" @@ -122,7 +125,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. storm::dd::Bdd transitionMatrixBdd = transitionMatrix.notZero(); @@ -146,23 +149,24 @@ namespace storm { // If we minimize, we know that the solution to the equation system is unique. bool uniqueSolution = dir == storm::solver::OptimizationDirection::Minimize; // Check for requirements of the solver early so we can adjust the maybe state computation accordingly. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir, true); + storm::solver::GeneralMinMaxLinearEquationSolverFactory linearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; SolverRequirementsData solverRequirementsData; bool extendMaybeStates = false; - if (!clearedRequirements.empty()) { - if (clearedRequirements.requiresNoEndComponents()) { + if (clearedRequirements.hasEnabledRequirement()) { + if (clearedRequirements.noEndComponents()) { STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearNoEndComponents(); } - if (clearedRequirements.requiresValidInitialScheduler()) { + if (clearedRequirements.validInitialScheduler()) { STORM_LOG_DEBUG("Scheduling valid scheduler computation, because the solver requires it."); clearedRequirements.clearValidInitialScheduler(); } clearedRequirements.clearBounds(); - STORM_LOG_THROW(clearedRequirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!clearedRequirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + clearedRequirements.getEnabledRequirementsAsString() + " not checked."); } storm::dd::Bdd extendedMaybeStates = maybeStates; @@ -172,8 +176,12 @@ namespace storm { extendedMaybeStates |= maybeStates.relationalProduct(transitionMatrixBdd.existsAbstract(model.getNondeterminismVariables()), model.getRowVariables(), model.getColumnVariables()); } + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = extendedMaybeStates.createOdd(); + conversionWatch.stop(); // Convert the maybe states BDD to an ADD. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -189,20 +197,21 @@ namespace storm { submatrix *= extendedMaybeStates.template toAdd().swapVariables(model.getRowColumnMetaVariablePairs()); // Only translate the matrix for now. + conversionWatch.start(); explicitRepresentation.first = submatrix.toMatrix(model.getNondeterminismVariables(), odd, odd); // Get all original maybe states in the extended matrix. solverRequirementsData.properMaybeStates = maybeStates.toVector(odd); - + // Compute the target states within the set of extended maybe states. storm::storage::BitVector targetStates = (extendedMaybeStates && statesWithProbability01.second).toVector(odd); - + conversionWatch.stop(); + // 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. @@ -215,13 +224,17 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Translate the symbolic matrix/vector to their explicit representations and solve the equation system. + conversionWatch.start(); explicitRepresentation = submatrix.toMatrixVector(subvector, model.getNondeterminismVariables(), odd, odd); + conversionWatch.stop(); - if (requirements.requiresValidInitialScheduler()) { + if (requirements.validInitialScheduler()) { solverRequirementsData.initialScheduler = computeValidInitialSchedulerForUntilProbabilities(explicitRepresentation.first, explicitRepresentation.second); } } + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Create the solution vector. std::vector x(explicitRepresentation.first.getRowGroupCount(), storm::utility::zero()); @@ -238,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.requiresNoEndComponents() && solverRequirementsData.ecInformation) { + if (requirements.noEndComponents() && solverRequirementsData.ecInformation) { std::vector extendedVector(solverRequirementsData.properMaybeStates.getNumberOfSetBits()); solverRequirementsData.ecInformation.get().setValues(extendedVector, solverRequirementsData.properMaybeStates, x); x = std::move(extendedVector); @@ -258,8 +271,8 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { - std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Maximize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + std::unique_ptr HybridMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Maximize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result->asQuantitativeCheckResult().oneMinus(); return result; } @@ -270,7 +283,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0; @@ -285,8 +298,12 @@ namespace storm { // If there are maybe states, we need to perform matrix-vector multiplications. if (!maybeStates.isZero()) { + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = maybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -307,10 +324,13 @@ namespace storm { std::vector x(maybeStates.getNonZeroCount(), storm::utility::zero()); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); std::pair, std::vector> explicitRepresentation = submatrix.toMatrixVector(subvector, model.getNondeterminismVariables(), odd, odd); - - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitRepresentation.first)); - solver->repeatedMultiply(env, dir, x, &explicitRepresentation.second, stepBound); + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitRepresentation.first); + multiplier->repeatedMultiplyAndReduce(env, dir, x, &explicitRepresentation.second, stepBound); // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new storm::modelchecker::HybridQuantitativeCheckResult(model.getReachableStates(), model.getReachableStates() && !maybeStates, psiStates.template toAdd(), maybeStates, odd, x)); @@ -320,10 +340,12 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. storm::dd::Odd odd = model.getReachableStates().createOdd(); @@ -332,36 +354,42 @@ namespace storm { // Create the solution vector (and initialize it to the state rewards of the model). std::vector x = rewardModel.getStateRewardVector().toVector(odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitMatrix)); - solver->repeatedMultiply(env, dir, x, nullptr, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitMatrix); + multiplier->repeatedMultiplyAndReduce(env, dir, x, nullptr, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); } template - std::unique_ptr HybridMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Compute the reward vector to add in each step based on the available reward models. storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); - // Create the ODD for the translation between symbolic and explicit storage. - storm::dd::Odd odd = model.getReachableStates().createOdd(); - // Create the solution vector. std::vector x(model.getNumberOfStates(), storm::utility::zero()); + + storm::utility::Stopwatch conversionWatch(true); + + // Create the ODD for the translation between symbolic and explicit storage. + storm::dd::Odd odd = model.getReachableStates().createOdd(); // Translate the symbolic matrix/vector to their explicit representations. std::pair, std::vector> explicitRepresentation = transitionMatrix.toMatrixVector(totalRewardVector, model.getNondeterminismVariables(), odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Perform the matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, std::move(explicitRepresentation.first)); - solver->repeatedMultiply(env, dir, x, &explicitRepresentation.second, stepBound); - + auto multiplier = storm::solver::MultiplierFactory().create(env, explicitRepresentation.first); + multiplier->repeatedMultiplyAndReduce(env, dir, x, &explicitRepresentation.second, stepBound); + // Return a hybrid check result that stores the numerical values explicitly. return std::unique_ptr(new HybridQuantitativeCheckResult(model.getReachableStates(), model.getManager().getBddZero(), model.getManager().template getAddZero(), model.getReachableStates(), odd, x)); } @@ -487,7 +515,7 @@ namespace storm { } template - std::unique_ptr HybridMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr HybridMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -517,34 +545,39 @@ namespace storm { // If we maximize, we know that the solution to the equation system is unique. bool uniqueSolution = dir == storm::solver::OptimizationDirection::Maximize; // Check for requirements of the solver this early so we can adapt the maybe states accordingly. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir, true); + storm::solver::GeneralMinMaxLinearEquationSolverFactory linearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env, uniqueSolution, dir); storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements; bool extendMaybeStates = false; - if (!clearedRequirements.empty()) { - if (clearedRequirements.requiresNoEndComponents()) { + if (clearedRequirements.hasEnabledRequirement()) { + if (clearedRequirements.noEndComponents()) { STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearNoEndComponents(); } - if (clearedRequirements.requiresValidInitialScheduler()) { + if (clearedRequirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearValidInitialScheduler(); } clearedRequirements.clearLowerBounds(); - if (clearedRequirements.requiresUpperBounds()) { + if (clearedRequirements.upperBounds()) { STORM_LOG_DEBUG("Computing upper bounds, because the solver requires it."); extendMaybeStates = true; clearedRequirements.clearUpperBounds(); } - STORM_LOG_THROW(clearedRequirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!clearedRequirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + clearedRequirements.getEnabledRequirementsAsString() + " not checked."); } // Compute the set of maybe states that we are required to keep in the translation to explicit. storm::dd::Bdd requiredMaybeStates = extendMaybeStates ? maybeStatesWithTargetStates : maybeStates; + storm::utility::Stopwatch conversionWatch; + // Create the ODD for the translation between symbolic and explicit storage. + conversionWatch.start(); storm::dd::Odd odd = requiredMaybeStates.createOdd(); + conversionWatch.stop(); // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -559,31 +592,36 @@ namespace storm { // Then compute the reward vector to use in the computation. storm::dd::Add subvector = rewardModel.getTotalRewardVector(maybeStatesAdd, choiceFilterAdd, submatrix, model.getColumnVariables()); + conversionWatch.start(); std::vector rowGroupSizes = (submatrix.notZero().existsAbstract(model.getColumnVariables()) || subvector.notZero()).template toAdd().sumAbstract(model.getNondeterminismVariables()).toVector(odd); + conversionWatch.stop(); // Finally cut away all columns targeting non-maybe states (or non-(maybe or target) states, respectively). submatrix *= extendMaybeStates ? maybeStatesWithTargetStates.swapVariables(model.getRowColumnMetaVariablePairs()).template toAdd() : maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Translate the symbolic matrix/vector to their explicit representations. + conversionWatch.start(); std::pair, std::vector> explicitRepresentation = submatrix.toMatrixVector(std::move(rowGroupSizes), subvector, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), odd, odd); - + conversionWatch.stop(); + STORM_LOG_INFO("Converting symbolic matrix/vector to explicit representation done in " << conversionWatch.getTimeInMilliseconds() << "ms."); + // Fulfill the solver's requirements. SolverRequirementsData solverRequirementsData; if (extendMaybeStates) { storm::storage::BitVector targetStates = computeTargetStatesForReachabilityRewardsFromExplicitRepresentation(explicitRepresentation.first); solverRequirementsData.properMaybeStates = ~targetStates; - if (requirements.requiresNoEndComponents()) { - eliminateEndComponentsAndTargetStatesReachabilityRewards(explicitRepresentation, solverRequirementsData, targetStates, requirements.requiresUpperBounds()); + if (requirements.noEndComponents()) { + eliminateEndComponentsAndTargetStatesReachabilityRewards(explicitRepresentation, solverRequirementsData, targetStates, requirements.upperBounds()); // The solution becomes unique after end components have been eliminated. uniqueSolution = true; } else { - if (requirements.requiresValidInitialScheduler()) { + if (requirements.validInitialScheduler()) { // Compute a valid initial scheduler. solverRequirementsData.initialScheduler = computeValidInitialSchedulerForReachabilityRewards(explicitRepresentation.first, solverRequirementsData.properMaybeStates, targetStates); } - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { solverRequirementsData.oneStepTargetProbabilities = computeOneStepTargetProbabilitiesFromExtendedExplicitRepresentation(explicitRepresentation.first, solverRequirementsData.properMaybeStates, targetStates); } @@ -603,7 +641,7 @@ namespace storm { solver->setHasUniqueSolution(uniqueSolution); // If the solver requires upper bounds, compute them now. - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { setUpperRewardBounds(*solver, dir, explicitRepresentation.first, explicitRepresentation.second, solverRequirementsData.oneStepTargetProbabilities.get()); } @@ -619,7 +657,7 @@ namespace storm { solver->solveEquations(env, dir, x, explicitRepresentation.second); // If we eliminated end components, we need to extend the solution vector. - if (requirements.requiresNoEndComponents() && solverRequirementsData.ecInformation) { + if (requirements.noEndComponents() && solverRequirementsData.ecInformation) { std::vector extendedVector(solverRequirementsData.properMaybeStates.getNumberOfSetBits()); solverRequirementsData.ecInformation.get().setValues(extendedVector, solverRequirementsData.properMaybeStates, x); x = std::move(extendedVector); @@ -638,6 +676,13 @@ namespace storm { } } + template + std::unique_ptr HybridMdpPrctlHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, dir, model, transitionMatrix, rewardModel, targetStates, qualitative); + } + + template class HybridMdpPrctlHelper; template class HybridMdpPrctlHelper; diff --git a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h index 224830220..ce7072624 100644 --- a/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.h @@ -24,19 +24,21 @@ namespace storm { public: typedef typename storm::models::symbolic::NondeterministicModel::RewardModelType RewardModelType; - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static std::unique_ptr computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative); + + static std::unique_ptr computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative); }; } diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp index fd52e4437..0e5cf1849 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.cpp @@ -11,6 +11,7 @@ #include "storm/storage/ConsecutiveUint64DynamicPriorityQueue.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h" #include "storm/modelchecker/hints/ExplicitModelCheckerHint.h" @@ -23,6 +24,7 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/utility/Stopwatch.h" #include "storm/utility/ProgressMeasurement.h" @@ -41,7 +43,7 @@ namespace storm { namespace modelchecker { namespace helper { template - std::vector SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); // If we identify the states that have probability 0 of reaching the target states, we can exclude them in the further analysis. @@ -68,10 +70,9 @@ namespace storm { // Create the vector with which to multiply. std::vector subresult(maybeStates.getNumberOfSetBits()); - // Perform the matrix vector multiplication as often as required by the formula bound. - goal.restrictRelevantValues(maybeStates); - std::unique_ptr> solver = storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, std::move(submatrix), storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(subresult, &b, stepBound); + // Perform the matrix vector multiplication + auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); + multiplier->repeatedMultiply(env, subresult, &b, stepBound); // Set the values of the resulting vector accordingly. storm::utility::vector::setVectorValues(result, maybeStates, subresult); @@ -110,14 +111,15 @@ namespace storm { } template - std::vector analyzeNonTrivialDtmcEpochModel(Environment const& env, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& linEqSolver, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional const& lowerBound, boost::optional const& upperBound) { + std::vector analyzeNonTrivialDtmcEpochModel(Environment const& env, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& linEqSolver, boost::optional const& lowerBound, boost::optional const& upperBound) { // Update some data for the case that the Matrix has changed if (epochModel.epochMatrixChanged) { x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero()); - linEqSolver = linearEquationSolverFactory.create(env, epochModel.epochMatrix, storm::solver::LinearEquationSolverTask::SolveEquations); + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; + linEqSolver = linearEquationSolverFactory.create(env, epochModel.epochMatrix); linEqSolver->setCachingEnabled(true); - auto req = linEqSolver->getRequirements(env, storm::solver::LinearEquationSolverTask::SolveEquations); + auto req = linEqSolver->getRequirements(env); if (lowerBound) { linEqSolver->setLowerBound(lowerBound.get()); req.clearLowerBounds(); @@ -126,7 +128,7 @@ namespace storm { linEqSolver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); } // Prepare the right hand side of the equation system @@ -149,13 +151,13 @@ namespace storm { } template<> - std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The specified property is not supported by this value type."); return std::map(); } template - std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::map SparseDtmcPrctlHelper::computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula) { storm::utility::Stopwatch swAll(true), swBuild, swCheck; storm::modelchecker::helper::rewardbounded::MultiDimensionalRewardUnfolding rewardUnfolding(model, rewardBoundedFormula); @@ -179,7 +181,8 @@ namespace storm { // In case of cdf export we store the necessary data. std::vector> cdfData; - // Set the correct equation problem format + // Set the correct equation problem format. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; rewardUnfolding.setEquationSystemFormatForEpochModel(linearEquationSolverFactory.getEquationProblemFormat(preciseEnv)); bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(preciseEnv) == solver::LinearEquationSolverProblemFormat::EquationSystem; @@ -195,7 +198,7 @@ namespace storm { if ((convertToEquationSystem && epochModel.epochMatrix.isIdentityMatrix()) || (!convertToEquationSystem && epochModel.epochMatrix.getEntryCount() == 0)) { rewardUnfolding.setSolutionForCurrentEpoch(analyzeTrivialDtmcEpochModel(epochModel)); } else { - rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialDtmcEpochModel(preciseEnv, epochModel, x, b, linEqSolver, linearEquationSolverFactory, lowerBound, upperBound)); + rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialDtmcEpochModel(preciseEnv, epochModel, x, b, linEqSolver, lowerBound, upperBound)); } swCheck.stop(); if (storm::settings::getModule().isExportCdfSet() && !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) { @@ -242,7 +245,7 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); @@ -290,6 +293,7 @@ namespace storm { // In this case we have have to compute the probabilities. // Check whether we need to convert the input to equation system format. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; // We can eliminate the rows and columns from the original transition probability matrix. @@ -328,9 +332,9 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative) { goal.oneMinus(); - std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), ~psiStates, qualitative, linearEquationSolverFactory); + std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), ~psiStates, qualitative); for (auto& entry : result) { entry = storm::utility::one() - entry; } @@ -338,19 +342,19 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates) { // Create the vector with which to multiply and initialize it correctly. std::vector result(transitionMatrix.getRowCount()); storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); // Perform one single matrix-vector multiplication. - std::unique_ptr> solver = linearEquationSolverFactory.create(env, transitionMatrix, storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(result, nullptr, 1); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->multiply(env, result, nullptr, result); return result; } template - std::vector SparseDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Initialize result to the null vector. std::vector result(transitionMatrix.getRowCount()); @@ -358,14 +362,14 @@ namespace storm { std::vector totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix); // Perform the matrix vector multiplication as often as required by the formula bound. - std::unique_ptr> solver = storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, transitionMatrix, storm::solver::LinearEquationSolverTask::Multiply); - solver->repeatedMultiply(result, &totalRewardVector, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiply(env, result, &totalRewardVector, stepBound); return result; } template - std::vector SparseDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount) { // Only compute the result if the model has a state-based reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -373,19 +377,38 @@ namespace storm { std::vector result = rewardModel.getStateRewardVector(); // Perform the matrix vector multiplication as often as required by the formula bound. - std::unique_ptr> solver = storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, transitionMatrix); - solver->repeatedMultiply(result, nullptr, stepCount); - + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiply(env, result, nullptr, stepCount); + return result; } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { - return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); }, targetStates, qualitative, linearEquationSolverFactory, hint); + std::vector SparseDtmcPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, ModelCheckerHint const& hint) { + // Identify the states from which only states with zero reward are reachable. + // We can then compute reachability rewards assuming these states as target set. + storm::storage::BitVector statesWithoutReward = rewardModel.getStatesWithZeroReward(transitionMatrix); + storm::storage::BitVector rew0States = storm::utility::graph::performProbGreater0(backwardTransitions, statesWithoutReward, ~statesWithoutReward); + rew0States.complement(); + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0States, qualitative, hint); + } + + template + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { + + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, + [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { + return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates); + }, + targetStates, qualitative, + [&] () { + return rewardModel.getStatesWithZeroReward(transitionMatrix); + }, + hint); } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const&, storm::storage::BitVector const& maybeStates) { @@ -393,9 +416,28 @@ namespace storm { storm::utility::vector::selectVectorValues(result, maybeStates, totalStateRewardVector); return result; }, - targetStates, qualitative, linearEquationSolverFactory, hint); + targetStates, qualitative, + [&] () { + return storm::utility::vector::filterZero(totalStateRewardVector); + }, + hint); } + template + std::vector SparseDtmcPrctlHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) { + + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, + [&] (uint_fast64_t numberOfRows, storm::storage::SparseMatrix const&, storm::storage::BitVector const&) { + return std::vector(numberOfRows, storm::utility::one()); + }, + targetStates, qualitative, + [&] () { + return storm::storage::BitVector(transitionMatrix.getRowGroupCount(), false); + }, + hint); + } + + // This function computes an upper bound on the reachability rewards (see Baier et al, CAV'17). template std::vector computeUpperRewardBounds(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& rewards, std::vector const& oneStepTargetProbabilities) { @@ -410,24 +452,32 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowCount(), storm::utility::zero()); + // Determine which states have reward zero + storm::storage::BitVector rew0States; + if (storm::settings::getModule().isFilterRewZeroSet()) { + rew0States = storm::utility::graph::performProb1(backwardTransitions, zeroRewardStatesGetter(), targetStates); + } else { + rew0States = targetStates; + } + // Determine which states have a reward that is less than infinity. storm::storage::BitVector maybeStates; if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().getComputeOnlyMaybeStates()) { maybeStates = hint.template asExplicitModelCheckerHint().getMaybeStates(); - storm::utility::vector::setVectorValues(result, ~(maybeStates | targetStates), storm::utility::infinity()); + storm::utility::vector::setVectorValues(result, ~(maybeStates | rew0States), storm::utility::infinity()); - STORM_LOG_INFO("Preprocessing: " << targetStates.getNumberOfSetBits() << " target states (" << maybeStates.getNumberOfSetBits() << " states remaining)."); + STORM_LOG_INFO("Preprocessing: " << rew0States.getNumberOfSetBits() << " States with reward zero (" << maybeStates.getNumberOfSetBits() << " states remaining)."); } else { storm::storage::BitVector trueStates(transitionMatrix.getRowCount(), true); - storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(backwardTransitions, trueStates, targetStates); + storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(backwardTransitions, trueStates, rew0States); infinityStates.complement(); - maybeStates = ~(targetStates | infinityStates); + maybeStates = ~(rew0States | infinityStates); - STORM_LOG_INFO("Preprocessing: " << infinityStates.getNumberOfSetBits() << " states with reward infinity, " << targetStates.getNumberOfSetBits() << " target states (" << maybeStates.getNumberOfSetBits() << " states remaining)."); + STORM_LOG_INFO("Preprocessing: " << infinityStates.getNumberOfSetBits() << " states with reward infinity, " << rew0States.getNumberOfSetBits() << " states with reward zero (" << maybeStates.getNumberOfSetBits() << " states remaining)."); storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity()); } @@ -440,6 +490,7 @@ namespace storm { } else { if (!maybeStates.empty()) { // Check whether we need to convert the input to equation system format. + storm::solver::GeneralLinearEquationSolverFactory linearEquationSolverFactory; bool convertToEquationSystem = linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem; // In this case we have to compute the reward values for the remaining states. @@ -461,11 +512,11 @@ namespace storm { storm::solver::LinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env); boost::optional> upperRewardBounds; requirements.clearLowerBounds(); - if (requirements.requiresUpperBounds()) { - upperRewardBounds = computeUpperRewardBounds(submatrix, b, transitionMatrix.getConstrainedRowSumVector(maybeStates, targetStates)); + if (requirements.upperBounds()) { + upperRewardBounds = computeUpperRewardBounds(submatrix, b, transitionMatrix.getConstrainedRowSumVector(maybeStates, rew0States)); requirements.clearUpperBounds(); } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "There are unchecked requirements of the solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); // If necessary, convert the matrix from the fixpoint notation to the form needed for the equation system. if (convertToEquationSystem) { @@ -492,27 +543,27 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, std::move(goal), transitionMatrix, psiStates, nullptr, linearEquationSolverFactory); + std::vector SparseDtmcPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates) { + return SparseCtmcCslHelper::computeLongRunAverageProbabilities(env, std::move(goal), transitionMatrix, psiStates, nullptr); } template - std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, rewardModel, nullptr, linearEquationSolverFactory); + std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel) { + return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, rewardModel, nullptr); } template - std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { - return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, stateRewards, nullptr, linearEquationSolverFactory); + std::vector SparseDtmcPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards) { + return SparseCtmcCslHelper::computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, stateRewards, nullptr); } template - typename SparseDtmcPrctlHelper::BaierTransformedModel SparseDtmcPrctlHelper::computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + typename SparseDtmcPrctlHelper::BaierTransformedModel SparseDtmcPrctlHelper::computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards) { BaierTransformedModel result; // Start by computing all 'before' states, i.e. the states for which the conditional probability is defined. - std::vector probabilitiesToReachConditionStates = computeUntilProbabilities(env, storm::solver::SolveGoal(), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), conditionStates, false, linearEquationSolverFactory); + std::vector probabilitiesToReachConditionStates = computeUntilProbabilities(env, storm::solver::SolveGoal(), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowCount(), true), conditionStates, false); result.beforeStates = storm::storage::BitVector(targetStates.size(), true); uint_fast64_t state = 0; @@ -644,13 +695,13 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative) { // Prepare result vector. std::vector result(transitionMatrix.getRowCount(), storm::utility::infinity()); if (!conditionStates.empty()) { - BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, boost::none, linearEquationSolverFactory); + BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, boost::none); if (transformedModel.noTargetStates) { storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, storm::utility::zero()); @@ -668,7 +719,7 @@ namespace storm { newRelevantValues = transformedModel.getNewRelevantStates(); } goal.setRelevantValues(std::move(newRelevantValues)); - std::vector conditionalProbabilities = computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), storm::storage::BitVector(newTransitionMatrix.getRowCount(), true), transformedModel.targetStates.get(), qualitative, linearEquationSolverFactory); + std::vector conditionalProbabilities = computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), storm::storage::BitVector(newTransitionMatrix.getRowCount(), true), transformedModel.targetStates.get(), qualitative); storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalProbabilities); } @@ -678,12 +729,12 @@ namespace storm { } template - std::vector SparseDtmcPrctlHelper::computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory) { + std::vector SparseDtmcPrctlHelper::computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative) { // Prepare result vector. std::vector result(transitionMatrix.getRowCount(), storm::utility::infinity()); if (!conditionStates.empty()) { - BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, rewardModel.getTotalRewardVector(transitionMatrix), linearEquationSolverFactory); + BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, rewardModel.getTotalRewardVector(transitionMatrix)); if (transformedModel.noTargetStates) { storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, storm::utility::zero()); @@ -701,7 +752,7 @@ namespace storm { newRelevantValues = transformedModel.getNewRelevantStates(); } goal.setRelevantValues(std::move(newRelevantValues)); - std::vector conditionalRewards = computeReachabilityRewards(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), transformedModel.stateRewards.get(), transformedModel.targetStates.get(), qualitative, linearEquationSolverFactory); + std::vector conditionalRewards = computeReachabilityRewards(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), transformedModel.stateRewards.get(), transformedModel.targetStates.get(), qualitative); storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalRewards); } } diff --git a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h index ead15de74..16702ffed 100644 --- a/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseDtmcPrctlHelper.h @@ -28,36 +28,40 @@ namespace storm { class SparseDtmcPrctlHelper { public: - static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::map computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::map computeRewardBoundedValues(Environment const& env, storm::models::sparse::Dtmc const& model, std::shared_ptr rewardBoundedFormula); - static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeNextProbabilities(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates); - static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative); - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount); - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); + + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::vector const& totalStateRewardVector, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); + + static std::vector computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& psiStates); - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel); - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewards); - static std::vector computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative); - static std::vector computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static std::vector computeConditionalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, bool qualitative); private: - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, std::function const& zeroRewardStatesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); struct BaierTransformedModel { BaierTransformedModel() : noTargetStates(false) { @@ -74,7 +78,7 @@ namespace storm { bool noTargetStates; }; - static BaierTransformedModel computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards, storm::solver::LinearEquationSolverFactory const& linearEquationSolverFactory); + static BaierTransformedModel computeBaierTransformation(Environment const& env, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, boost::optional> const& stateRewards); }; } } diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 10311c2a2..58c94a95b 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -21,9 +21,11 @@ #include "storm/storage/Scheduler.h" #include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/LpSolver.h" #include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" @@ -33,6 +35,8 @@ #include "storm/utility/ProgressMeasurement.h" #include "storm/utility/export.h" +#include "storm/transformer/EndComponentEliminator.h" + #include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/exceptions/InvalidStateException.h" @@ -48,7 +52,7 @@ namespace storm { namespace helper { template - std::vector SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + std::vector SparseMdpPrctlHelper::computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint) { std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); // Determine the states that have 0 probability of reaching the target states. @@ -74,9 +78,8 @@ namespace storm { // Create the vector with which to multiply. std::vector subresult(maybeStates.getNumberOfSetBits()); - goal.restrictRelevantValues(maybeStates); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix)); - solver->repeatedMultiply(env, subresult, &b, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, submatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), subresult, &b, stepBound); // Set the values of the resulting vector accordingly. storm::utility::vector::setVectorValues(result, maybeStates, subresult); @@ -137,11 +140,12 @@ namespace storm { } template - std::vector analyzeNonTrivialMdpEpochModel(Environment const& env, OptimizationDirection dir, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& minMaxSolver, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, boost::optional const& lowerBound, boost::optional const& upperBound) { + std::vector analyzeNonTrivialMdpEpochModel(Environment const& env, OptimizationDirection dir, typename rewardbounded::MultiDimensionalRewardUnfolding::EpochModel& epochModel, std::vector& x, std::vector& b, std::unique_ptr>& minMaxSolver, boost::optional const& lowerBound, boost::optional const& upperBound) { // Update some data for the case that the Matrix has changed if (epochModel.epochMatrixChanged) { x.assign(epochModel.epochMatrix.getRowGroupCount(), storm::utility::zero()); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; minMaxSolver = minMaxLinearEquationSolverFactory.create(env, epochModel.epochMatrix); minMaxSolver->setHasUniqueSolution(); minMaxSolver->setOptimizationDirection(dir); @@ -156,7 +160,7 @@ namespace storm { minMaxSolver->setUpperBound(upperBound.get()); req.clearUpperBounds(); } - STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "At least one requirement was not checked."); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); minMaxSolver->setRequirementsChecked(); } else { auto choicesTmp = minMaxSolver->getSchedulerChoices(); @@ -183,7 +187,7 @@ namespace storm { } template - std::map SparseMdpPrctlHelper::computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::map SparseMdpPrctlHelper::computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates) { storm::utility::Stopwatch swAll(true), swBuild, swCheck; // Get lower and upper bounds for the solution. @@ -217,7 +221,7 @@ namespace storm { if (epochModel.epochMatrix.getEntryCount() == 0) { rewardUnfolding.setSolutionForCurrentEpoch(analyzeTrivialMdpEpochModel(dir, epochModel)); } else { - rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialMdpEpochModel(preciseEnv, dir, epochModel, x, b, minMaxSolver, minMaxLinearEquationSolverFactory, lowerBound, upperBound)); + rewardUnfolding.setSolutionForCurrentEpoch(analyzeNonTrivialMdpEpochModel(preciseEnv, dir, epochModel, x, b, minMaxSolver, lowerBound, upperBound)); } swCheck.stop(); if (storm::settings::getModule().isExportCdfSet() && !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) { @@ -265,14 +269,14 @@ namespace storm { } template - std::vector SparseMdpPrctlHelper::computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates) { // Create the vector with which to multiply and initialize it correctly. std::vector result(transitionMatrix.getRowGroupCount()); storm::utility::vector::setVectorValues(result, nextStates, storm::utility::one()); - std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, transitionMatrix); - solver->repeatedMultiply(env, dir, result, nullptr, 1); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->multiplyAndReduce(env, dir, result, nullptr, result); return result; } @@ -422,7 +426,7 @@ namespace storm { } template - SparseMdpHintType computeHints(Environment const& env, SolutionType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, boost::optional const& selectedChoices = boost::none) { + SparseMdpHintType computeHints(Environment const& env, SolutionType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, boost::optional const& selectedChoices = boost::none) { SparseMdpHintType result; // The solution to the min-max equation system is unique if we minimize until probabilities or @@ -433,11 +437,11 @@ namespace storm { // Check for requirements of the solver. bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().hasSchedulerHint(); - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, !hasSchedulerHint); - if (!requirements.empty()) { - + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, dir, hasSchedulerHint); + if (requirements.hasEnabledRequirement()) { // If the solver still requires no end-components, we have to eliminate them later. - if (requirements.requiresNoEndComponents()) { + if (requirements.noEndComponents()) { 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."); result.eliminateEndComponents = true; @@ -447,7 +451,7 @@ namespace storm { } // If the solver requires an initial scheduler, compute one now. - if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) { + if (requirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); result.schedulerHint = computeValidSchedulerHint(env, type, transitionMatrix, backwardTransitions, maybeStates, phiStates, targetStates); requirements.clearValidInitialScheduler(); @@ -459,11 +463,11 @@ namespace storm { } else if (type == SolutionType::ExpectedRewards) { requirements.clearLowerBounds(); } - if (requirements.requiresUpperBounds()) { + if (requirements.upperBounds()) { result.computeUpperBounds = true; requirements.clearUpperBounds(); } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "There are unchecked requirements of the solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); } else { STORM_LOG_DEBUG("Solver has no requirements."); } @@ -515,12 +519,13 @@ namespace storm { }; template - MaybeStateResult computeValuesForMaybeStates(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix&& submatrix, std::vector const& b, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, SparseMdpHintType& hint) { + MaybeStateResult computeValuesForMaybeStates(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix&& submatrix, std::vector const& b, bool produceScheduler, SparseMdpHintType& hint) { // Initialize the solution vector. std::vector x = hint.hasValueHint() ? std::move(hint.getValueHint()) : std::vector(submatrix.getRowGroupCount(), hint.hasLowerResultBound() ? hint.getLowerResultBound() : storm::utility::zero()); // Set up the solver. + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix)); solver->setRequirementsChecked(); solver->setHasUniqueSolution(hint.hasUniqueSolution()); @@ -546,7 +551,7 @@ namespace storm { if (solver->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { auto resultIt = x.begin(); for (auto const& entry : solver->getUpperBounds()) { - STORM_LOG_ASSERT(*resultIt <= entry, "Expecting result value for state " << std::distance(x.begin(), resultIt) << " to be <= " << entry << ", but got " << *resultIt << "."); + STORM_LOG_ASSERT(*resultIt <= entry + env.solver().minMax().getPrecision(), "Expecting result value for state " << std::distance(x.begin(), resultIt) << " to be <= " << entry << ", but got " << *resultIt << "."); ++resultIt; } } @@ -702,7 +707,7 @@ namespace storm { } template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { STORM_LOG_THROW(!qualitative || !produceScheduler, storm::exceptions::InvalidSettingsException, "Cannot produce scheduler when performing qualitative model checking only."); // Prepare resulting vector. @@ -732,7 +737,7 @@ namespace storm { // In this case we have have to compute the remaining probabilities. // Obtain proper hint information either from the provided hint or from requirements of the solver. - SparseMdpHintType hintInformation = computeHints(env, SolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1, minMaxLinearEquationSolverFactory); + SparseMdpHintType hintInformation = computeHints(env, SolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1); // Declare the components of the equation system we will solve. storm::storage::SparseMatrix submatrix; @@ -751,7 +756,7 @@ namespace storm { } // Now compute the results for the maybe states. - MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, minMaxLinearEquationSolverFactory, hintInformation); + MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation); // If we eliminated end components, we need to extract the result differently. if (ecInformation && ecInformation.get().getEliminatedEndComponents()) { @@ -780,7 +785,7 @@ namespace storm { } template - std::vector SparseMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, bool useMecBasedTechnique) { + std::vector SparseMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, bool useMecBasedTechnique) { if (useMecBasedTechnique) { storm::storage::MaximalEndComponentDecomposition mecDecomposition(transitionMatrix, backwardTransitions, psiStates); storm::storage::BitVector statesInPsiMecs(transitionMatrix.getRowGroupCount()); @@ -790,10 +795,10 @@ namespace storm { } } - return std::move(computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, psiStates, statesInPsiMecs, qualitative, false, minMaxLinearEquationSolverFactory).values); + return std::move(computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, psiStates, statesInPsiMecs, qualitative, false).values); } else { goal.oneMinus(); - std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), ~psiStates, qualitative, false, minMaxLinearEquationSolverFactory).values; + std::vector result = computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), ~psiStates, qualitative, false).values; for (auto& element : result) { element = storm::utility::one() - element; } @@ -803,7 +808,7 @@ namespace storm { template template - std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount) { // Only compute the result if the model has a state-based reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -811,15 +816,15 @@ namespace storm { // Initialize result to state rewards of the this->getModel(). std::vector result(rewardModel.getStateRewardVector()); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, transitionMatrix); - solver->repeatedMultiply(env, result, nullptr, stepCount); - + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, nullptr, stepCount); + return result; } template template - std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -830,27 +835,123 @@ namespace storm { // Initialize result to the zero vector. std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, transitionMatrix); - solver->repeatedMultiply(env, result, &totalRewardVector, stepBound); + auto multiplier = storm::solver::MultiplierFactory().create(env, transitionMatrix); + multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, &totalRewardVector, stepBound); return result; } template template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { + + // Reduce to reachability rewards + if (goal.minimize()) { + STORM_LOG_ERROR_COND(!produceScheduler, "Can not produce scheduler for this property (functionality not implemented"); + // Identify the states from which no reward can be collected under some scheduler + storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix); + storm::storage::BitVector statesWithZeroRewardChoice(transitionMatrix.getRowGroupCount(), false); + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + if (choicesWithoutReward.getNextSetIndex(transitionMatrix.getRowGroupIndices()[state])< transitionMatrix.getRowGroupIndices()[state + 1]) { + statesWithZeroRewardChoice.set(state); + } + } + storm::storage::BitVector rew0EStates = storm::utility::graph::performProbGreater0A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, statesWithZeroRewardChoice, ~statesWithZeroRewardChoice, false, 0, choicesWithoutReward); + rew0EStates.complement(); + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0EStates, qualitative, false, hint); + } else { + // Identify the states from which only states with zero reward are reachable. + storm::storage::BitVector statesWithoutReward = rewardModel.getStatesWithZeroReward(transitionMatrix); + storm::storage::BitVector rew0AStates = storm::utility::graph::performProbGreater0E(backwardTransitions, statesWithoutReward, ~statesWithoutReward); + rew0AStates.complement(); + + // There might be end components that consists only of states/choices with zero rewards. The reachability reward semantics would assign such + // end components reward infinity. To avoid this, we potentially need to eliminate such end components + storm::storage::BitVector trueStates(transitionMatrix.getRowGroupCount(), true); + if (storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, rew0AStates).full()) { + return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0AStates, qualitative, produceScheduler, hint); + } else { + // The transformation of schedulers for the ec-eliminated system back to the original one is not implemented. + STORM_LOG_ERROR_COND(!produceScheduler, "Can not produce scheduler for this property (functionality not implemented"); + storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix); + auto ecElimResult = storm::transformer::EndComponentEliminator::transform(transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), choicesWithoutReward, rew0AStates, true); + storm::storage::BitVector newRew0AStates(ecElimResult.matrix.getRowGroupCount(), false); + for (auto const& oldRew0AState : rew0AStates) { + newRew0AStates.set(ecElimResult.oldToNewStateMapping[oldRew0AState]); + } + + return computeReachabilityRewardsHelper(env, std::move(goal), ecElimResult.matrix, ecElimResult.matrix.transpose(true), + [&] (uint_fast64_t rowCount, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { + std::vector result; + std::vector oldChoiceRewards = rewardModel.getTotalRewardVector(transitionMatrix); + result.reserve(rowCount); + for (uint64_t newState : maybeStates) { + for (uint64_t newChoice = transitionMatrix.getRowGroupIndices()[newState]; newChoice < transitionMatrix.getRowGroupIndices()[newState + 1]; ++newChoice) { + uint64_t oldChoice = ecElimResult.newToOldRowMapping[newChoice]; + result.push_back(oldChoiceRewards[oldChoice]); + } + } + STORM_LOG_ASSERT(result.size() == rowCount, "Unexpected size of reward vector."); + return result; + }, newRew0AStates, qualitative, false, + [&] () { + storm::storage::BitVector newStatesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false); + for (auto const& oldStateWithoutRew : statesWithoutReward) { + newStatesWithoutReward.set(ecElimResult.oldToNewStateMapping[oldStateWithoutRew]); + } + return newStatesWithoutReward; + }, + [&] () { + storm::storage::BitVector newChoicesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false); + for (uint64_t newChoice = 0; newChoice < ecElimResult.matrix.getRowCount(); ++newChoice) { + if (choicesWithoutReward.get(ecElimResult.newToOldRowMapping[newChoice])) { + newChoicesWithoutReward.set(newChoice); + } + } + return newChoicesWithoutReward; + }); + } + } + } + + template + template + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); return computeReachabilityRewardsHelper(env, std::move(goal), transitionMatrix, backwardTransitions, [&rewardModel] (uint_fast64_t rowCount, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& maybeStates) { return rewardModel.getTotalRewardVector(rowCount, transitionMatrix, maybeStates); }, - targetStates, qualitative, produceScheduler, minMaxLinearEquationSolverFactory, hint); + targetStates, qualitative, produceScheduler, + [&] () { + return rewardModel.getStatesWithZeroReward(transitionMatrix); + }, + [&] () { + return rewardModel.getChoicesWithZeroReward(transitionMatrix); + }, + hint); + } + + template + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) { + return computeReachabilityRewardsHelper(env, std::move(goal), transitionMatrix, backwardTransitions, + [] (uint_fast64_t rowCount, storm::storage::SparseMatrix const&, storm::storage::BitVector const&) { + return std::vector(rowCount, storm::utility::one()); + }, + targetStates, qualitative, produceScheduler, + [&] () { + return storm::storage::BitVector(transitionMatrix.getRowGroupCount(), false); + }, + [&] () { + return storm::storage::BitVector(transitionMatrix.getRowCount(), false); + }, + hint); } #ifdef STORM_HAVE_CARL template - std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative) { // Only compute the result if the reward model is not empty. STORM_LOG_THROW(!intervalRewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); return computeReachabilityRewardsHelper(env, std::move(goal), transitionMatrix, backwardTransitions, \ @@ -862,12 +963,18 @@ namespace storm { result.push_back(lowerBoundOfIntervals ? interval.lower() : interval.upper()); } return result; - }, \ - targetStates, qualitative, false, minMaxLinearEquationSolverFactory).values; + }, + targetStates, qualitative, false, + [&] () { + return intervalRewardModel.getStatesWithFilter(transitionMatrix, [&](storm::Interval const& i) {return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());}); + }, + [&] () { + return intervalRewardModel.getChoicesWithFilter(transitionMatrix, [&](storm::Interval const& i) {return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());}); + }).values; } template<> - std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&&, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::models::sparse::StandardRewardModel const&, bool, storm::storage::BitVector const&, bool, storm::solver::MinMaxLinearEquationSolverFactory const&) { + std::vector SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&&, storm::storage::SparseMatrix const&, storm::storage::SparseMatrix const&, storm::models::sparse::StandardRewardModel const&, bool, storm::storage::BitVector const&, bool) { STORM_LOG_THROW(false, storm::exceptions::IllegalFunctionCallException, "Computing reachability rewards is unsupported for this data type."); } #endif @@ -875,18 +982,32 @@ namespace storm { struct QualitativeStateSetsReachabilityRewards { storm::storage::BitVector maybeStates; storm::storage::BitVector infinityStates; + storm::storage::BitVector rewardZeroStates; }; template QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewardsFromHint(ModelCheckerHint const& hint, storm::storage::BitVector const& targetStates) { QualitativeStateSetsReachabilityRewards result; result.maybeStates = hint.template asExplicitModelCheckerHint().getMaybeStates(); - result.infinityStates = ~(result.maybeStates | targetStates); + + // Treat the states with reward zero/infinity. + std::vector const& resultsForNonMaybeStates = hint.template asExplicitModelCheckerHint().getResultHint(); + result.infinityStates = storm::storage::BitVector(result.maybeStates.size()); + result.rewardZeroStates = storm::storage::BitVector(result.maybeStates.size()); + storm::storage::BitVector nonMaybeStates = ~result.maybeStates; + for (auto const& state : nonMaybeStates) { + if (storm::utility::isZero(resultsForNonMaybeStates[state])) { + result.rewardZeroStates.set(state, true); + } else { + STORM_LOG_THROW(storm::utility::isInfinity(resultsForNonMaybeStates[state]), storm::exceptions::IllegalArgumentException, "Expected that the result hint specifies probabilities in {0,infinity} for non-maybe states"); + result.infinityStates.set(state, true); + } + } return result; } template - QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates) { + QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter) { QualitativeStateSetsReachabilityRewards result; storm::storage::BitVector trueStates(transitionMatrix.getRowGroupCount(), true); if (goal.minimize()) { @@ -895,33 +1016,43 @@ namespace storm { result.infinityStates = storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, targetStates); } result.infinityStates.complement(); - result.maybeStates = ~(targetStates | result.infinityStates); + + if (storm::settings::getModule().isFilterRewZeroSet()) { + if (goal.minimize()) { + result.rewardZeroStates = storm::utility::graph::performProb1E(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, targetStates, zeroRewardChoicesGetter()); + } else { + result.rewardZeroStates = storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, zeroRewardStatesGetter(), targetStates); + } + } else { + result.rewardZeroStates = targetStates; + } + result.maybeStates = ~(result.rewardZeroStates | result.infinityStates); return result; } template - QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, ModelCheckerHint const& hint) { + QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, ModelCheckerHint const& hint, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter) { if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint().getComputeOnlyMaybeStates()) { return getQualitativeStateSetsReachabilityRewardsFromHint(hint, targetStates); } else { - return computeQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates); + return computeQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates, zeroRewardStatesGetter, zeroRewardChoicesGetter); } } template - void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& targetStates) { + void extendScheduler(storm::storage::Scheduler& scheduler, storm::solver::SolveGoal const& goal, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, std::function const& zeroRewardChoicesGetter) { // Finally, if we need to produce a scheduler, we also need to figure out the parts of the scheduler for - // the states with reward infinity. Moreover, we have to set some arbitrary choice for the remaining states - // to obtain a fully defined scheduler. - if (!goal.minimize()) { - storm::utility::graph::computeSchedulerProb0E(qualitativeStateSets.infinityStates, transitionMatrix, scheduler); - } else { + // the states with reward zero/infinity. + if (goal.minimize()) { + storm::utility::graph::computeSchedulerProb1E(qualitativeStateSets.rewardZeroStates, transitionMatrix, backwardTransitions, qualitativeStateSets.rewardZeroStates, targetStates, scheduler, zeroRewardChoicesGetter()); for (auto const& state : qualitativeStateSets.infinityStates) { scheduler.setChoice(0, state); } - } - for (auto const& state : targetStates) { - scheduler.setChoice(0, state); + } else { + storm::utility::graph::computeSchedulerProb0E(qualitativeStateSets.infinityStates, transitionMatrix, scheduler); + for (auto const& state : qualitativeStateSets.rewardZeroStates) { + scheduler.setChoice(0, state); + } } } @@ -949,21 +1080,21 @@ namespace storm { } template - void computeFixedPointSystemReachabilityRewards(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::BitVector const& targetStates, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, std::vector* oneStepTargetProbabilities = nullptr) { + void computeFixedPointSystemReachabilityRewards(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, std::vector* oneStepTargetProbabilities = nullptr) { // Remove rows and columns from the original transition probability matrix for states whose reward values are already known. // If there are infinity states, we additionally have to remove choices of maybeState that lead to infinity. if (qualitativeStateSets.infinityStates.empty()) { submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false); b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, qualitativeStateSets.maybeStates); if (oneStepTargetProbabilities) { - (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, targetStates); + (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.rewardZeroStates); } } else { submatrix = transitionMatrix.getSubmatrix(false, *selectedChoices, qualitativeStateSets.maybeStates, false); b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true)); storm::utility::vector::filterVectorInPlace(b, *selectedChoices); if (oneStepTargetProbabilities) { - (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowSumVector(*selectedChoices, targetStates); + (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowSumVector(*selectedChoices, qualitativeStateSets.rewardZeroStates); } } @@ -972,7 +1103,7 @@ namespace storm { } template - boost::optional> computeFixedPointSystemReachabilityRewardsEliminateEndComponents(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, storm::storage::BitVector const& targetStates, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, boost::optional>& oneStepTargetProbabilities) { + boost::optional> computeFixedPointSystemReachabilityRewardsEliminateEndComponents(storm::solver::SolveGoal& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional const& selectedChoices, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::SparseMatrix& submatrix, std::vector& b, boost::optional>& oneStepTargetProbabilities) { // Start by computing the choices with reward 0, as we only want ECs within this fragment. storm::storage::BitVector zeroRewardChoices(transitionMatrix.getRowCount()); @@ -1019,7 +1150,7 @@ namespace storm { // Only do more work if there are actually end-components. if (doDecomposition && !endComponentDecomposition.empty()) { STORM_LOG_DEBUG("Eliminating " << endComponentDecomposition.size() << " ECs."); - SparseMdpEndComponentInformation result = SparseMdpEndComponentInformation::eliminateEndComponents(endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, oneStepTargetProbabilities ? &targetStates : nullptr, selectedChoices ? &selectedChoices.get() : nullptr, &rewardVector, submatrix, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr, &b); + SparseMdpEndComponentInformation result = SparseMdpEndComponentInformation::eliminateEndComponents(endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, oneStepTargetProbabilities ? &qualitativeStateSets.rewardZeroStates : nullptr, selectedChoices ? &selectedChoices.get() : nullptr, &rewardVector, submatrix, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr, &b); // If the solve goal has relevant values, we need to adjust them. if (goal.hasRelevantValues()) { @@ -1037,7 +1168,7 @@ namespace storm { return result; } else { STORM_LOG_DEBUG("Not eliminating ECs as there are none."); - computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, targetStates, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); + computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); return boost::none; } } @@ -1056,15 +1187,15 @@ namespace storm { } template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint) { // Prepare resulting vector. std::vector result(transitionMatrix.getRowGroupCount(), storm::utility::zero()); // Determine which states have a reward that is infinity or less than infinity. - QualitativeStateSetsReachabilityRewards qualitativeStateSets = getQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates, hint); + QualitativeStateSetsReachabilityRewards qualitativeStateSets = getQualitativeStateSetsReachabilityRewards(goal, transitionMatrix, backwardTransitions, targetStates, hint, zeroRewardStatesGetter, zeroRewardChoicesGetter); - STORM_LOG_INFO("Preprocessing: " << qualitativeStateSets.infinityStates.getNumberOfSetBits() << " states with reward infinity, " << targetStates.getNumberOfSetBits() << " target states (" << qualitativeStateSets.maybeStates.getNumberOfSetBits() << " states remaining)."); + STORM_LOG_INFO("Preprocessing: " << qualitativeStateSets.infinityStates.getNumberOfSetBits() << " states with reward infinity, " << qualitativeStateSets.rewardZeroStates.getNumberOfSetBits() << " states with reward zero (" << qualitativeStateSets.maybeStates.getNumberOfSetBits() << " states remaining)."); storm::utility::vector::setVectorValues(result, qualitativeStateSets.infinityStates, storm::utility::infinity()); @@ -1091,7 +1222,7 @@ namespace storm { } // Obtain proper hint information either from the provided hint or from requirements of the solver. - SparseMdpHintType hintInformation = computeHints(env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~targetStates, targetStates, minMaxLinearEquationSolverFactory, selectedChoices); + SparseMdpHintType hintInformation = computeHints(env, SolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~qualitativeStateSets.rewardZeroStates, qualitativeStateSets.rewardZeroStates, selectedChoices); // Declare the components of the equation system we will solve. storm::storage::SparseMatrix submatrix; @@ -1107,13 +1238,13 @@ namespace storm { // If the hint information tells us that we have to eliminate MECs, we do so now. boost::optional> ecInformation; if (hintInformation.getEliminateEndComponents()) { - ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents(goal, transitionMatrix, backwardTransitions, qualitativeStateSets, targetStates, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities); + ecInformation = computeFixedPointSystemReachabilityRewardsEliminateEndComponents(goal, transitionMatrix, backwardTransitions, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities); // Make sure we are not supposed to produce a scheduler if we actually eliminate end components. STORM_LOG_THROW(!ecInformation || !ecInformation.get().getEliminatedEndComponents() || !produceScheduler, storm::exceptions::NotSupportedException, "Producing schedulers is not supported if end-components need to be eliminated for the solver."); } else { // Otherwise, we compute the standard equations. - computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, targetStates, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); + computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr); } // If we need to compute upper bounds, do so now. @@ -1123,7 +1254,7 @@ namespace storm { } // Now compute the results for the maybe states. - MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, minMaxLinearEquationSolverFactory, hintInformation); + MaybeStateResult resultForMaybeStates = computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation); // If we eliminated end components, we need to extract the result differently. if (ecInformation && ecInformation.get().getEliminatedEndComponents()) { @@ -1141,7 +1272,7 @@ namespace storm { // Extend scheduler with choices for the states in the qualitative state sets. if (produceScheduler) { - extendScheduler(*scheduler, goal, qualitativeStateSets, transitionMatrix, targetStates); + extendScheduler(*scheduler, goal, qualitativeStateSets, transitionMatrix, backwardTransitions, targetStates, zeroRewardChoicesGetter); } // Sanity check for created scheduler. @@ -1151,7 +1282,7 @@ namespace storm { } template - std::vector SparseMdpPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates) { // If there are no goal states, we avoid the computation and directly return zero. if (psiStates.empty()) { @@ -1168,12 +1299,12 @@ namespace storm { std::vector stateRewards(psiStates.size(), storm::utility::zero()); storm::utility::vector::setVectorValues(stateRewards, psiStates, storm::utility::one()); storm::models::sparse::StandardRewardModel rewardModel(std::move(stateRewards)); - return computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, minMaxLinearEquationSolverFactory); + return computeLongRunAverageRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel); } template template - std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel) { uint64_t numberOfStates = transitionMatrix.getRowGroupCount(); @@ -1192,7 +1323,7 @@ namespace storm { for (uint_fast64_t currentMecIndex = 0; currentMecIndex < mecDecomposition.size(); ++currentMecIndex) { storm::storage::MaximalEndComponent const& mec = mecDecomposition[currentMecIndex]; - lraValuesForEndComponents[currentMecIndex] = computeLraForMaximalEndComponent(env, goal.direction(), transitionMatrix, rewardModel, mec, minMaxLinearEquationSolverFactory); + lraValuesForEndComponents[currentMecIndex] = computeLraForMaximalEndComponent(env, goal.direction(), transitionMatrix, rewardModel, mec); // Gather information for later use. for (auto const& stateChoicesPair : mec) { @@ -1244,7 +1375,7 @@ namespace storm { // Now insert all (cumulative) probability values that target an MEC. for (uint_fast64_t mecIndex = 0; mecIndex < auxiliaryStateToProbabilityMap.size(); ++mecIndex) { - if (auxiliaryStateToProbabilityMap[mecIndex] != 0) { + if (!storm::utility::isZero(auxiliaryStateToProbabilityMap[mecIndex])) { sspMatrixBuilder.addNextValue(currentChoice, firstAuxiliaryStateIndex + mecIndex, auxiliaryStateToProbabilityMap[mecIndex]); } } @@ -1279,7 +1410,7 @@ namespace storm { // Now insert all (cumulative) probability values that target an MEC. for (uint_fast64_t targetMecIndex = 0; targetMecIndex < auxiliaryStateToProbabilityMap.size(); ++targetMecIndex) { - if (auxiliaryStateToProbabilityMap[targetMecIndex] != 0) { + if (!storm::utility::isZero(auxiliaryStateToProbabilityMap[targetMecIndex])) { sspMatrixBuilder.addNextValue(currentChoice, firstAuxiliaryStateIndex + targetMecIndex, auxiliaryStateToProbabilityMap[targetMecIndex]); } } @@ -1298,9 +1429,11 @@ namespace storm { storm::storage::SparseMatrix sspMatrix = sspMatrixBuilder.build(currentChoice, numberOfSspStates, numberOfSspStates); // Check for requirements of the solver. - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction(), true); + storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction()); requirements.clearBounds(); - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); + std::vector sspResult(numberOfSspStates); goal.restrictRelevantValues(statesNotContainedInAnyMec); @@ -1327,7 +1460,7 @@ namespace storm { template template - ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // If the mec only consists of a single state, we compute the LRA value directly if (++mec.begin() == mec.end()) { @@ -1349,7 +1482,7 @@ namespace storm { if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMaximalEndComponentLP(env, dir, transitionMatrix, rewardModel, mec); } else if (method == storm::solver::LraMethod::ValueIteration) { - return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, rewardModel, mec, minMaxLinearEquationSolverFactory); + return computeLraForMaximalEndComponentVI(env, dir, transitionMatrix, rewardModel, mec); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } @@ -1357,7 +1490,7 @@ namespace storm { template template - ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + ValueType SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec) { // Initialize data about the mec storm::storage::BitVector mecStates(transitionMatrix.getRowGroupCount(), false); @@ -1421,12 +1554,11 @@ namespace storm { std::vector x(mecTransitions.getRowGroupCount(), storm::utility::zero()); std::vector xPrime = x; - auto solver = minMaxLinearEquationSolverFactory.create(env, std::move(mecTransitions)); - solver->setCachingEnabled(true); + auto multiplier = storm::solver::MultiplierFactory().create(env, mecTransitions); ValueType maxDiff, minDiff; while (true) { // Compute the obtained rewards for the next step - solver->repeatedMultiply(env, dir, x, &choiceRewards, 1); + multiplier->multiplyAndReduce(env, dir, x, &choiceRewards, x); // update xPrime and check for convergence // to avoid large (and numerically unstable) x-values, we substract a reference value. @@ -1495,7 +1627,7 @@ namespace storm { } template - std::unique_ptr SparseMdpPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + std::unique_ptr SparseMdpPrctlHelper::computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates) { std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now(); @@ -1531,7 +1663,7 @@ namespace storm { STORM_LOG_DEBUG("Computing probabilities to satisfy condition."); std::chrono::high_resolution_clock::time_point conditionStart = std::chrono::high_resolution_clock::now(); - std::vector conditionProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, extendedConditionStates, false, false, minMaxLinearEquationSolverFactory).values); + std::vector conditionProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, extendedConditionStates, false, false).values); std::chrono::high_resolution_clock::time_point conditionEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Computed probabilities to satisfy for condition in " << std::chrono::duration_cast(conditionEnd - conditionStart).count() << "ms."); @@ -1542,7 +1674,7 @@ namespace storm { STORM_LOG_DEBUG("Computing probabilities to reach target."); std::chrono::high_resolution_clock::time_point targetStart = std::chrono::high_resolution_clock::now(); - std::vector targetProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, fixedTargetStates, false, false, minMaxLinearEquationSolverFactory).values); + std::vector targetProbabilities = std::move(computeUntilProbabilities(env, OptimizationDirection::Maximize, transitionMatrix, backwardTransitions, allStates, fixedTargetStates, false, false).values); std::chrono::high_resolution_clock::time_point targetEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Computed probabilities to reach target in " << std::chrono::duration_cast(targetEnd - targetStart).count() << "ms."); @@ -1634,7 +1766,7 @@ namespace storm { } std::chrono::high_resolution_clock::time_point conditionalStart = std::chrono::high_resolution_clock::now(); - std::vector goalProbabilities = std::move(computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newBackwardTransitions, storm::storage::BitVector(newFailState + 1, true), newGoalStates, false, false, minMaxLinearEquationSolverFactory).values); + std::vector goalProbabilities = std::move(computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newBackwardTransitions, storm::storage::BitVector(newFailState + 1, true), newGoalStates, false, false).values); std::chrono::high_resolution_clock::time_point conditionalEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Computed conditional probabilities in transformed model in " << std::chrono::duration_cast(conditionalEnd - conditionalStart).count() << "ms."); @@ -1642,24 +1774,25 @@ namespace storm { } template class SparseMdpPrctlHelper; - template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint); - template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template double SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); + template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel); + template double SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); + template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template double SparseMdpPrctlHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); #ifdef STORM_HAVE_CARL template class SparseMdpPrctlHelper; - template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint); - template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + template std::vector SparseMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepCount); + template std::vector SparseMdpPrctlHelper::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, uint_fast64_t stepBound); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint); + template std::vector SparseMdpPrctlHelper::computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& rewardModel); + template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); + template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); template storm::RationalNumber SparseMdpPrctlHelper::computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::models::sparse::StandardRewardModel const& rewardModel, storm::storage::MaximalEndComponent const& mec); - #endif } } diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index b06b14192..0be4ad060 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -39,44 +39,49 @@ namespace storm { class SparseMdpPrctlHelper { public: - static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static std::vector computeStepBoundedUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::map computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::map computeRewardBoundedValues(Environment const& env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding& rewardUnfolding, storm::storage::BitVector const& initialStates); - static std::vector computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates); - static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); - static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, bool useMecBasedTechnique = false); + static std::vector computeGloballyProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, bool useMecBasedTechnique = false); template - static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepCount); template - static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); template - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeTotalRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + + template + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); + + static MDPSparseModelCheckingHelperReturnType computeReachabilityTimes(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint = ModelCheckerHint()); #ifdef STORM_HAVE_CARL - static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::models::sparse::StandardRewardModel const& intervalRewardModel, bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative); #endif - static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates); template - static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::vector computeLongRunAverageRewards(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, RewardModelType const& rewardModel); - static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static std::unique_ptr computeConditionalProbabilities(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& targetStates, storm::storage::BitVector const& conditionStates); private: - static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint()); + static MDPSparseModelCheckingHelperReturnType computeReachabilityRewardsHelper(Environment const& env, storm::solver::SolveGoal&& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, std::function(uint_fast64_t, storm::storage::SparseMatrix const&, storm::storage::BitVector const&)> const& totalStateRewardVectorGetter, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, std::function const& zeroRewardStatesGetter, std::function const& zeroRewardChoicesGetter, ModelCheckerHint const& hint = ModelCheckerHint()); template - static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponent(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template - static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec, storm::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static ValueType computeLraForMaximalEndComponentVI(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); template static ValueType computeLraForMaximalEndComponentLP(Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, RewardModelType const& rewardModel, storm::storage::MaximalEndComponent const& mec); diff --git a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp index 9993640bc..8f2468a70 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.cpp @@ -19,7 +19,7 @@ namespace storm { namespace helper { template - storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. STORM_LOG_TRACE("Found " << phiStates.getNonZeroCount() << " phi states and " << psiStates.getNonZeroCount() << " psi states."); @@ -35,7 +35,7 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeUntilProbabilities(env, model, transitionMatrix, maybeStates, statesWithProbability01.second, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeUntilProbabilities(env, model, transitionMatrix, maybeStates, statesWithProbability01.second, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return statesWithProbability01.second.template toAdd(); } @@ -43,7 +43,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -60,6 +60,7 @@ namespace storm { // Finally cut away all columns targeting non-maybe states and convert the matrix into the matrix needed // for solving the equation system (i.e. compute (I-A)). submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem) { submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix; } @@ -73,8 +74,8 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { - storm::dd::Add result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + storm::dd::Add SymbolicDtmcPrctlHelper::computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + storm::dd::Add result = computeUntilProbabilities(env, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result = result.getDdManager().template getAddOne() - result; return result; } @@ -86,7 +87,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0 = storm::utility::graph::performProbGreater0(model, transitionMatrix.notZero(), phiStates, psiStates, stepBound); @@ -110,6 +111,7 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(env, submatrix, maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(model.getManager().template getAddZero(), &subvector, stepBound); @@ -120,7 +122,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -128,22 +130,24 @@ namespace storm { storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(env, transitionMatrix, model.getReachableStates(), model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); return solver->multiply(model.getManager().template getAddZero(), &totalRewardVector, stepBound); } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(env, transitionMatrix, model.getReachableStates(), model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs()); return solver->multiply(rewardModel.getStateRewardVector(), nullptr, stepBound); } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -162,7 +166,7 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, maybeStates, targetStates, infinityStates, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, maybeStates, targetStates, infinityStates, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return infinityStates.ite(model.getManager().getConstant(storm::utility::infinity()), model.getManager().getConstant(storm::utility::zero())); } @@ -170,7 +174,7 @@ namespace storm { } template - storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -185,6 +189,7 @@ namespace storm { // Finally cut away all columns targeting non-maybe states and convert the matrix into the matrix needed // for solving the equation system (i.e. compute (I-A)). submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); + storm::solver::GeneralSymbolicLinearEquationSolverFactory linearEquationSolverFactory; if (linearEquationSolverFactory.getEquationProblemFormat(env) == storm::solver::LinearEquationSolverProblemFormat::EquationSystem) { submatrix = (model.getRowColumnIdentity() * maybeStatesAdd) - submatrix; } @@ -197,6 +202,12 @@ namespace storm { return infinityStates.ite(model.getManager().getConstant(storm::utility::infinity()), result); } + template + storm::dd::Add SymbolicDtmcPrctlHelper::computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, model, transitionMatrix, rewardModel, targetStates, qualitative, startValues); + } + template class SymbolicDtmcPrctlHelper; template class SymbolicDtmcPrctlHelper; diff --git a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h index dc6307db1..ecf6a6fe4 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SymbolicDtmcPrctlHelper.h @@ -20,23 +20,25 @@ namespace storm { public: typedef typename storm::models::symbolic::Model::RewardModelType RewardModelType; - static storm::dd::Add computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeBoundedUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static storm::dd::Add computeNextProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues = boost::none); - static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeUntilProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues = boost::none); - static storm::dd::Add computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeGloballyProbabilities(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static storm::dd::Add computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeCumulativeRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static storm::dd::Add computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory); + static storm::dd::Add computeInstantaneousRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues = boost::none); - static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::SymbolicLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static storm::dd::Add computeReachabilityRewards(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues = boost::none); + + static storm::dd::Add computeReachabilityTimes(Environment const& env, storm::models::symbolic::Model const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, bool qualitative, boost::optional> const& startValues = boost::none); }; } diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp index 523ba2711..5080d90a8 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp @@ -45,7 +45,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -65,6 +65,7 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Now solve the resulting equation system. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); if (storm::solver::minimize(dir)) { @@ -74,20 +75,20 @@ namespace storm { // Check requirements of solver. storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(env, dir); boost::optional> initialScheduler; - if (!requirements.empty()) { - if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) { + if (requirements.hasEnabledRequirement()) { + if (requirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); initialScheduler = computeValidSchedulerHint(EquationSystemType::UntilProbabilities, model, transitionMatrix, maybeStates, statesWithProbability1); requirements.clearValidInitialScheduler(); } requirements.clearBounds(); - if (requirements.requiresNoEndComponents()) { + if (requirements.noEndComponents()) { // Check whether there are end components if (storm::utility::graph::performProb0E(model, transitionMatrix.notZero(), maybeStates, !maybeStates && model.getReachableStates()).isZero()) { requirements.clearNoEndComponents(); } } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Could not establish requirements of solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); } if (initialScheduler) { solver->setInitialScheduler(initialScheduler.get()); @@ -101,7 +102,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 and 1 of satisfying the until-formula. std::pair, storm::dd::Bdd> statesWithProbability01; @@ -121,7 +122,7 @@ namespace storm { } else { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeUntilProbabilities(env, dir, model, transitionMatrix, maybeStates, statesWithProbability01.second, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeUntilProbabilities(env, dir, model, transitionMatrix, maybeStates, statesWithProbability01.second, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return std::unique_ptr(new storm::modelchecker::SymbolicQuantitativeCheckResult(model.getReachableStates(), statesWithProbability01.second.template toAdd())); } @@ -129,8 +130,8 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { - std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Minimize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative, linearEquationSolverFactory); + std::unique_ptr SymbolicMdpPrctlHelper::computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative) { + std::unique_ptr result = computeUntilProbabilities(env, dir == OptimizationDirection::Minimize ? OptimizationDirection::Maximize : OptimizationDirection::Minimize, model, transitionMatrix, model.getReachableStates(), !psiStates && model.getReachableStates(), qualitative); result->asQuantitativeCheckResult().oneMinus(); return result; } @@ -147,7 +148,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr SymbolicMdpPrctlHelper::computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound) { // We need to identify the states which have to be taken out of the matrix, i.e. all states that have // probability 0 or 1 of satisfying the until-formula. storm::dd::Bdd statesWithProbabilityGreater0; @@ -174,7 +175,8 @@ namespace storm { // Finally cut away all columns targeting non-maybe states. submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); - + + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(dir, model.getManager().template getAddZero(), &subvector, stepBound); @@ -185,11 +187,12 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr SymbolicMdpPrctlHelper::computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(transitionMatrix, model.getReachableStates(), model.getIllegalMask(), model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(dir, rewardModel.getStateRewardVector(), nullptr, stepBound); @@ -197,7 +200,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory) { + std::unique_ptr SymbolicMdpPrctlHelper::computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound) { // Only compute the result if the model has at least one reward this->getModel(). STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -205,6 +208,7 @@ namespace storm { storm::dd::Add totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix, model.getColumnVariables()); // Perform the matrix-vector multiplication. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(model.getTransitionMatrix(), model.getReachableStates(), model.getIllegalMask(), model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); storm::dd::Add result = solver->multiply(dir, model.getManager().template getAddZero(), &totalRewardVector, stepBound); @@ -212,7 +216,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues) { // Create the matrix and the vector for the equation system. storm::dd::Add maybeStatesAdd = maybeStates.template toAdd(); @@ -232,6 +236,7 @@ namespace storm { submatrix *= maybeStatesAdd.swapVariables(model.getRowColumnMetaVariablePairs()); // Now solve the resulting equation system. + storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory linearEquationSolverFactory; std::unique_ptr> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs()); if (storm::solver::maximize(dir)) { @@ -241,20 +246,20 @@ namespace storm { // Check requirements of solver. storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(env, dir); boost::optional> initialScheduler; - if (!requirements.empty()) { - if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) { + if (requirements.hasEnabledRequirement()) { + if (requirements.validInitialScheduler()) { STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it."); initialScheduler = computeValidSchedulerHint(EquationSystemType::ExpectedRewards, model, transitionMatrix, maybeStates, targetStates); requirements.clearValidInitialScheduler(); } requirements.clearLowerBounds(); - if (requirements.requiresNoEndComponents()) { + if (requirements.noEndComponents()) { // Check whether there are end components if (storm::utility::graph::performProb0E(model, transitionMatrixBdd, maybeStates, !maybeStates && model.getReachableStates()).isZero()) { requirements.clearNoEndComponents(); } } - STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Could not establish requirements of solver."); + STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); } if (initialScheduler) { solver->setInitialScheduler(initialScheduler.get()); @@ -268,7 +273,7 @@ namespace storm { } template - std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues) { + std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, boost::optional> const& startValues) { // Only compute the result if there is at least one reward model. STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula."); @@ -289,12 +294,19 @@ namespace storm { // If there are maybe states, we need to solve an equation system. if (!maybeStates.isZero()) { - return computeReachabilityRewards(env, dir, model, transitionMatrix, transitionMatrixBdd, rewardModel, maybeStates, targetStates, infinityStates, linearEquationSolverFactory, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); + return computeReachabilityRewards(env, dir, model, transitionMatrix, transitionMatrixBdd, rewardModel, maybeStates, targetStates, infinityStates, startValues ? maybeStates.ite(startValues.get(), model.getManager().template getAddZero()) : model.getManager().template getAddZero()); } else { return std::unique_ptr(new storm::modelchecker::SymbolicQuantitativeCheckResult(model.getReachableStates(), infinityStates.ite(model.getManager().getConstant(storm::utility::infinity()), model.getManager().template getAddZero()))); } } + template + std::unique_ptr SymbolicMdpPrctlHelper::computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, boost::optional> const& startValues) { + RewardModelType rewardModel(model.getManager().getConstant(storm::utility::one()), boost::none, boost::none); + return computeReachabilityRewards(env, dir, model, transitionMatrix, rewardModel, targetStates, startValues); + } + + template class SymbolicMdpPrctlHelper; template class SymbolicMdpPrctlHelper; diff --git a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h index c8737299c..51f5f7dd1 100644 --- a/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h +++ b/src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.h @@ -24,23 +24,25 @@ namespace storm { public: typedef typename storm::models::symbolic::NondeterministicModel::RewardModelType RewardModelType; - static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeBoundedUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, uint_fast64_t stepBound); static std::unique_ptr computeNextProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& nextStates); - static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& phiStates, storm::dd::Bdd const& psiStates, bool qualitative, boost::optional> const& startValues = boost::none); - static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeUntilProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& statesWithProbability1, boost::optional> const& startValues = boost::none); - static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeGloballyProbabilities(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& psiStates, bool qualitative); - static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeCumulativeRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory); + static std::unique_ptr computeInstantaneousRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, uint_fast64_t stepBound); - static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, RewardModelType const& rewardModel, storm::dd::Bdd const& targetStates, boost::optional> const& startValues = boost::none); - static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, storm::solver::GeneralSymbolicMinMaxLinearEquationSolverFactory const& linearEquationSolverFactory, boost::optional> const& startValues = boost::none); + static std::unique_ptr computeReachabilityRewards(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& transitionMatrixBdd, RewardModelType const& rewardModel, storm::dd::Bdd const& maybeStates, storm::dd::Bdd const& targetStates, storm::dd::Bdd const& infinityStates, boost::optional> const& startValues = boost::none); + + static std::unique_ptr computeReachabilityTimes(Environment const& env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel const& model, storm::dd::Add const& transitionMatrix, storm::dd::Bdd const& targetStates, boost::optional> const& startValues = boost::none); }; } diff --git a/src/storm/modelchecker/results/CheckResult.cpp b/src/storm/modelchecker/results/CheckResult.cpp index 9155057d3..26eb24946 100644 --- a/src/storm/modelchecker/results/CheckResult.cpp +++ b/src/storm/modelchecker/results/CheckResult.cpp @@ -162,6 +162,10 @@ namespace storm { SymbolicParetoCurveCheckResult const& CheckResult::asSymbolicParetoCurveCheckResult() const { return dynamic_cast const&>(*this); } + + bool CheckResult::hasScheduler() const { + return false; + } // Explicitly instantiate the template functions. template QuantitativeCheckResult& CheckResult::asQuantitativeCheckResult(); diff --git a/src/storm/modelchecker/results/CheckResult.h b/src/storm/modelchecker/results/CheckResult.h index 4edd2cb19..740a8269d 100644 --- a/src/storm/modelchecker/results/CheckResult.h +++ b/src/storm/modelchecker/results/CheckResult.h @@ -111,7 +111,9 @@ namespace storm { template SymbolicParetoCurveCheckResult const& asSymbolicParetoCurveCheckResult() const; - + + virtual bool hasScheduler() const; + virtual std::ostream& writeToStream(std::ostream& out) const = 0; }; diff --git a/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h b/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h index 131cf0cea..57be3266f 100644 --- a/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h +++ b/src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h @@ -65,7 +65,7 @@ namespace storm { virtual ValueType average() const override; virtual ValueType sum() const override; - bool hasScheduler() const; + virtual bool hasScheduler() const override; void setScheduler(std::unique_ptr>&& scheduler); storm::storage::Scheduler const& getScheduler() const; storm::storage::Scheduler& getScheduler(); diff --git a/src/storm/models/Model.h b/src/storm/models/Model.h index 4f17fdf24..52dfec2b6 100644 --- a/src/storm/models/Model.h +++ b/src/storm/models/Model.h @@ -16,6 +16,7 @@ namespace storm { Model(ModelType const& modelType) : ModelBase(modelType) { // Intentionally left empty. } + }; diff --git a/src/storm/models/ModelBase.h b/src/storm/models/ModelBase.h index 49f96d5ed..77fa5b60d 100644 --- a/src/storm/models/ModelBase.h +++ b/src/storm/models/ModelBase.h @@ -48,7 +48,7 @@ namespace storm { std::shared_ptr as() const { return std::dynamic_pointer_cast(this->shared_from_this()); } - + /*! * @brief Return the actual type of the model. * diff --git a/src/storm/models/sparse/MarkovAutomaton.cpp b/src/storm/models/sparse/MarkovAutomaton.cpp index 9c077e2c4..dad398ea6 100644 --- a/src/storm/models/sparse/MarkovAutomaton.cpp +++ b/src/storm/models/sparse/MarkovAutomaton.cpp @@ -7,6 +7,8 @@ #include "storm/utility/constants.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" +#include "storm/utility/graph.h" +#include "storm/transformer/SubsystemBuilder.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -117,20 +119,11 @@ namespace storm { exitRates[state] = storm::utility::zero(); } } - // Remove the Markovian choices for the different model ingredients - this->getTransitionMatrix() = this->getTransitionMatrix().restrictRows(keptChoices); - for(auto& rewModel : this->getRewardModels()) { - if(rewModel.second.hasStateActionRewards()) { - storm::utility::vector::filterVectorInPlace(rewModel.second.getStateActionRewardVector(), keptChoices); - } - if(rewModel.second.hasTransitionRewards()) { - rewModel.second.getTransitionRewardMatrix() = rewModel.second.getTransitionRewardMatrix().restrictRows(keptChoices); - } - } - if(this->hasChoiceLabeling()) { - this->getOptionalChoiceLabeling() = this->getChoiceLabeling().getSubLabeling(keptChoices); + + if (!keptChoices.full()) { + *this = std::move(*storm::transformer::buildSubsystem(*this, storm::storage::BitVector(this->getNumberOfStates(), true), keptChoices, false).model->template as>()); } - + // Mark the automaton as closed. closed = true; } @@ -171,7 +164,7 @@ namespace storm { template bool MarkovAutomaton::isConvertibleToCtmc() const { - return markovianStates.full(); + return isClosed() && markovianStates.full(); } template @@ -181,7 +174,7 @@ namespace storm { // Get number of choices in current state uint_fast64_t numberChoices = this->getTransitionMatrix().getRowGroupIndices()[state + 1] - this->getTransitionMatrix().getRowGroupIndices()[state]; if (isMarkovianState(state)) { - STORM_LOG_ASSERT(numberChoices == 1, "Wrong number of choices for markovian state."); + STORM_LOG_ASSERT(numberChoices == 1, "Wrong number of choices for Markovian state."); } if (numberChoices > 1) { STORM_LOG_ASSERT(isProbabilisticState(state), "State is not probabilistic."); @@ -203,6 +196,21 @@ namespace storm { template std::shared_ptr> MarkovAutomaton::convertToCtmc() const { + if (isClosed() && markovianStates.full()) { + storm::storage::sparse::ModelComponents components(this->getTransitionMatrix(), this->getStateLabeling(), this->getRewardModels(), false); + components.transitionMatrix.makeRowGroupingTrivial(); + components.exitRates = this->getExitRates(); + if (this->hasChoiceLabeling()) { + components.choiceLabeling = this->getChoiceLabeling(); + } + if (this->hasStateValuations()) { + components.stateValuations = this->getStateValuations(); + } + if (this->hasChoiceOrigins()) { + components.choiceOrigins = this->getChoiceOrigins(); + } + return std::make_shared>(std::move(components)); + } STORM_LOG_TRACE("MA matrix:" << std::endl << this->getTransitionMatrix()); STORM_LOG_TRACE("Markovian states: " << getMarkovianStates()); @@ -211,7 +219,7 @@ namespace storm { storm::storage::FlexibleSparseMatrix flexibleMatrix(this->getTransitionMatrix()); storm::storage::FlexibleSparseMatrix flexibleBackwardTransitions(this->getTransitionMatrix().transpose()); storm::solver::stateelimination::StateEliminator stateEliminator(flexibleMatrix, flexibleBackwardTransitions); - + for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) { STORM_LOG_ASSERT(!this->isHybridState(state), "State is hybrid."); if (this->isProbabilisticState(state)) { @@ -220,7 +228,7 @@ namespace storm { STORM_LOG_TRACE("Flexible matrix after eliminating state " << state << ":" << std::endl << flexibleMatrix); } } - + // Create the rate matrix for the CTMC storm::storage::SparseMatrixBuilder transitionMatrixBuilder(0, 0, 0, false, false); // Remember state to keep @@ -230,7 +238,7 @@ namespace storm { // State is eliminated and can be discarded keepStates.set(state, false); } else { - STORM_LOG_ASSERT(this->isMarkovianState(state), "State is not markovian."); + STORM_LOG_ASSERT(this->isMarkovianState(state), "State is not Markovian."); // Copy transitions for (uint_fast64_t row = flexibleMatrix.getRowGroupIndices()[state]; row < flexibleMatrix.getRowGroupIndices()[state + 1]; ++row) { for (auto const& entry : flexibleMatrix.getRow(row)) { @@ -240,21 +248,19 @@ namespace storm { } } } - + storm::storage::SparseMatrix rateMatrix = transitionMatrixBuilder.build(); rateMatrix = rateMatrix.getSubmatrix(false, keepStates, keepStates, false); STORM_LOG_TRACE("New CTMC matrix:" << std::endl << rateMatrix); // Construct CTMC storm::models::sparse::StateLabeling stateLabeling = this->getStateLabeling().getSubLabeling(keepStates); - + //TODO update reward models and choice labels according to kept states STORM_LOG_WARN_COND(this->getRewardModels().empty(), "Conversion of MA to CTMC does not preserve rewards."); - std::unordered_map rewardModels = this->getRewardModels(); STORM_LOG_WARN_COND(!this->hasChoiceLabeling(), "Conversion of MA to CTMC does not preserve choice labels."); STORM_LOG_WARN_COND(!this->hasStateValuations(), "Conversion of MA to CTMC does not preserve choice labels."); STORM_LOG_WARN_COND(!this->hasChoiceOrigins(), "Conversion of MA to CTMC does not preserve choice labels."); - - return std::make_shared>(std::move(rateMatrix), std::move(stateLabeling), std::move(rewardModels)); + return std::make_shared>(std::move(rateMatrix), std::move(stateLabeling)); } diff --git a/src/storm/models/sparse/Model.cpp b/src/storm/models/sparse/Model.cpp index 0cb7ec8cc..7393ad698 100644 --- a/src/storm/models/sparse/Model.cpp +++ b/src/storm/models/sparse/Model.cpp @@ -74,9 +74,9 @@ namespace storm { STORM_LOG_THROW(!components.exitRates.is_initialized() || components.exitRates->size() == stateCount, storm::exceptions::IllegalArgumentException, "Size of exit rate vector does not match state count."); STORM_LOG_THROW(this->isOfType(ModelType::Ctmc) || components.markovianStates.is_initialized(), storm::exceptions::IllegalArgumentException, "Can not create Markov Automaton: no Markovian states given."); } else { - STORM_LOG_ERROR_COND(!components.rateTransitions && !components.exitRates.is_initialized(), "Rates specified for discrete-time model. The rates will be ignored."); + STORM_LOG_WARN_COND(!components.rateTransitions && !components.exitRates.is_initialized(), "Rates specified for discrete-time model. The rates will be ignored."); } - STORM_LOG_ERROR_COND(this->isOfType(ModelType::MarkovAutomaton) || !components.markovianStates.is_initialized(), "Markovian states given for a model that is not a Markov automaton (will be ignored)."); + STORM_LOG_WARN_COND(this->isOfType(ModelType::MarkovAutomaton) || !components.markovianStates.is_initialized(), "Markovian states given for a model that is not a Markov automaton (will be ignored)."); } template @@ -423,11 +423,7 @@ namespace storm { template bool Model::supportsParameters() const { -#ifdef STORM_HAVE_CARL return std::is_same::value; -#else - return false; -#endif } template diff --git a/src/storm/models/sparse/NondeterministicModel.cpp b/src/storm/models/sparse/NondeterministicModel.cpp index 263f67c16..08331c6f5 100644 --- a/src/storm/models/sparse/NondeterministicModel.cpp +++ b/src/storm/models/sparse/NondeterministicModel.cpp @@ -45,7 +45,7 @@ namespace storm { } template - std::shared_ptr> NondeterministicModel::applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates) { + std::shared_ptr> NondeterministicModel::applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates) const { storm::storage::SparseModelMemoryProduct memoryProduct(*this, scheduler); if (!dropUnreachableStates) { memoryProduct.setBuildFullProduct(); diff --git a/src/storm/models/sparse/NondeterministicModel.h b/src/storm/models/sparse/NondeterministicModel.h index ac8603e7f..5280ba962 100644 --- a/src/storm/models/sparse/NondeterministicModel.h +++ b/src/storm/models/sparse/NondeterministicModel.h @@ -57,7 +57,7 @@ namespace storm { * @param scheduler the considered scheduler. * @param dropUnreachableStates if set, the resulting model only considers the states that are reachable from an initial state */ - std::shared_ptr> applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates = true); + std::shared_ptr> applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates = true) const; virtual void printModelInformationToStream(std::ostream& out) const override; diff --git a/src/storm/models/sparse/StandardRewardModel.cpp b/src/storm/models/sparse/StandardRewardModel.cpp index ccf9b5d71..e37de0562 100644 --- a/src/storm/models/sparse/StandardRewardModel.cpp +++ b/src/storm/models/sparse/StandardRewardModel.cpp @@ -270,11 +270,17 @@ namespace storm { template template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const { - storm::storage::BitVector result = this->hasStateRewards() ? storm::utility::vector::filterZero(this->getStateRewardVector()) : storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true); + return getStatesWithFilter(transitionMatrix, storm::utility::isZero); + } + + template + template + storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const { + storm::storage::BitVector result = this->hasStateRewards() ? storm::utility::vector::filter(this->getStateRewardVector(), filter) : storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true); if (this->hasStateActionRewards()) { for (uint_fast64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { for (uint_fast64_t row = transitionMatrix.getRowGroupIndices()[state]; row < transitionMatrix.getRowGroupIndices()[state+1]; ++row) { - if(!storm::utility::isZero(this->getStateActionRewardVector()[row])) { + if(!filter(this->getStateActionRewardVector()[row])) { result.set(state, false); break; } @@ -284,7 +290,7 @@ namespace storm { if (this->hasTransitionRewards()) { for (uint_fast64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { for (auto const& rewardMatrixEntry : this->getTransitionRewardMatrix().getRowGroup(state)) { - if(!storm::utility::isZero(rewardMatrixEntry.getValue())) { + if(!filter(rewardMatrixEntry.getValue())) { result.set(state, false); break; } @@ -293,19 +299,25 @@ namespace storm { } return result; } - + template template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const { + return getChoicesWithFilter(transitionMatrix, storm::utility::isZero); + } + + template + template + storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const { storm::storage::BitVector result; if (this->hasStateActionRewards()) { - result = storm::utility::vector::filterZero(this->getStateActionRewardVector()); + result = storm::utility::vector::filter(this->getStateActionRewardVector(), filter); if (this->hasStateRewards()) { - result &= transitionMatrix.getRowFilter(storm::utility::vector::filterZero(this->getStateRewardVector())); + result &= transitionMatrix.getRowFilter(storm::utility::vector::filter(this->getStateRewardVector(), filter)); } } else { if (this->hasStateRewards()) { - result = transitionMatrix.getRowFilter(storm::utility::vector::filterZero(this->getStateRewardVector())); + result = transitionMatrix.getRowFilter(storm::utility::vector::filter(this->getStateRewardVector(), filter)); } else { result = storm::storage::BitVector(transitionMatrix.getRowCount(), true); } @@ -313,7 +325,7 @@ namespace storm { if (this->hasTransitionRewards()) { for (uint_fast64_t row = 0; row < transitionMatrix.getRowCount(); ++row) { for (auto const& rewardMatrixEntry : this->getTransitionRewardMatrix().getRow(row)) { - if(!storm::utility::isZero(rewardMatrixEntry.getValue())) { + if(!filter(rewardMatrixEntry.getValue())) { result.set(row, false); break; } @@ -396,7 +408,9 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template double StandardRewardModel::getTotalStateActionReward(uint_fast64_t stateIndex, uint_fast64_t choiceIndex, storm::storage::SparseMatrix const& transitionMatrix, double const& stateRewardWeight, double const& actionRewardWeight) const; template void StandardRewardModel::reduceToStateBasedRewards(storm::storage::SparseMatrix const& transitionMatrix, bool reduceToStateRewards, std::vector const* weights); @@ -421,7 +435,9 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::RationalNumber StandardRewardModel::getTotalStateActionReward(uint_fast64_t stateIndex, uint_fast64_t choiceIndex, storm::storage::SparseMatrix const& transitionMatrix, storm::RationalNumber const& stateRewardWeight, storm::RationalNumber const& actionRewardWeight) const; template void StandardRewardModel::reduceToStateBasedRewards(storm::storage::SparseMatrix const& transitionMatrix, bool reduceToStateRewards, std::vector const* weights); template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, storm::RationalNumber const & newValue); @@ -433,7 +449,9 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix) const; template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template storm::storage::BitVector StandardRewardModel::getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template storm::storage::BitVector StandardRewardModel::getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; template storm::RationalFunction StandardRewardModel::getTotalStateActionReward(uint_fast64_t stateIndex, uint_fast64_t choiceIndex, storm::storage::SparseMatrix const& transitionMatrix, storm::RationalFunction const& stateRewardWeight, storm::RationalFunction const& actionRewardWeight) const; @@ -447,6 +465,8 @@ namespace storm { template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix) const; template std::vector StandardRewardModel::getTotalRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& weights) const; template std::vector StandardRewardModel::getTotalActionRewardVector(storm::storage::SparseMatrix const& transitionMatrix, std::vector const& stateRewardWeights) const; + template storm::storage::BitVector StandardRewardModel::getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; + template storm::storage::BitVector StandardRewardModel::getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, double const & newValue); template void StandardRewardModel::setStateActionReward(uint_fast64_t choiceIndex, storm::Interval const & newValue); template void StandardRewardModel::setStateReward(uint_fast64_t state, double const & newValue); diff --git a/src/storm/models/sparse/StandardRewardModel.h b/src/storm/models/sparse/StandardRewardModel.h index 33303f380..cdfce6038 100644 --- a/src/storm/models/sparse/StandardRewardModel.h +++ b/src/storm/models/sparse/StandardRewardModel.h @@ -253,6 +253,13 @@ namespace storm { template storm::storage::BitVector getStatesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; + /*! + * Returns the set of states for which all associated rewards (state, action or transition rewards) satisfy the given filter. + * @param transitionMatrix the transition matrix of the model (used to determine the actions and transitions that belong to a state) + */ + template + storm::storage::BitVector getStatesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; + /*! * Returns the set of choices at which all rewards (state-, action- and transition-rewards) are zero. * @@ -261,7 +268,14 @@ namespace storm { */ template storm::storage::BitVector getChoicesWithZeroReward(storm::storage::SparseMatrix const& transitionMatrix) const; - + + /*! + * Returns the set of choices for which all associated rewards (state, action or transition rewards) satisfy the given filter. + * @param transitionMatrix the transition matrix of the model (used to determine the actions and transitions that belong to a state) + */ + template + storm::storage::BitVector getChoicesWithFilter(storm::storage::SparseMatrix const& transitionMatrix, std::function const& filter) const; + /*! * Sets the given value in the state-action reward vector at the given row. This assumes that the reward * model has state-action rewards. diff --git a/src/storm/models/sparse/StateLabeling.cpp b/src/storm/models/sparse/StateLabeling.cpp index e80556108..bcb00b7a9 100644 --- a/src/storm/models/sparse/StateLabeling.cpp +++ b/src/storm/models/sparse/StateLabeling.cpp @@ -50,7 +50,7 @@ namespace storm { } void StateLabeling::addLabelToState(std::string const& label, storm::storage::sparse::state_type state) { - return ItemLabeling::addLabelToItem(label, state); + ItemLabeling::addLabelToItem(label, state); } bool StateLabeling::getStateHasLabel(std::string const& label, storm::storage::sparse::state_type state) const { diff --git a/src/storm/models/symbolic/Ctmc.cpp b/src/storm/models/symbolic/Ctmc.cpp index e94079efc..4b05372be 100644 --- a/src/storm/models/symbolic/Ctmc.cpp +++ b/src/storm/models/symbolic/Ctmc.cpp @@ -84,11 +84,29 @@ namespace storm { return exitRates.get(); } + template + template + std::shared_ptr> Ctmc::toValueType() const { + typedef typename DeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getExitRateVector().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class Ctmc; template class Ctmc; template class Ctmc; + template std::shared_ptr> Ctmc::toValueType() const; template class Ctmc; } // namespace symbolic diff --git a/src/storm/models/symbolic/Ctmc.h b/src/storm/models/symbolic/Ctmc.h index 68c4e7b35..0035e3ffb 100644 --- a/src/storm/models/symbolic/Ctmc.h +++ b/src/storm/models/symbolic/Ctmc.h @@ -141,6 +141,9 @@ namespace storm { */ storm::dd::Add const& getExitRateVector() const; + template + std::shared_ptr> toValueType() const; + private: mutable boost::optional> exitRates; }; diff --git a/src/storm/models/symbolic/Dtmc.cpp b/src/storm/models/symbolic/Dtmc.cpp index fdd478b71..2b4adb149 100644 --- a/src/storm/models/symbolic/Dtmc.cpp +++ b/src/storm/models/symbolic/Dtmc.cpp @@ -43,11 +43,29 @@ namespace storm { // Intentionally left empty. } + template + template + std::shared_ptr> Dtmc::toValueType() const { + typedef typename DeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class Dtmc; template class Dtmc; template class Dtmc; + template std::shared_ptr> Dtmc::toValueType() const; template class Dtmc; } // namespace symbolic diff --git a/src/storm/models/symbolic/Dtmc.h b/src/storm/models/symbolic/Dtmc.h index ebe837e1c..76a3e81ca 100644 --- a/src/storm/models/symbolic/Dtmc.h +++ b/src/storm/models/symbolic/Dtmc.h @@ -76,6 +76,10 @@ namespace storm { std::vector> const& rowColumnMetaVariablePairs, std::map> labelToBddMap = std::map>(), std::unordered_map const& rewardModels = std::unordered_map()); + + template + std::shared_ptr> toValueType() const; + }; } // namespace symbolic diff --git a/src/storm/models/symbolic/MarkovAutomaton.cpp b/src/storm/models/symbolic/MarkovAutomaton.cpp index 09b2fe7b3..111890edd 100644 --- a/src/storm/models/symbolic/MarkovAutomaton.cpp +++ b/src/storm/models/symbolic/MarkovAutomaton.cpp @@ -66,7 +66,7 @@ namespace storm { // Compute the vector of exit rates. this->exitRateVector = (this->getTransitionMatrix() * this->markovianMarker.template toAdd()).sumAbstract(columnAndNondeterminsmVariables); - + // Modify the transition matrix so all choices are probabilistic and the Markovian choices additionally // have a rate. this->transitionMatrix = this->transitionMatrix / this->markovianChoices.ite(this->exitRateVector, this->getManager().template getAddOne()); @@ -105,7 +105,7 @@ namespace storm { template MarkovAutomaton MarkovAutomaton::close() { // Create the new transition matrix by deleting all Markovian transitions from probabilistic states. - storm::dd::Add newTransitionMatrix = this->probabilisticStates.ite(this->getTransitionMatrix() * (!this->getMarkovianMarker()).template toAdd(), this->getTransitionMatrix()); + storm::dd::Add newTransitionMatrix = this->probabilisticStates.ite(this->getTransitionMatrix() * (!this->getMarkovianMarker()).template toAdd(), this->getTransitionMatrix() * this->getExitRateVector()); return MarkovAutomaton(this->getManagerAsSharedPointer(), this->getMarkovianMarker(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), newTransitionMatrix, this->getRowVariables(), this->getRowExpressionAdapter(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getNondeterminismVariables(), this->getLabelToExpressionMap(), this->getRewardModels()); } @@ -115,11 +115,29 @@ namespace storm { return this->exitRateVector; } + template + template + std::shared_ptr> MarkovAutomaton::toValueType() const { + typedef typename NondeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getMarkovianMarker(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getNondeterminismVariables(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class MarkovAutomaton; template class MarkovAutomaton; template class MarkovAutomaton; + template std::shared_ptr> MarkovAutomaton::toValueType() const; template class MarkovAutomaton; } // namespace symbolic diff --git a/src/storm/models/symbolic/MarkovAutomaton.h b/src/storm/models/symbolic/MarkovAutomaton.h index 30b1dbdfc..e2e0f3369 100644 --- a/src/storm/models/symbolic/MarkovAutomaton.h +++ b/src/storm/models/symbolic/MarkovAutomaton.h @@ -92,6 +92,9 @@ namespace storm { storm::dd::Add const& getExitRateVector() const; + template + std::shared_ptr> toValueType() const; + private: /*! * Computes the member data related to Markovian stuff. diff --git a/src/storm/models/symbolic/Mdp.cpp b/src/storm/models/symbolic/Mdp.cpp index c5de7a371..65bd49769 100644 --- a/src/storm/models/symbolic/Mdp.cpp +++ b/src/storm/models/symbolic/Mdp.cpp @@ -45,11 +45,29 @@ namespace storm { // Intentionally left empty. } + template + template + std::shared_ptr> Mdp::toValueType() const { + typedef typename NondeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getNondeterminismVariables(), newLabelToBddMap, newRewardModels); + } + // Explicitly instantiate the template class. template class Mdp; template class Mdp; template class Mdp; + template std::shared_ptr> Mdp::toValueType() const; template class Mdp; } // namespace symbolic diff --git a/src/storm/models/symbolic/Mdp.h b/src/storm/models/symbolic/Mdp.h index 771f0bd05..d8432ad49 100644 --- a/src/storm/models/symbolic/Mdp.h +++ b/src/storm/models/symbolic/Mdp.h @@ -83,6 +83,9 @@ namespace storm { std::map> labelToBddMap = std::map>(), std::unordered_map const& rewardModels = std::unordered_map()); + template + std::shared_ptr> toValueType() const; + }; } // namespace symbolic diff --git a/src/storm/models/symbolic/Model.cpp b/src/storm/models/symbolic/Model.cpp index 1c1ebf749..f7a9f367f 100644 --- a/src/storm/models/symbolic/Model.cpp +++ b/src/storm/models/symbolic/Model.cpp @@ -2,6 +2,12 @@ #include +#include "storm/models/symbolic/Dtmc.h" +#include "storm/models/symbolic/Ctmc.h" +#include "storm/models/symbolic/Mdp.h" +#include "storm/models/symbolic/MarkovAutomaton.h" +#include "storm/models/symbolic/StochasticTwoPlayerGame.h" + #include "storm/exceptions/IllegalArgumentException.h" #include "storm/exceptions/InvalidOperationException.h" @@ -9,6 +15,7 @@ #include "storm/models/symbolic/StandardRewardModel.h" +#include "storm/utility/constants.h" #include "storm/utility/macros.h" #include "storm/utility/dd.h" @@ -211,6 +218,11 @@ namespace storm { return labelToExpressionMap; } + template + std::map> const& Model::getLabelToBddMap() const { + return labelToBddMap; + } + template storm::dd::Add Model::getRowColumnIdentity() const { return (storm::utility::dd::getRowColumnDiagonal(this->getManager(), this->getRowColumnMetaVariablePairs()) && this->getReachableStates()).template toAdd(); @@ -351,6 +363,26 @@ namespace storm { bool Model::isSymbolicModel() const { return true; } + + template + bool Model::supportsParameters() const { + return std::is_same::value; + } + + template + bool Model::hasParameters() const { + if (!this->supportsParameters()) { + return false; + } + // Check for parameters + for (auto it = this->getTransitionMatrix().begin(false); it != this->getTransitionMatrix().end(); ++it) { + if (!storm::utility::isConstant((*it).second)) { + return true; + } + } + // Only constant values present + return false; + } template void Model::addParameters(std::set const& parameters) { @@ -372,11 +404,59 @@ namespace storm { return parameters; } + template + template + typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const { + STORM_LOG_TRACE("Converting value type of symbolic model from " << typeid(ValueType).name() << " to " << typeid(NewValueType).name() << "."); + + // Make a huge branching here as we cannot make a templated function virtual. + if (this->getType() == storm::models::ModelType::Dtmc) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::Ctmc) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::Mdp) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::MarkovAutomaton) { + return this->template as>()->template toValueType(); + } else if (this->getType() == storm::models::ModelType::S2pg) { + return this->template as>()->template toValueType(); + } + + STORM_LOG_WARN("Could not convert value type of model."); + return nullptr; + } + + template + template + typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const { + // Make a huge branching here as we cannot make a templated function virtual. + if (this->getType() == storm::models::ModelType::Dtmc) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::Ctmc) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::Mdp) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::MarkovAutomaton) { + return std::make_shared>(*this->template as>()); + } else if (this->getType() == storm::models::ModelType::S2pg) { + return std::make_shared>(*this->template as>()); + } + + STORM_LOG_WARN("Could not convert value type of model."); + return nullptr; + } + // Explicitly instantiate the template class. template class Model; template class Model; - + + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template class Model; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; + template typename std::enable_if::value, std::shared_ptr>>::type Model::toValueType() const; template class Model; } // namespace symbolic } // namespace models diff --git a/src/storm/models/symbolic/Model.h b/src/storm/models/symbolic/Model.h index 42cf143f1..7b3500bd1 100644 --- a/src/storm/models/symbolic/Model.h +++ b/src/storm/models/symbolic/Model.h @@ -321,12 +321,28 @@ namespace storm { virtual bool isSymbolicModel() const override; + virtual bool supportsParameters() const override; + + /*! + * Checks whether the model has parameters. + * Performance warning: the worst-case complexity is linear in the number of transitions. + * + * @return True iff the model has parameters. + */ + virtual bool hasParameters() const override; + std::vector getLabels() const; void addParameters(std::set const& parameters); std::set const& getParameters() const; + template + typename std::enable_if::value, std::shared_ptr>>::type toValueType() const; + + template + typename std::enable_if::value, std::shared_ptr>>::type toValueType() const; + protected: /*! * Sets the transition matrix of the model. @@ -342,6 +358,13 @@ namespace storm { */ std::map const& getLabelToExpressionMap() const; + /*! + * Retrieves the mapping of labels to their defining expressions. + * + * @returns The mapping of labels to their defining expressions. + */ + std::map> const& getLabelToBddMap() const; + /*! * Prints the information header (number of states and transitions) of the model to the specified stream. * diff --git a/src/storm/models/symbolic/StandardRewardModel.cpp b/src/storm/models/symbolic/StandardRewardModel.cpp index ffd94ad74..38bd56c5c 100644 --- a/src/storm/models/symbolic/StandardRewardModel.cpp +++ b/src/storm/models/symbolic/StandardRewardModel.cpp @@ -196,10 +196,17 @@ namespace storm { } } + template + template + StandardRewardModel StandardRewardModel::toValueType() const { + return StandardRewardModel(this->hasStateRewards() ? boost::make_optional(this->getStateRewardVector().template toValueType()) : boost::none, this->hasStateActionRewards() ? boost::make_optional(this->getStateActionRewardVector().template toValueType()) : boost::none, this->hasTransitionRewards() ? boost::make_optional(this->getTransitionRewardMatrix().template toValueType()) : boost::none); + } + template class StandardRewardModel; template class StandardRewardModel; template class StandardRewardModel; + template StandardRewardModel StandardRewardModel::toValueType() const; template class StandardRewardModel; } diff --git a/src/storm/models/symbolic/StandardRewardModel.h b/src/storm/models/symbolic/StandardRewardModel.h index c16f144e5..3d705e448 100644 --- a/src/storm/models/symbolic/StandardRewardModel.h +++ b/src/storm/models/symbolic/StandardRewardModel.h @@ -212,6 +212,9 @@ namespace storm { */ void reduceToStateBasedRewards(storm::dd::Add const& transitionMatrix, std::set const& rowVariables, std::set const& columnVariables, bool reduceToStateRewards); + template + StandardRewardModel toValueType() const; + private: // The state reward vector. boost::optional> optionalStateRewardVector; diff --git a/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp b/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp index b4b59e934..8695c57d8 100644 --- a/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp +++ b/src/storm/models/symbolic/StochasticTwoPlayerGame.cpp @@ -82,11 +82,35 @@ namespace storm { return player2Variables; } + template + template + std::shared_ptr> StochasticTwoPlayerGame::toValueType() const { + typedef typename NondeterministicModel::RewardModelType NewRewardModelType; + std::unordered_map newRewardModels; + + for (auto const& e : this->getRewardModels()) { + newRewardModels.emplace(e.first, e.second.template toValueType()); + } + + auto newLabelToBddMap = this->getLabelToBddMap(); + newLabelToBddMap.erase("init"); + newLabelToBddMap.erase("deadlock"); + + return std::make_shared>(this->getManagerAsSharedPointer(), this->getReachableStates(), this->getInitialStates(), this->getDeadlockStates(), this->getTransitionMatrix().template toValueType(), this->getRowVariables(), this->getColumnVariables(), this->getRowColumnMetaVariablePairs(), this->getPlayer1Variables(), this->getPlayer2Variables(), this->getNondeterminismVariables(), newLabelToBddMap, newRewardModels); + + } + + template + uint64_t StochasticTwoPlayerGame::getNumberOfPlayer2States() const { + return this->getQualitativeTransitionMatrix().existsAbstract(this->getColumnVariables()).getNonZeroCount(); + } + // Explicitly instantiate the template class. template class StochasticTwoPlayerGame; template class StochasticTwoPlayerGame; #ifdef STORM_HAVE_CARL template class StochasticTwoPlayerGame; + template std::shared_ptr> StochasticTwoPlayerGame::toValueType() const; template class StochasticTwoPlayerGame; #endif diff --git a/src/storm/models/symbolic/StochasticTwoPlayerGame.h b/src/storm/models/symbolic/StochasticTwoPlayerGame.h index d3f009593..1a243eff5 100644 --- a/src/storm/models/symbolic/StochasticTwoPlayerGame.h +++ b/src/storm/models/symbolic/StochasticTwoPlayerGame.h @@ -117,6 +117,14 @@ namespace storm { */ storm::dd::Bdd getIllegalPlayer2Mask() const; + template + std::shared_ptr> toValueType() const; + + /*! + * Retrieves the number of player 2 states in the game. + */ + uint64_t getNumberOfPlayer2States() const; + private: /*! * Prepare all illegal masks. diff --git a/src/storm/parser/JaniParser.h b/src/storm/parser/JaniParser.h deleted file mode 100644 index 9a6bdace6..000000000 --- a/src/storm/parser/JaniParser.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once -#include "storm/storage/jani/Constant.h" -#include "storm/logic/Formula.h" -#include "storm/logic/Bound.h" -#include "storm/exceptions/FileIoException.h" -#include "storm/storage/expressions/ExpressionManager.h" - - -// JSON parser -#include "json.hpp" - -using json = nlohmann::json; - -namespace storm { - namespace jani { - class Model; - class Automaton; - class Variable; - class Composition; - class Property; - struct PropertyInterval; - } - - namespace logic { - enum class FormulaContext; - } - - - namespace parser { - /* - * The JANI format parser. - * Parses Models and Properties - * - * TODO some parts are copy-heavy, a bit of cleaning is good as soon as the format is stable. - */ - class JaniParser { - - public: - typedef std::vector PropertyVector; - - JaniParser() : expressionManager(new storm::expressions::ExpressionManager()) {} - JaniParser(std::string const& jsonstring); - static std::pair> parse(std::string const& path); - - - protected: - void readFile(std::string const& path); - std::pair> parseModel(bool parseProperties = true); - storm::jani::Property parseProperty(json const& propertyStructure, std::unordered_map> const& globalVars, std::unordered_map> const& constants); - storm::jani::Automaton parseAutomaton(json const& automatonStructure, storm::jani::Model const& parentModel, std::unordered_map> const& globalVars, std::unordered_map> const& constants); - std::shared_ptr parseVariable(json const& variableStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool prefWithScope = false); - storm::expressions::Expression parseExpression(json const& expressionStructure, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false); - - private: - std::shared_ptr parseConstant(json const& constantStructure, std::unordered_map> const& constants, std::string const& scopeDescription = "global"); - - /** - * Helper for parsing the actions of a model. - */ - void parseActions(json const& actionStructure, storm::jani::Model& parentModel); - std::shared_ptr parseFormula(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context, boost::optional bound = boost::none); - std::vector parseUnaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars= {}, bool returnNoneOnUnknownOpString = false); - std::vector parseBinaryExpressionArguments(json const& expressionStructure, std::string const& opstring, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}, bool returnNoneOnUnknownOpString = false); - - - std::vector> parseUnaryFormulaArgument(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); - std::vector> parseBinaryFormulaArguments(json const& propertyStructure, storm::logic::FormulaContext formulaContext, std::string const& opstring, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::string const& context); - storm::jani::PropertyInterval parsePropertyInterval(json const& piStructure); - - - std::shared_ptr parseComposition(json const& compositionStructure); - storm::expressions::Variable getVariableOrConstantExpression(std::string const& ident, std::string const& scopeDescription, std::unordered_map> const& globalVars, std::unordered_map> const& constants, std::unordered_map> const& localVars = {}); - - - - /** - * The overall structure currently under inspection. - */ - json parsedStructure; - /** - * The expression manager to be used. - */ - std::shared_ptr expressionManager; - - std::set labels = {}; - - bool allowRecursion = true; - - ////////// - // Default values -- assumptions from JANI. - ////////// - static const bool defaultVariableTransient; - - static const bool defaultBooleanInitialValue; - static const double defaultRationalInitialValue; - static const int64_t defaultIntegerInitialValue; - - static const std::set unsupportedOpstrings; - - }; - } -} - diff --git a/src/storm/settings/SettingsManager.cpp b/src/storm/settings/SettingsManager.cpp index fa17365d0..3990daf45 100644 --- a/src/storm/settings/SettingsManager.cpp +++ b/src/storm/settings/SettingsManager.cpp @@ -15,8 +15,8 @@ #include "storm/settings/modules/GeneralSettings.h" #include "storm/settings/modules/CoreSettings.h" #include "storm/settings/modules/IOSettings.h" +#include "storm/settings/modules/ModelCheckerSettings.h" #include "storm/settings/modules/DebugSettings.h" -#include "storm/settings/modules/CounterexampleGeneratorSettings.h" #include "storm/settings/modules/CuddSettings.h" #include "storm/settings/modules/BuildSettings.h" #include "storm/settings/modules/SylvanSettings.h" @@ -30,13 +30,13 @@ #include "storm/settings/modules/GlpkSettings.h" #include "storm/settings/modules/GurobiSettings.h" #include "storm/settings/modules/Smt2SmtSolverSettings.h" -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" #include "storm/settings/modules/ExplorationSettings.h" #include "storm/settings/modules/ResourceSettings.h" #include "storm/settings/modules/AbstractionSettings.h" -#include "storm/settings/modules/JaniExportSettings.h" #include "storm/settings/modules/JitBuilderSettings.h" #include "storm/settings/modules/MultiObjectiveSettings.h" +#include "storm/settings/modules/MultiplierSettings.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" #include "storm/settings/Option.h" @@ -137,7 +137,7 @@ namespace storm { } // Include the options from a possibly specified configuration file, but don't overwrite existing settings. - if (storm::settings::getModule().isConfigSet()) { + if (storm::settings::hasModule() && storm::settings::getModule().isConfigSet()) { this->setFromConfigurationFile(storm::settings::getModule().getConfigFilename()); } @@ -530,8 +530,8 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); @@ -543,14 +543,14 @@ namespace storm { storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); + storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); - storm::settings::addModule(); storm::settings::addModule(); storm::settings::addModule(); + storm::settings::addModule(); } } diff --git a/src/storm/settings/SettingsManager.h b/src/storm/settings/SettingsManager.h index 1ccb10bfa..1e02e4471 100644 --- a/src/storm/settings/SettingsManager.h +++ b/src/storm/settings/SettingsManager.h @@ -270,6 +270,20 @@ namespace storm { return dynamic_cast(manager().getModule(SettingsType::moduleName)); } + + /*! + * Returns true if the given module is registered. + * + */ + template + bool hasModule() { + static_assert(std::is_base_of::value, "Template argument must be derived from ModuleSettings"); + if (manager().hasModule(SettingsType::moduleName)) { + return dynamic_cast(&(manager().getModule(SettingsType::moduleName))) != nullptr; + } + return false; + } + /*! * Retrieves the core settings in a mutable form. This is only meant to be used for debug purposes or very * rare cases where it is necessary. diff --git a/src/storm/settings/modules/AbstractionSettings.cpp b/src/storm/settings/modules/AbstractionSettings.cpp index 4835019d4..3f02b352a 100644 --- a/src/storm/settings/modules/AbstractionSettings.cpp +++ b/src/storm/settings/modules/AbstractionSettings.cpp @@ -17,18 +17,33 @@ namespace storm { const std::string AbstractionSettings::useDecompositionOptionName = "decomposition"; const std::string AbstractionSettings::splitModeOptionName = "split"; const std::string AbstractionSettings::addAllGuardsOptionName = "all-guards"; + const std::string AbstractionSettings::addInitialExpressionsOptionName = "all-inits"; const std::string AbstractionSettings::useInterpolationOptionName = "interpolation"; const std::string AbstractionSettings::precisionOptionName = "precision"; + const std::string AbstractionSettings::relativeOptionName = "relative"; const std::string AbstractionSettings::pivotHeuristicOptionName = "pivot-heuristic"; const std::string AbstractionSettings::reuseResultsOptionName = "reuse"; + const std::string AbstractionSettings::restrictToRelevantStatesOptionName = "relevant"; + const std::string AbstractionSettings::solveModeOptionName = "solve"; + const std::string AbstractionSettings::maximalAbstractionOptionName = "maxabs"; + const std::string AbstractionSettings::rankRefinementPredicatesOptionName = "rankpred"; + const std::string AbstractionSettings::constraintsOptionName = "constraints"; + const std::string AbstractionSettings::useEagerRefinementOptionName = "eagerref"; + const std::string AbstractionSettings::debugOptionName = "debug"; + const std::string AbstractionSettings::injectRefinementPredicatesOptionName = "injectref"; + const std::string AbstractionSettings::fixPlayer1StrategyOptionName = "fixpl1strat"; + const std::string AbstractionSettings::fixPlayer2StrategyOptionName = "fixpl2strat"; + const std::string AbstractionSettings::validBlockModeOptionName = "validmode"; AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) { std::vector methods = {"games", "bisimulation", "bisim"}; this->addOption(storm::settings::OptionBuilder(moduleName, methodOptionName, true, "Sets which abstraction-refinement method to use.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of themethod to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)) + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)) .setDefaultValueString("bisim").build()) .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalAbstractionOptionName, false, "The maximal number of abstraction to perform before solving is aborted.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal abstraction count.").setDefaultValueUnsignedInteger(20000).build()).build()); + std::vector onOff = {"on", "off"}; this->addOption(storm::settings::OptionBuilder(moduleName, useDecompositionOptionName, true, "Sets whether to apply decomposition during the abstraction.") @@ -41,18 +56,34 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(splitModes)) .setDefaultValueString("all").build()) .build()); - + + std::vector solveModes = {"dd", "sparse"}; + this->addOption(storm::settings::OptionBuilder(moduleName, solveModeOptionName, true, "Sets how the abstractions are solved.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(solveModes)) + .setDefaultValueString("sparse").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, addAllGuardsOptionName, true, "Sets whether all guards are added as initial predicates.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("on").build()) .build()); - + + this->addOption(storm::settings::OptionBuilder(moduleName, addInitialExpressionsOptionName, true, "Sets whether all initial expressions are added as initial predicates.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + this->addOption(storm::settings::OptionBuilder(moduleName, useInterpolationOptionName, true, "Sets whether interpolation is to be used to eliminate spurious pivot blocks.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) .setDefaultValueString("on").build()) .build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, true, "The precision used for detecting convergence.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-03).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, relativeOptionName, true, "Sets whether to use a relative termination criterion.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); std::vector pivotHeuristic = {"nearest-max-dev", "most-prob-path", "max-weighted-dev"}; this->addOption(storm::settings::OptionBuilder(moduleName, pivotHeuristicOptionName, true, "Sets the pivot selection heuristic.") @@ -64,6 +95,51 @@ namespace storm { .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(reuseModes)) .setDefaultValueString("all").build()) .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, restrictToRelevantStatesOptionName, true, "Sets whether to restrict to relevant states during the abstraction.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, rankRefinementPredicatesOptionName, true, "Sets whether to rank the refinement predicates if there are multiple.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, useEagerRefinementOptionName, true, "Sets whether to refine eagerly.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, constraintsOptionName, true, "Specifies additional constraints used by the abstraction.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("constraints", "The constraints to use.").setDefaultValueString("").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, injectRefinementPredicatesOptionName, true, "Specifies predicates used by the refinement instead of the derived predicates.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("predicates", "The (semicolon-separated) refinement predicates to use.").setDefaultValueString("").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, fixPlayer1StrategyOptionName, true, "Sets whether to fix player 1 strategies.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, fixPlayer2StrategyOptionName, true, "Sets whether to fix player 2 strategies.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("on").build()) + .build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, debugOptionName, true, "Sets whether to enable debug mode.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("value", "The value of the flag.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(onOff)) + .setDefaultValueString("off").build()) + .build()); + + std::vector validModes = {"morepreds", "blockenum"}; + this->addOption(storm::settings::OptionBuilder(moduleName, validBlockModeOptionName, true, "Sets the mode to guarantee valid blocks only.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(validModes)) + .setDefaultValueString("morepreds").build()) + .build()); + } AbstractionSettings::Method AbstractionSettings::getAbstractionRefinementMethod() const { @@ -77,7 +153,7 @@ namespace storm { } bool AbstractionSettings::isUseDecompositionSet() const { - return this->getOption(useDecompositionOptionName).getHasOptionBeenSet(); + return this->getOption(useDecompositionOptionName).getArgumentByName("value").getValueAsString() == "on"; } AbstractionSettings::SplitMode AbstractionSettings::getSplitMode() const { @@ -92,22 +168,46 @@ namespace storm { return SplitMode::All; } + AbstractionSettings::SolveMode AbstractionSettings::getSolveMode() const { + std::string solveModeAsString = this->getOption(solveModeOptionName).getArgumentByName("mode").getValueAsString(); + if (solveModeAsString == "dd") { + return SolveMode::Dd; + } + return SolveMode::Sparse; + } + bool AbstractionSettings::isAddAllGuardsSet() const { return this->getOption(addAllGuardsOptionName).getArgumentByName("value").getValueAsString() == "on"; } + bool AbstractionSettings::isAddAllInitialExpressionsSet() const { + return this->getOption(addInitialExpressionsOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + void AbstractionSettings::setAddAllGuards(bool value) { this->getOption(addAllGuardsOptionName).getArgumentByName("value").setFromStringValue(value ? "on" : "off"); } + void AbstractionSettings::setAddAllInitialExpressions(bool value) { + this->getOption(addInitialExpressionsOptionName).getArgumentByName("value").setFromStringValue(value ? "on" : "off"); + } + bool AbstractionSettings::isUseInterpolationSet() const { return this->getOption(useInterpolationOptionName).getArgumentByName("value").getValueAsString() == "on"; } + bool AbstractionSettings::isRestrictToRelevantStatesSet() const { + return this->getOption(restrictToRelevantStatesOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + double AbstractionSettings::getPrecision() const { return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); } + bool AbstractionSettings::getRelativeTerminationCriterion() const { + return this->getOption(relativeOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + AbstractionSettings::PivotSelectionHeuristic AbstractionSettings::getPivotSelectionHeuristic() const { std::string heuristicName = this->getOption(pivotHeuristicOptionName).getArgumentByName("name").getValueAsString(); if (heuristicName == "nearest-max-dev") { @@ -134,6 +234,56 @@ namespace storm { return ReuseMode::All; } + uint_fast64_t AbstractionSettings::getMaximalAbstractionCount() const { + return this->getOption(maximalAbstractionOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); + } + + bool AbstractionSettings::isRankRefinementPredicatesSet() const { + return this->getOption(rankRefinementPredicatesOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + bool AbstractionSettings::isConstraintsSet() const { + return this->getOption(constraintsOptionName).getHasOptionBeenSet(); + } + + std::string AbstractionSettings::getConstraintString() const { + return this->getOption(constraintsOptionName).getArgumentByName("constraints").getValueAsString(); + } + + bool AbstractionSettings::isUseEagerRefinementSet() const { + return this->getOption(useEagerRefinementOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + bool AbstractionSettings::isDebugSet() const { + return this->getOption(debugOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + bool AbstractionSettings::isInjectRefinementPredicatesSet() const { + return this->getOption(injectRefinementPredicatesOptionName).getHasOptionBeenSet(); + } + + std::string AbstractionSettings::getInjectedRefinementPredicates() const { + return this->getOption(injectRefinementPredicatesOptionName).getArgumentByName("predicates").getValueAsString(); + } + + bool AbstractionSettings::isFixPlayer1StrategySet() const { + return this->getOption(fixPlayer1StrategyOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + bool AbstractionSettings::isFixPlayer2StrategySet() const { + return this->getOption(fixPlayer2StrategyOptionName).getArgumentByName("value").getValueAsString() == "on"; + } + + AbstractionSettings::ValidBlockMode AbstractionSettings::getValidBlockMode() const { + std::string modeAsString = this->getOption(validBlockModeOptionName).getArgumentByName("mode").getValueAsString(); + if (modeAsString == "morepreds") { + return ValidBlockMode::MorePredicates; + } else if (modeAsString == "blockenum") { + return ValidBlockMode::BlockEnumeration; + } + return ValidBlockMode::MorePredicates; + } + } } } diff --git a/src/storm/settings/modules/AbstractionSettings.h b/src/storm/settings/modules/AbstractionSettings.h index 4d5827187..4619f300c 100644 --- a/src/storm/settings/modules/AbstractionSettings.h +++ b/src/storm/settings/modules/AbstractionSettings.h @@ -27,6 +27,14 @@ namespace storm { All, None, Qualitative, Quantitative }; + enum class SolveMode { + Dd, Sparse + }; + + enum class ValidBlockMode { + MorePredicates, BlockEnumeration + }; + /*! * Creates a new set of abstraction settings. */ @@ -58,6 +66,13 @@ namespace storm { */ bool isAddAllGuardsSet() const; + /*! + * Retrieves whether the option to add all initial expressions was set. + * + * @return True iff the option was set. + */ + bool isAddAllInitialExpressionsSet() const; + /*! * Sets the option to add all guards to the specified value. * @@ -65,6 +80,13 @@ namespace storm { */ void setAddAllGuards(bool value); + /*! + * Sets the option to add all initial expressions to the specified value. + * + * @param value The new value. + */ + void setAddAllInitialExpressions(bool value); + /*! * Retrieves whether the option to use interpolation was set. * @@ -79,6 +101,11 @@ namespace storm { */ double getPrecision() const; + /*! + * Retrieves whether to use a relative termination criterion for detecting convergence. + */ + bool getRelativeTerminationCriterion() const; + /*! * Retrieves the selected heuristic to select pivot blocks. * @@ -93,6 +120,81 @@ namespace storm { */ ReuseMode getReuseMode() const; + /*! + * Retrieves whether only relevant states are to be considered. + * + * @return True iff the option was set. + */ + bool isRestrictToRelevantStatesSet() const; + + /*! + * Retrieves the mode with which to solve the games. + */ + SolveMode getSolveMode() const; + + /*! + * Retrieves the maximal number of abstractions to perform until giving up on converging. + * + * @return The maximal abstraction count. + */ + uint_fast64_t getMaximalAbstractionCount() const; + + /* + * Determines whether refinement predicates are to be ranked. + * + * @return True iff the refinement predicates are to be ranked. + */ + bool isRankRefinementPredicatesSet() const; + + /*! + * Retrieves whether the constraints option was set. + * + * @return True if the constraints option was set. + */ + bool isConstraintsSet() const; + + /*! + * Retrieves the string that specifies additional constraints. + * + * @return The string that defines the constraints. + */ + std::string getConstraintString() const; + + /*! + * Retrieves whether to refine eagerly. + */ + bool isUseEagerRefinementSet() const; + + /*! + * Retrieves whether the debug option was set. + */ + bool isDebugSet() const; + + /*! + * Retrieves whether the option to inject the refinement predicates is set. + */ + bool isInjectRefinementPredicatesSet() const; + + /*! + * Retrieves a string containing refinement predicates to inject (if there are any). + */ + std::string getInjectedRefinementPredicates() const; + + /*! + * Retrieves whether player 1 strategies are to be fixed. + */ + bool isFixPlayer1StrategySet() const; + + /*! + * Retrieves whether player 2 strategies are to be fixed. + */ + bool isFixPlayer2StrategySet() const; + + /*! + * Retrieves the selected mode to guarantee valid blocks. + */ + ValidBlockMode getValidBlockMode() const; + const static std::string moduleName; private: @@ -100,10 +202,23 @@ namespace storm { const static std::string useDecompositionOptionName; const static std::string splitModeOptionName; const static std::string addAllGuardsOptionName; + const static std::string addInitialExpressionsOptionName; const static std::string useInterpolationOptionName; const static std::string precisionOptionName; + const static std::string relativeOptionName; const static std::string pivotHeuristicOptionName; const static std::string reuseResultsOptionName; + const static std::string restrictToRelevantStatesOptionName; + const static std::string solveModeOptionName; + const static std::string maximalAbstractionOptionName; + const static std::string rankRefinementPredicatesOptionName; + const static std::string constraintsOptionName; + const static std::string useEagerRefinementOptionName; + const static std::string debugOptionName; + const static std::string injectRefinementPredicatesOptionName; + const static std::string fixPlayer1StrategyOptionName; + const static std::string fixPlayer2StrategyOptionName; + const static std::string validBlockModeOptionName; }; } diff --git a/src/storm/settings/modules/BisimulationSettings.cpp b/src/storm/settings/modules/BisimulationSettings.cpp index 56b3419e9..0b7c219f5 100644 --- a/src/storm/settings/modules/BisimulationSettings.cpp +++ b/src/storm/settings/modules/BisimulationSettings.cpp @@ -21,6 +21,7 @@ namespace storm { const std::string BisimulationSettings::reuseOptionName = "reuse"; const std::string BisimulationSettings::initialPartitionOptionName = "init"; const std::string BisimulationSettings::refinementModeOptionName = "refine"; + const std::string BisimulationSettings::exactArithmeticDdOptionName = "ddexact"; BisimulationSettings::BisimulationSettings() : ModuleSettings(moduleName) { std::vector types = { "strong", "weak" }; @@ -31,6 +32,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, representativeOptionName, false, "Sets whether to use representatives in the quotient rather than block numbers.").build()); this->addOption(storm::settings::OptionBuilder(moduleName, originalVariablesOptionName, false, "Sets whether to use the original variables in the quotient rather than the block variables.").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, exactArithmeticDdOptionName, false, "Sets whether to use exact arithmetic in dd-based bisimulation.").build()); std::vector signatureModes = { "eager", "lazy" }; this->addOption(storm::settings::OptionBuilder(moduleName, signatureModeOptionName, false, "Sets the signature computation mode.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("mode", "The mode to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(signatureModes)).setDefaultValueString("eager").build()).build()); @@ -84,6 +86,10 @@ namespace storm { return this->getOption(originalVariablesOptionName).getHasOptionBeenSet(); } + bool BisimulationSettings::useExactArithmeticInDdBisimulation() const { + return this->getOption(exactArithmeticDdOptionName).getHasOptionBeenSet(); + } + storm::dd::bisimulation::SignatureMode BisimulationSettings::getSignatureMode() const { std::string modeAsString = this->getOption(signatureModeOptionName).getArgumentByName("mode").getValueAsString(); if (modeAsString == "eager") { diff --git a/src/storm/settings/modules/BisimulationSettings.h b/src/storm/settings/modules/BisimulationSettings.h index eb9627f68..c06713a8a 100644 --- a/src/storm/settings/modules/BisimulationSettings.h +++ b/src/storm/settings/modules/BisimulationSettings.h @@ -63,6 +63,13 @@ namespace storm { */ bool isUseOriginalVariablesSet() const; + /*! + * Retrieves whether exact arithmetic is to be used in symbolic bisimulation minimization. + * + * @return True iff exact arithmetic is to be used in symbolic bisimulation minimization. + */ + bool useExactArithmeticInDdBisimulation() const; + /*! * Retrieves the mode to compute signatures. */ @@ -99,6 +106,7 @@ namespace storm { static const std::string initialPartitionOptionName; static const std::string refinementModeOptionName; static const std::string parallelismModeOptionName; + static const std::string exactArithmeticDdOptionName; }; } // namespace modules } // namespace settings diff --git a/src/storm/settings/modules/BuildSettings.cpp b/src/storm/settings/modules/BuildSettings.cpp index a813b08fa..2faa39fa5 100644 --- a/src/storm/settings/modules/BuildSettings.cpp +++ b/src/storm/settings/modules/BuildSettings.cpp @@ -29,6 +29,8 @@ namespace storm { const std::string fullModelBuildOptionName = "buildfull"; const std::string buildChoiceLabelOptionName = "buildchoicelab"; const std::string buildStateValuationsOptionName = "buildstateval"; + const std::string buildOutOfBoundsStateOptionName = "buildoutofboundsstate"; + const std::string bitsForUnboundedVariablesOptionName = "int-bits"; BuildSettings::BuildSettings() : ModuleSettings(moduleName) { std::vector explorationOrders = {"dfs", "bfs"}; @@ -42,10 +44,11 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, explorationOrderOptionName, false, "Sets which exploration order to use.").setShortName(explorationOrderOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the exploration order to choose.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(explorationOrders)).setDefaultValueString("bfs").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, explorationChecksOptionName, false, "If set, additional checks (if available) are performed during model exploration to debug the model.").setShortName(explorationChecksOptionShortName).build()); - + this->addOption(storm::settings::OptionBuilder(moduleName, buildOutOfBoundsStateOptionName, false, "If set, a state for out-of-bounds valuations is added").build()); + this->addOption(storm::settings::OptionBuilder(moduleName, bitsForUnboundedVariablesOptionName, false, "Sets the number of bits that is used for unbounded integer variables.") + .addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("number", "The number of bits.").addValidatorUnsignedInteger(ArgumentValidatorFactory::createUnsignedRangeValidatorExcluding(0,63)).setDefaultValueUnsignedInteger(32).build()).build()); } - bool BuildSettings::isJitSet() const { return this->getOption(jitOptionName).getHasOptionBeenSet(); } @@ -74,6 +77,9 @@ namespace storm { return this->getOption(buildStateValuationsOptionName).getHasOptionBeenSet(); } + bool BuildSettings::isBuildOutOfBoundsStateSet() const { + return this->getOption(buildOutOfBoundsStateOptionName).getHasOptionBeenSet(); + } storm::builder::ExplorationOrder BuildSettings::getExplorationOrder() const { std::string explorationOrderAsString = this->getOption(explorationOrderOptionName).getArgumentByName("name").getValueAsString(); @@ -84,10 +90,15 @@ namespace storm { } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown exploration order '" << explorationOrderAsString << "'."); } - + bool BuildSettings::isExplorationChecksSet() const { return this->getOption(explorationChecksOptionName).getHasOptionBeenSet(); } + + uint64_t BuildSettings::getBitsForUnboundedVariables() const { + return this->getOption(bitsForUnboundedVariablesOptionName).getArgumentByName("number").getValueAsUnsignedInteger(); + } + } diff --git a/src/storm/settings/modules/BuildSettings.h b/src/storm/settings/modules/BuildSettings.h index 4ef0f5193..29575e2a3 100644 --- a/src/storm/settings/modules/BuildSettings.h +++ b/src/storm/settings/modules/BuildSettings.h @@ -75,6 +75,18 @@ namespace storm { */ bool isBuildStateValuationsSet() const; + /*! + * Retrieves whether out of bounds state should be added + * @return + */ + bool isBuildOutOfBoundsStateSet() const; + + /*! + * Retrieves the number of bits that should be used to represent unbounded integer variables + * @return + */ + uint64_t getBitsForUnboundedVariables() const; + // The name of the module. static const std::string moduleName; diff --git a/src/storm/settings/modules/CoreSettings.cpp b/src/storm/settings/modules/CoreSettings.cpp index b01aee3f7..343d3c3d1 100644 --- a/src/storm/settings/modules/CoreSettings.cpp +++ b/src/storm/settings/modules/CoreSettings.cpp @@ -39,13 +39,13 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, counterexampleOptionName, false, "Generates a counterexample for the given PRCTL formulas if not satisfied by the model.").setShortName(counterexampleOptionShortName).build()); this->addOption(storm::settings::OptionBuilder(moduleName, dontFixDeadlockOptionName, false, "If the model contains deadlock states, they need to be fixed by setting this option.").setShortName(dontFixDeadlockOptionShortName).build()); - std::vector engines = {"sparse", "hybrid", "dd", "expl", "abs"}; + std::vector engines = {"sparse", "hybrid", "dd", "dd-to-sparse", "expl", "abs"}; this->addOption(storm::settings::OptionBuilder(moduleName, engineOptionName, false, "Sets which engine is used for model building and model checking.").setShortName(engineOptionShortName) .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the engine to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(engines)).setDefaultValueString("sparse").build()).build()); - std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; + std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, eqSolverOptionName, false, "Sets which solver is preferred for solving systems of linear equations.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the solver to prefer.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("topological").build()).build()); std::vector ddLibraries = {"cudd", "sylvan"}; this->addOption(storm::settings::OptionBuilder(moduleName, ddLibraryOptionName, false, "Sets which library is preferred for decision-diagram operations.") @@ -86,6 +86,8 @@ namespace storm { return storm::solver::EquationSolverType::Eigen; } else if (equationSolverName == "elimination") { return storm::solver::EquationSolverType::Elimination; + } else if (equationSolverName == "topological") { + return storm::solver::EquationSolverType::Topological; } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown equation solver '" << equationSolverName << "'."); } @@ -162,6 +164,8 @@ namespace storm { engine = CoreSettings::Engine::Hybrid; } else if (engineStr == "dd") { engine = CoreSettings::Engine::Dd; + } else if (engineStr == "dd-to-sparse") { + engine = CoreSettings::Engine::DdSparse; } else if (engineStr == "expl") { engine = CoreSettings::Engine::Exploration; } else if (engineStr == "abs") { diff --git a/src/storm/settings/modules/CoreSettings.h b/src/storm/settings/modules/CoreSettings.h index afd16cd78..8a07a48d0 100644 --- a/src/storm/settings/modules/CoreSettings.h +++ b/src/storm/settings/modules/CoreSettings.h @@ -28,7 +28,7 @@ namespace storm { public: // An enumeration of all engines. enum class Engine { - Sparse, Hybrid, Dd, Exploration, AbstractionRefinement + Sparse, Hybrid, Dd, DdSparse, Exploration, AbstractionRefinement }; /*! diff --git a/src/storm/settings/modules/EigenEquationSolverSettings.cpp b/src/storm/settings/modules/EigenEquationSolverSettings.cpp index 78eff7cef..f339a852e 100644 --- a/src/storm/settings/modules/EigenEquationSolverSettings.cpp +++ b/src/storm/settings/modules/EigenEquationSolverSettings.cpp @@ -34,7 +34,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, restartOptionName, true, "The number of iteration until restarted methods are actually restarted.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The number of iterations.").setDefaultValueUnsignedInteger(50).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); } diff --git a/src/storm/settings/modules/GameSolverSettings.cpp b/src/storm/settings/modules/GameSolverSettings.cpp index 58cbd3529..84feaba4f 100644 --- a/src/storm/settings/modules/GameSolverSettings.cpp +++ b/src/storm/settings/modules/GameSolverSettings.cpp @@ -23,7 +23,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which game solving technique is preferred.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a game solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(gameSolvingTechniques)).setDefaultValueString("vi").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); diff --git a/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp b/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp index 76da580a6..46b7f58fb 100644 --- a/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/GmmxxEquationSolverSettings.cpp @@ -34,7 +34,7 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, restartOptionName, true, "The number of iteration until restarted methods are actually restarted.").addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The number of iterations.").setDefaultValueUnsignedInteger(50).build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); } diff --git a/src/storm/settings/modules/IOSettings.cpp b/src/storm/settings/modules/IOSettings.cpp index 658b59cbe..2dabdbdb9 100644 --- a/src/storm/settings/modules/IOSettings.cpp +++ b/src/storm/settings/modules/IOSettings.cpp @@ -207,7 +207,11 @@ namespace storm { return this->getOption(janiPropertyOptionName).getHasOptionBeenSet(); } - std::vector IOSettings::getJaniProperties() const { + bool IOSettings::areJaniPropertiesSelected() const { + return this->getOption(janiPropertyOptionName).getHasOptionBeenSet() && (this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString() != ""); + } + + std::vector IOSettings::getSelectedJaniProperties() const { return storm::parser::parseCommaSeperatedValues(this->getOption(janiPropertyOptionName).getArgumentByName("values").getValueAsString()); } diff --git a/src/storm/settings/modules/IOSettings.h b/src/storm/settings/modules/IOSettings.h index cc41176bf..232368cc1 100644 --- a/src/storm/settings/modules/IOSettings.h +++ b/src/storm/settings/modules/IOSettings.h @@ -214,9 +214,9 @@ namespace storm { std::string getChoiceLabelingFilename() const; /*! - * Retrieves whether the export-to-dot option was set. + * Retrieves whether the constants option was set. * - * @return True if the export-to-dot option was set. + * @return True if the constants option was set. */ bool isConstantsSet() const; @@ -233,10 +233,16 @@ namespace storm { */ bool isJaniPropertiesSet() const; + /*! + * Retrieves whether one or more jani-properties have been selected + * @return + */ + bool areJaniPropertiesSelected() const; + /*! * @return The names of the jani properties to check */ - std::vector getJaniProperties() const; + std::vector getSelectedJaniProperties() const; /*! * Retrieves whether the property option was set. diff --git a/src/storm/settings/modules/JaniExportSettings.cpp b/src/storm/settings/modules/JaniExportSettings.cpp deleted file mode 100644 index a56cbc668..000000000 --- a/src/storm/settings/modules/JaniExportSettings.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "JaniExportSettings.h" - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/SettingMemento.h" -#include "storm/settings/Option.h" -#include "storm/settings/OptionBuilder.h" -#include "storm/settings/ArgumentBuilder.h" -#include "storm/settings/Argument.h" - -namespace storm { - namespace settings { - namespace modules { - const std::string JaniExportSettings::moduleName = "exportJani"; - - const std::string JaniExportSettings::janiFileOptionName = "jani-output"; - const std::string JaniExportSettings::janiFileOptionShortName = "output"; - const std::string JaniExportSettings::standardCompliantOptionName = "standard-compliant"; - const std::string JaniExportSettings::standardCompliantOptionShortName = "standard"; - - - JaniExportSettings::JaniExportSettings() : ModuleSettings(moduleName) { - this->addOption(storm::settings::OptionBuilder(moduleName, janiFileOptionName, false, "Destination for the jani model.").setShortName(janiFileOptionShortName).addArgument(storm::settings::ArgumentBuilder::createStringArgument("filename", "path to file").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, standardCompliantOptionName, false, "Export in standard compliant variant.").setShortName(standardCompliantOptionShortName).build()); - } - - bool JaniExportSettings::isJaniFileSet() const { - return this->getOption(janiFileOptionName).getHasOptionBeenSet(); - } - - std::string JaniExportSettings::getJaniFilename() const { - return this->getOption(janiFileOptionName).getArgumentByName("filename").getValueAsString(); - } - - bool JaniExportSettings::isExportAsStandardJaniSet() const { - return this->getOption(standardCompliantOptionName).getHasOptionBeenSet(); - } - - void JaniExportSettings::finalize() { - - } - - bool JaniExportSettings::check() const { - return true; - } - } - } -} diff --git a/src/storm/settings/modules/JaniExportSettings.h b/src/storm/settings/modules/JaniExportSettings.h deleted file mode 100644 index 397eb183a..000000000 --- a/src/storm/settings/modules/JaniExportSettings.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "storm-config.h" -#include "storm/settings/modules/ModuleSettings.h" - - -namespace storm { - namespace settings { - namespace modules { - class JaniExportSettings : public ModuleSettings { - public: - /*! - * Creates a new JaniExport setting - */ - JaniExportSettings(); - - /** - * Retrievew whether the pgcl file option was set - */ - bool isJaniFileSet() const; - - /** - * Retrieves the pgcl file name - */ - std::string getJaniFilename() const; - - bool isExportAsStandardJaniSet() const; - - bool check() const override; - void finalize() override; - - static const std::string moduleName; - - private: - static const std::string janiFileOptionName; - static const std::string janiFileOptionShortName; - static const std::string standardCompliantOptionName; - static const std::string standardCompliantOptionShortName; - - }; - } - } -} diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp index 15254ead1..d0e891b56 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.cpp @@ -18,14 +18,16 @@ namespace storm { const std::string MinMaxEquationSolverSettings::precisionOptionName = "precision"; const std::string MinMaxEquationSolverSettings::absoluteOptionName = "absolute"; const std::string MinMaxEquationSolverSettings::lraMethodOptionName = "lramethod"; + const std::string MinMaxEquationSolverSettings::markovAutomatonBoundedReachabilityMethodOptionName = "mamethod"; const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult"; + const std::string MinMaxEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch"}; + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "lp", "linear-programming", "rs", "ratsearch", "ii", "interval-iteration", "svi", "sound-value-iteration", "topological"}; this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.") - .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build()); + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("topological").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); @@ -35,9 +37,15 @@ namespace storm { this->addOption(storm::settings::OptionBuilder(moduleName, lraMethodOptionName, false, "Sets which method is preferred for computing long run averages.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a long run average computation method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(lraMethods)).setDefaultValueString("vi").build()).build()); + std::vector maMethods = {"imca", "unifplus"}; + this->addOption(storm::settings::OptionBuilder(moduleName, markovAutomatonBoundedReachabilityMethodOptionName, false, "The method to use to solve bounded reachability queries on MAs.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(maMethods)).setDefaultValueString("unifplus").build()).build()); + std::vector multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, valueIterationMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for value iteration.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, intervalIterationSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); + } storm::solver::MinMaxMethod MinMaxEquationSolverSettings::getMinMaxEquationSolvingMethod() const { @@ -48,9 +56,16 @@ namespace storm { return storm::solver::MinMaxMethod::PolicyIteration; } else if (minMaxEquationSolvingTechnique == "linear-programming" || minMaxEquationSolvingTechnique == "lp") { return storm::solver::MinMaxMethod::LinearProgramming; - } else if (minMaxEquationSolvingTechnique == "ratsearch") { + } else if (minMaxEquationSolvingTechnique == "ratsearch" || minMaxEquationSolvingTechnique == "rs") { return storm::solver::MinMaxMethod::RationalSearch; + } else if (minMaxEquationSolvingTechnique == "interval-iteration" || minMaxEquationSolvingTechnique == "ii") { + return storm::solver::MinMaxMethod::IntervalIteration; + } else if (minMaxEquationSolvingTechnique == "sound-value-iteration" || minMaxEquationSolvingTechnique == "svi") { + return storm::solver::MinMaxMethod::SoundValueIteration; + } else if (minMaxEquationSolvingTechnique == "topological") { + return storm::solver::MinMaxMethod::Topological; } + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown min/max equation solving technique '" << minMaxEquationSolvingTechnique << "'."); } @@ -95,6 +110,14 @@ namespace storm { } STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown lra solving technique '" << lraMethodString << "'."); } + + MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod MinMaxEquationSolverSettings::getMarkovAutomatonBoundedReachabilityMethod() const { + std::string techniqueAsString = this->getOption(markovAutomatonBoundedReachabilityMethodOptionName).getArgumentByName("name").getValueAsString(); + if (techniqueAsString == "imca") { + return MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::Imca; + } + return MinMaxEquationSolverSettings::MarkovAutomatonBoundedReachabilityMethod::UnifPlus; + } storm::solver::MultiplicationStyle MinMaxEquationSolverSettings::getValueIterationMultiplicationStyle() const { std::string multiplicationStyleString = this->getOption(valueIterationMultiplicationStyleOptionName).getArgumentByName("name").getValueAsString(); @@ -106,6 +129,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } + bool MinMaxEquationSolverSettings::isForceIntervalIterationSymmetricUpdatesSet() const { + return this->getOption(intervalIterationSymmetricUpdatesOptionName).getHasOptionBeenSet(); + } + } } } diff --git a/src/storm/settings/modules/MinMaxEquationSolverSettings.h b/src/storm/settings/modules/MinMaxEquationSolverSettings.h index bc9697476..43d3d1b00 100644 --- a/src/storm/settings/modules/MinMaxEquationSolverSettings.h +++ b/src/storm/settings/modules/MinMaxEquationSolverSettings.h @@ -18,6 +18,9 @@ namespace storm { // An enumeration of all available convergence criteria. enum class ConvergenceCriterion { Absolute, Relative }; + // An enumeration of all available bounded reachability methods for MAs. + enum class MarkovAutomatonBoundedReachabilityMethod { Imca, UnifPlus }; + MinMaxEquationSolverSettings(); /*! @@ -90,6 +93,13 @@ namespace storm { */ storm::solver::LraMethod getLraMethod() const; + /*! + * Retrieves the method to be used for bounded reachability on MAs. + * + * @return The selected method. + */ + MarkovAutomatonBoundedReachabilityMethod getMarkovAutomatonBoundedReachabilityMethod() const; + /*! * Retrieves the multiplication style to use in the min-max methods. * @@ -97,6 +107,11 @@ namespace storm { */ storm::solver::MultiplicationStyle getValueIterationMultiplicationStyle() const; + /*! + * Retrievew whether updates in interval iteration have to be made symmetrically + */ + bool isForceIntervalIterationSymmetricUpdatesSet() const; + // The name of the module. static const std::string moduleName; @@ -107,7 +122,10 @@ namespace storm { static const std::string precisionOptionName; static const std::string absoluteOptionName; static const std::string lraMethodOptionName; + static const std::string markovAutomatonBoundedReachabilityMethodOptionName; static const std::string valueIterationMultiplicationStyleOptionName; + static const std::string intervalIterationSymmetricUpdatesOptionName; + static const std::string forceBoundsOptionName; }; } diff --git a/src/storm/settings/modules/ModelCheckerSettings.cpp b/src/storm/settings/modules/ModelCheckerSettings.cpp new file mode 100644 index 000000000..9d7646327 --- /dev/null +++ b/src/storm/settings/modules/ModelCheckerSettings.cpp @@ -0,0 +1,28 @@ +#include "storm/settings/modules/ModelCheckerSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/SettingMemento.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" + + +namespace storm { + namespace settings { + namespace modules { + + const std::string ModelCheckerSettings::moduleName = "modelchecker"; + const std::string ModelCheckerSettings::filterRewZeroOptionName = "filterrewzero"; + + ModelCheckerSettings::ModelCheckerSettings() : ModuleSettings(moduleName) { + this->addOption(storm::settings::OptionBuilder(moduleName, filterRewZeroOptionName, false, "If set, states with reward zero are filtered out, potentially reducing the size of the equation system").build()); + } + + bool ModelCheckerSettings::isFilterRewZeroSet() const { + return this->getOption(filterRewZeroOptionName).getHasOptionBeenSet(); + } + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm/settings/modules/ModelCheckerSettings.h b/src/storm/settings/modules/ModelCheckerSettings.h new file mode 100644 index 000000000..4c6a1dfd6 --- /dev/null +++ b/src/storm/settings/modules/ModelCheckerSettings.h @@ -0,0 +1,36 @@ +#pragma once + +#include "storm-config.h" +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/builder/ExplorationOrder.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the general settings. + */ + class ModelCheckerSettings : public ModuleSettings { + public: + + /*! + * Creates a new set of general settings. + */ + ModelCheckerSettings(); + + bool isFilterRewZeroSet() const; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string filterRewZeroOptionName; + }; + + } // namespace modules + } // namespace settings +} // namespace storm + diff --git a/src/storm/settings/modules/MultiplierSettings.cpp b/src/storm/settings/modules/MultiplierSettings.cpp new file mode 100644 index 000000000..d386bbf3a --- /dev/null +++ b/src/storm/settings/modules/MultiplierSettings.cpp @@ -0,0 +1,40 @@ +#include "storm/settings/modules/MultiplierSettings.h" + +#include "storm/settings/Option.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/OptionBuilder.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string MultiplierSettings::moduleName = "multiplier"; + const std::string MultiplierSettings::multiplierTypeOptionName = "type"; + + MultiplierSettings::MultiplierSettings() : ModuleSettings(moduleName) { + std::vector multiplierTypes = {"native", "gmmxx"}; + this->addOption(storm::settings::OptionBuilder(moduleName, multiplierTypeOptionName, true, "Sets which type of multiplier is preferred.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplier.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplierTypes)).setDefaultValueString("gmmxx").build()).build()); + + } + + storm::solver::MultiplierType MultiplierSettings::getMultiplierType() const { + std::string type = this->getOption(multiplierTypeOptionName).getArgumentByName("name").getValueAsString(); + if (type == "native") { + return storm::solver::MultiplierType::Native; + } else if (type == "gmmxx") { + return storm::solver::MultiplierType::Gmmxx; + } + + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplier type '" << type << "'."); + } + + bool MultiplierSettings::isMultiplierTypeSetFromDefaultValue() const { + return !this->getOption(multiplierTypeOptionName).getArgumentByName("name").getHasBeenSet() || this->getOption(multiplierTypeOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + } + } +} diff --git a/src/storm/settings/modules/MultiplierSettings.h b/src/storm/settings/modules/MultiplierSettings.h new file mode 100644 index 000000000..ea5bfdd8c --- /dev/null +++ b/src/storm/settings/modules/MultiplierSettings.h @@ -0,0 +1,34 @@ +#pragma once + +#include "storm-config.h" +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/solver/MultiplicationStyle.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the multiplier settings. + */ + class MultiplierSettings : public ModuleSettings { + public: + + MultiplierSettings(); + + storm::solver::MultiplierType getMultiplierType() const; + + bool isMultiplierTypeSetFromDefaultValue() const; + + // The name of the module. + static const std::string moduleName; + + private: + static const std::string multiplierTypeOptionName; + }; + + } + } +} diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.cpp b/src/storm/settings/modules/NativeEquationSolverSettings.cpp index 664818b97..f96bd8714 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.cpp +++ b/src/storm/settings/modules/NativeEquationSolverSettings.cpp @@ -23,12 +23,13 @@ namespace storm { const std::string NativeEquationSolverSettings::precisionOptionName = "precision"; const std::string NativeEquationSolverSettings::absoluteOptionName = "absolute"; const std::string NativeEquationSolverSettings::powerMethodMultiplicationStyleOptionName = "powmult"; + const std::string NativeEquationSolverSettings::intervalIterationSymmetricUpdatesOptionName = "symmetricupdates"; NativeEquationSolverSettings::NativeEquationSolverSettings() : ModuleSettings(moduleName) { - std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "ratsearch" }; + std::vector methods = { "jacobi", "gaussseidel", "sor", "walkerchae", "power", "sound-value-iteration", "svi", "interval-iteration", "ii", "ratsearch" }; this->addOption(storm::settings::OptionBuilder(moduleName, techniqueOptionName, true, "The method to be used for solving linear equation systems with the native engine.").addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the method to use.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(methods)).setDefaultValueString("jacobi").build()).build()); - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); + this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").build()).build()); this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); @@ -39,6 +40,8 @@ namespace storm { std::vector multiplicationStyles = {"gaussseidel", "regular", "gs", "r"}; this->addOption(storm::settings::OptionBuilder(moduleName, powerMethodMultiplicationStyleOptionName, false, "Sets which method multiplication style to prefer for the power method.") .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a multiplication style.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(multiplicationStyles)).setDefaultValueString("gaussseidel").build()).build()); + + this->addOption(storm::settings::OptionBuilder(moduleName, intervalIterationSymmetricUpdatesOptionName, false, "If set, interval iteration performs an update on both, lower and upper bound in each iteration").build()); } bool NativeEquationSolverSettings::isLinearEquationSystemTechniqueSet() const { @@ -61,6 +64,10 @@ namespace storm { return storm::solver::NativeLinearEquationSolverMethod::WalkerChae; } else if (linearEquationSystemTechniqueAsString == "power") { return storm::solver::NativeLinearEquationSolverMethod::Power; + } else if (linearEquationSystemTechniqueAsString == "sound-value-iteration" || linearEquationSystemTechniqueAsString == "svi") { + return storm::solver::NativeLinearEquationSolverMethod::SoundValueIteration; + } else if (linearEquationSystemTechniqueAsString == "interval-iteration" || linearEquationSystemTechniqueAsString == "ii") { + return storm::solver::NativeLinearEquationSolverMethod::IntervalIteration; } else if (linearEquationSystemTechniqueAsString == "ratsearch") { return storm::solver::NativeLinearEquationSolverMethod::RationalSearch; } @@ -105,6 +112,10 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown multiplication style '" << multiplicationStyleString << "'."); } + bool NativeEquationSolverSettings::isForceIntervalIterationSymmetricUpdatesSet() const { + return this->getOption(intervalIterationSymmetricUpdatesOptionName).getHasOptionBeenSet(); + } + bool NativeEquationSolverSettings::check() const { // This list does not include the precision, because this option is shared with other modules. bool optionSet = isLinearEquationSystemTechniqueSet() || isMaximalIterationCountSet() || isConvergenceCriterionSet(); diff --git a/src/storm/settings/modules/NativeEquationSolverSettings.h b/src/storm/settings/modules/NativeEquationSolverSettings.h index 32d3caed1..306e9750e 100644 --- a/src/storm/settings/modules/NativeEquationSolverSettings.h +++ b/src/storm/settings/modules/NativeEquationSolverSettings.h @@ -93,6 +93,11 @@ namespace storm { */ ConvergenceCriterion getConvergenceCriterion() const; + /*! + * Retrievew whether updates in interval iteration have to be made symmetrically + */ + bool isForceIntervalIterationSymmetricUpdatesSet() const; + /*! * Retrieves the multiplication style to use in the power method. * @@ -100,6 +105,11 @@ namespace storm { */ storm::solver::MultiplicationStyle getPowerMethodMultiplicationStyle() const; + /*! + * Retrieves whether the force bounds option has been set. + */ + bool isForceBoundsSet() const; + bool check() const override; // The name of the module. @@ -113,7 +123,10 @@ namespace storm { static const std::string maximalIterationsOptionShortName; static const std::string precisionOptionName; static const std::string absoluteOptionName; + static const std::string intervalIterationSymmetricUpdatesOptionName; static const std::string powerMethodMultiplicationStyleOptionName; + static const std::string forceBoundsOptionName; + }; } // namespace modules diff --git a/src/storm/settings/modules/SylvanSettings.h b/src/storm/settings/modules/SylvanSettings.h index b4eed806b..b218cbdfc 100644 --- a/src/storm/settings/modules/SylvanSettings.h +++ b/src/storm/settings/modules/SylvanSettings.h @@ -13,7 +13,7 @@ namespace storm { class SylvanSettings : public ModuleSettings { public: /*! - * Creates a new set of CUDD settings. + * Creates a new set of Sylvan settings. */ SylvanSettings(); diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp new file mode 100644 index 000000000..88a0c48fd --- /dev/null +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.cpp @@ -0,0 +1,105 @@ +#include "storm/settings/modules/TopologicalEquationSolverSettings.h" + + +#include "storm/settings/modules/CoreSettings.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/SettingMemento.h" +#include "storm/settings/Option.h" +#include "storm/settings/OptionBuilder.h" +#include "storm/settings/ArgumentBuilder.h" +#include "storm/settings/Argument.h" +#include "storm/solver/SolverSelectionOptions.h" + +#include "storm/storage/dd/DdType.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/IllegalArgumentValueException.h" +#include "storm/exceptions/InvalidOptionException.h" + +namespace storm { + namespace settings { + namespace modules { + + const std::string TopologicalEquationSolverSettings::moduleName = "topological"; + const std::string TopologicalEquationSolverSettings::underlyingEquationSolverOptionName = "eqsolver"; + const std::string TopologicalEquationSolverSettings::underlyingMinMaxMethodOptionName = "minmax"; + + TopologicalEquationSolverSettings::TopologicalEquationSolverSettings() : ModuleSettings(moduleName) { + std::vector linearEquationSolver = {"gmm++", "native", "eigen", "elimination"}; + this->addOption(storm::settings::OptionBuilder(moduleName, underlyingEquationSolverOptionName, true, "Sets which solver is considered for solving the underlying equation systems.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used solver.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(linearEquationSolver)).setDefaultValueString("gmm++").build()).build()); + std::vector minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "lp", "linear-programming", "rs", "ratsearch", "ii", "interval-iteration", "svi", "sound-value-iteration"}; + this->addOption(storm::settings::OptionBuilder(moduleName, underlyingMinMaxMethodOptionName, true, "Sets which minmax method is considered for solving the underlying minmax equation systems.") + .addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of the used min max method.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("value-iteration").build()).build()); + } + + bool TopologicalEquationSolverSettings::isUnderlyingEquationSolverTypeSet() const { + return this->getOption(underlyingEquationSolverOptionName).getHasOptionBeenSet(); + } + + bool TopologicalEquationSolverSettings::isUnderlyingEquationSolverTypeSetFromDefaultValue() const { + return !this->getOption(underlyingEquationSolverOptionName).getHasOptionBeenSet() || this->getOption(underlyingEquationSolverOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + + storm::solver::EquationSolverType TopologicalEquationSolverSettings::getUnderlyingEquationSolverType() const { + std::string equationSolverName = this->getOption(underlyingEquationSolverOptionName).getArgumentByName("name").getValueAsString(); + if (equationSolverName == "gmm++") { + return storm::solver::EquationSolverType::Gmmxx; + } else if (equationSolverName == "native") { + return storm::solver::EquationSolverType::Native; + } else if (equationSolverName == "eigen") { + return storm::solver::EquationSolverType::Eigen; + } else if (equationSolverName == "elimination") { + return storm::solver::EquationSolverType::Elimination; + } + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << equationSolverName << "'."); + } + + bool TopologicalEquationSolverSettings::isUnderlyingMinMaxMethodSet() const { + return this->getOption(underlyingMinMaxMethodOptionName).getHasOptionBeenSet(); + } + + bool TopologicalEquationSolverSettings::isUnderlyingMinMaxMethodSetFromDefaultValue() const { + return !this->getOption(underlyingMinMaxMethodOptionName).getHasOptionBeenSet() || this->getOption(underlyingMinMaxMethodOptionName).getArgumentByName("name").wasSetFromDefaultValue(); + } + + storm::solver::MinMaxMethod TopologicalEquationSolverSettings::getUnderlyingMinMaxMethod() const { + std::string minMaxEquationSolvingTechnique = this->getOption(underlyingMinMaxMethodOptionName).getArgumentByName("name").getValueAsString(); + if (minMaxEquationSolvingTechnique == "value-iteration" || minMaxEquationSolvingTechnique == "vi") { + return storm::solver::MinMaxMethod::ValueIteration; + } else if (minMaxEquationSolvingTechnique == "policy-iteration" || minMaxEquationSolvingTechnique == "pi") { + return storm::solver::MinMaxMethod::PolicyIteration; + } else if (minMaxEquationSolvingTechnique == "linear-programming" || minMaxEquationSolvingTechnique == "lp") { + return storm::solver::MinMaxMethod::LinearProgramming; + } else if (minMaxEquationSolvingTechnique == "ratsearch" || minMaxEquationSolvingTechnique == "rs") { + return storm::solver::MinMaxMethod::RationalSearch; + } else if (minMaxEquationSolvingTechnique == "interval-iteration" || minMaxEquationSolvingTechnique == "ii") { + return storm::solver::MinMaxMethod::IntervalIteration; + } else if (minMaxEquationSolvingTechnique == "sound-value-iteration" || minMaxEquationSolvingTechnique == "svi") { + return storm::solver::MinMaxMethod::SoundValueIteration; + } + + + + + STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown underlying equation solver '" << minMaxEquationSolvingTechnique << "'."); + } + + bool TopologicalEquationSolverSettings::check() const { + if (this->isUnderlyingEquationSolverTypeSet() && getUnderlyingEquationSolverType() == storm::solver::EquationSolverType::Topological) { + STORM_LOG_WARN("Underlying solver type of the topological solver can not be the topological solver."); + return false; + } + if (this->isUnderlyingMinMaxMethodSet() && getUnderlyingMinMaxMethod() == storm::solver::MinMaxMethod::Topological) { + STORM_LOG_WARN("Underlying minmax method of the topological solver can not be topological."); + return false; + } + return true; + } + + } // namespace modules + } // namespace settings +} // namespace storm + + diff --git a/src/storm/settings/modules/TopologicalEquationSolverSettings.h b/src/storm/settings/modules/TopologicalEquationSolverSettings.h new file mode 100644 index 000000000..f9ddefd78 --- /dev/null +++ b/src/storm/settings/modules/TopologicalEquationSolverSettings.h @@ -0,0 +1,77 @@ +#pragma once + +#include "storm/settings/modules/ModuleSettings.h" + +#include "storm/solver/SolverSelectionOptions.h" + +namespace storm { + namespace settings { + namespace modules { + + /*! + * This class represents the settings for the native equation solver. + */ + class TopologicalEquationSolverSettings : public ModuleSettings { + public: + + /*! + * Creates a new set of native equation solver settings. + */ + TopologicalEquationSolverSettings(); + + /*! + * Retrieves whether the underlying equation solver type has been set. + * + * @return True iff the linear equation system technique has been set. + */ + bool isUnderlyingEquationSolverTypeSet() const; + + /*! + * Retrieves whether the underlying equation solver type is set from its default value. + * + * @return True iff it was set from its default value. + */ + bool isUnderlyingEquationSolverTypeSetFromDefaultValue() const; + + /*! + * Retrieves the method that is to be used for solving systems of linear equations. + * + * @return The method to use. + */ + storm::solver::EquationSolverType getUnderlyingEquationSolverType() const; + + /*! + * Retrieves whether the underlying equation solver type has been set. + * + * @return True iff the linear equation system technique has been set. + */ + bool isUnderlyingMinMaxMethodSet() const; + + /*! + * Retrieves whether the underlying minmax method is set from its default value. + * + * @return True iff it was set from its default value. + */ + bool isUnderlyingMinMaxMethodSetFromDefaultValue() const; + + /*! + * Retrieves the method that is to be used for solving systems of linear equations. + * + * @return The method to use. + */ + storm::solver::MinMaxMethod getUnderlyingMinMaxMethod() const; + + bool check() const override; + + // The name of the module. + static const std::string moduleName; + + private: + // Define the string names of the options as constants. + static const std::string underlyingEquationSolverOptionName; + static const std::string underlyingMinMaxMethodOptionName; + }; + + } // namespace modules + } // namespace settings +} // namespace storm diff --git a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp b/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp deleted file mode 100644 index ead40d320..000000000 --- a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h" - -#include "storm/settings/Option.h" -#include "storm/settings/OptionBuilder.h" -#include "storm/settings/ArgumentBuilder.h" -#include "storm/settings/Argument.h" - -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/GeneralSettings.h" -#include "storm/solver/SolverSelectionOptions.h" - -namespace storm { - namespace settings { - namespace modules { - - const std::string TopologicalValueIterationEquationSolverSettings::moduleName = "topologicalValueIteration"; - const std::string TopologicalValueIterationEquationSolverSettings::maximalIterationsOptionName = "maxiter"; - const std::string TopologicalValueIterationEquationSolverSettings::maximalIterationsOptionShortName = "i"; - const std::string TopologicalValueIterationEquationSolverSettings::precisionOptionName = "precision"; - const std::string TopologicalValueIterationEquationSolverSettings::absoluteOptionName = "absolute"; - - TopologicalValueIterationEquationSolverSettings::TopologicalValueIterationEquationSolverSettings() : ModuleSettings(moduleName) { - - this->addOption(storm::settings::OptionBuilder(moduleName, maximalIterationsOptionName, false, "The maximal number of iterations to perform before iterative solving is aborted.").setShortName(maximalIterationsOptionShortName).addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("count", "The maximal iteration count.").setDefaultValueUnsignedInteger(20000).build()).build()); - - this->addOption(storm::settings::OptionBuilder(moduleName, precisionOptionName, false, "The precision used for detecting convergence of iterative methods.").addArgument(storm::settings::ArgumentBuilder::createDoubleArgument("value", "The precision to achieve.").setDefaultValueDouble(1e-06).addValidatorDouble(ArgumentValidatorFactory::createDoubleRangeValidatorExcluding(0.0, 1.0)).build()).build()); - - this->addOption(storm::settings::OptionBuilder(moduleName, absoluteOptionName, false, "Sets whether the relative or the absolute error is considered for detecting convergence.").build()); - } - - bool TopologicalValueIterationEquationSolverSettings::isMaximalIterationCountSet() const { - return this->getOption(maximalIterationsOptionName).getHasOptionBeenSet(); - } - - uint_fast64_t TopologicalValueIterationEquationSolverSettings::getMaximalIterationCount() const { - return this->getOption(maximalIterationsOptionName).getArgumentByName("count").getValueAsUnsignedInteger(); - } - - bool TopologicalValueIterationEquationSolverSettings::isPrecisionSet() const { - return this->getOption(precisionOptionName).getHasOptionBeenSet(); - } - - double TopologicalValueIterationEquationSolverSettings::getPrecision() const { - return this->getOption(precisionOptionName).getArgumentByName("value").getValueAsDouble(); - } - - bool TopologicalValueIterationEquationSolverSettings::isConvergenceCriterionSet() const { - return this->getOption(absoluteOptionName).getHasOptionBeenSet(); - } - - TopologicalValueIterationEquationSolverSettings::ConvergenceCriterion TopologicalValueIterationEquationSolverSettings::getConvergenceCriterion() const { - return this->getOption(absoluteOptionName).getHasOptionBeenSet() ? TopologicalValueIterationEquationSolverSettings::ConvergenceCriterion::Absolute : TopologicalValueIterationEquationSolverSettings::ConvergenceCriterion::Relative; - } - - bool TopologicalValueIterationEquationSolverSettings::check() const { - return true; - } - - } // namespace modules - } // namespace settings -} // namespace storm diff --git a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h b/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h deleted file mode 100644 index 21006c3bd..000000000 --- a/src/storm/settings/modules/TopologicalValueIterationEquationSolverSettings.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef STORM_SETTINGS_MODULES_TOPOLOGICALVALUEITERATIONSETTINGS_H_ -#define STORM_SETTINGS_MODULES_TOPOLOGICALVALUEITERATIONSETTINGS_H_ - -#include "storm/settings/modules/ModuleSettings.h" - -namespace storm { - namespace settings { - namespace modules { - - /*! - * This class represents the settings for topological value iteration. - */ - class TopologicalValueIterationEquationSolverSettings : public ModuleSettings { - public: - - // An enumeration of all available convergence criteria. - enum class ConvergenceCriterion { Absolute, Relative }; - - /*! - * Creates a new set of topological value iteration settings. - */ - TopologicalValueIterationEquationSolverSettings(); - - - /*! - * Retrieves whether the maximal iteration count has been set. - * - * @return True iff the maximal iteration count has been set. - */ - bool isMaximalIterationCountSet() const; - - /*! - * Retrieves the maximal number of iterations to perform until giving up on converging. - * - * @return The maximal iteration count. - */ - uint_fast64_t getMaximalIterationCount() const; - - /*! - * Retrieves whether the precision has been set. - * - * @return True iff the precision has been set. - */ - bool isPrecisionSet() const; - - /*! - * Retrieves the precision that is used for detecting convergence. - * - * @return The precision to use for detecting convergence. - */ - double getPrecision() const; - - /*! - * Retrieves whether the convergence criterion has been set. - * - * @return True iff the convergence criterion has been set. - */ - bool isConvergenceCriterionSet() const; - - /*! - * Retrieves the selected convergence criterion. - * - * @return The selected convergence criterion. - */ - ConvergenceCriterion getConvergenceCriterion() const; - - bool check() const override; - - // The name of the module. - static const std::string moduleName; - - private: - // Define the string names of the options as constants. - static const std::string techniqueOptionName; - static const std::string maximalIterationsOptionName; - static const std::string maximalIterationsOptionShortName; - static const std::string precisionOptionName; - static const std::string absoluteOptionName; - }; - - } // namespace modules - } // namespace settings -} // namespace storm - -#endif /* STORM_SETTINGS_MODULES_TOPOLOGICALVALUEITERATIONSETTINGS_H_ */ diff --git a/src/storm/solver/AbstractEquationSolver.cpp b/src/storm/solver/AbstractEquationSolver.cpp index d17a9041d..69a2d0fad 100644 --- a/src/storm/solver/AbstractEquationSolver.cpp +++ b/src/storm/solver/AbstractEquationSolver.cpp @@ -9,6 +9,7 @@ #include "storm/utility/constants.h" #include "storm/utility/macros.h" #include "storm/exceptions/UnmetRequirementException.h" +#include "storm/exceptions/InvalidOperationException.h" namespace storm { namespace solver { @@ -119,10 +120,33 @@ namespace storm { return lowerBound.get(); } + template + ValueType AbstractEquationSolver::getLowerBound(bool convertLocalBounds) const { + if (lowerBound) { + return lowerBound.get(); + } else if (convertLocalBounds) { + return *std::min_element(lowerBounds->begin(), lowerBounds->end()); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "No lower bound available but some was requested."); + return ValueType(); + } + template ValueType const& AbstractEquationSolver::getUpperBound() const { return upperBound.get(); } + + template + ValueType AbstractEquationSolver::getUpperBound(bool convertLocalBounds) const { + if (upperBound) { + return upperBound.get(); + } else if (convertLocalBounds) { + return *std::max_element(upperBounds->begin(), upperBounds->end()); + } + STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "No upper bound available but some was requested."); + return ValueType(); + } + template std::vector const& AbstractEquationSolver::getLowerBounds() const { @@ -249,11 +273,6 @@ namespace storm { } } - template - void AbstractEquationSolver::setPrecision(ValueType const& precision) { - STORM_LOG_DEBUG("Setting solver precision for a solver that does not support precisions."); - } - template class AbstractEquationSolver; template class AbstractEquationSolver; diff --git a/src/storm/solver/AbstractEquationSolver.h b/src/storm/solver/AbstractEquationSolver.h index d5000f8c7..9f9efb411 100644 --- a/src/storm/solver/AbstractEquationSolver.h +++ b/src/storm/solver/AbstractEquationSolver.h @@ -3,7 +3,7 @@ #include #include - +#include #include #include "storm/solver/TerminationCondition.h" @@ -97,11 +97,25 @@ namespace storm { */ ValueType const& getLowerBound() const; + /*! + * Retrieves the lower bound (if there is any). + * If the given flag is true and if there are only local bounds, + * the minimum of the local bounds is returned. + */ + ValueType getLowerBound(bool convertLocalBounds) const; + /*! * Retrieves the upper bound (if there is any). */ ValueType const& getUpperBound() const; + /*! + * Retrieves the upper bound (if there is any). + * If the given flag is true and if there are only local bounds, + * the maximum of the local bounds is returned. + */ + ValueType getUpperBound(bool convertLocalBounds) const; + /*! * Retrieves a vector containing the lower bounds (if there are any). */ @@ -163,8 +177,6 @@ namespace storm { * Shows progress if this solver is asked to do so. */ void showProgressIterative(uint64_t iterations, boost::optional const& bound = boost::none) const; - - virtual void setPrecision(ValueType const& precision); protected: /*! diff --git a/src/storm/solver/EigenLinearEquationSolver.cpp b/src/storm/solver/EigenLinearEquationSolver.cpp index 874d6f4c4..6c96715cf 100644 --- a/src/storm/solver/EigenLinearEquationSolver.cpp +++ b/src/storm/solver/EigenLinearEquationSolver.cpp @@ -116,7 +116,10 @@ namespace storm { } else { bool converged = false; uint64_t numberOfIterations = 0; - uint64_t maxIter = env.solver().eigen().getMaximalNumberOfIterations(); + StormEigen::Index maxIter = std::numeric_limits::max(); + if (env.solver().eigen().getMaximalNumberOfIterations() < static_cast(maxIter)) { + maxIter = env.solver().eigen().getMaximalNumberOfIterations(); + } uint64_t restartThreshold = env.solver().eigen().getRestartThreshold(); ValueType precision = storm::utility::convertNumber(env.solver().eigen().getPrecision()); EigenLinearEquationSolverPreconditioner preconditioner = env.solver().eigen().getPreconditioner(); @@ -241,35 +244,7 @@ namespace storm { } template - void EigenLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - // Typedef the map-type so we don't have to spell it out. - typedef decltype(StormEigen::Matrix::Map(b->data(), b->size())) MapType; - - auto eigenX = StormEigen::Matrix::Map(x.data(), x.size()); - auto eigenResult = StormEigen::Matrix::Map(result.data(), result.size()); - - std::unique_ptr eigenB; - if (b != nullptr) { - eigenB = std::make_unique(StormEigen::Matrix::Map(b->data(), b->size())); - } - - if (&x != &result) { - if (b != nullptr) { - eigenResult.noalias() = *eigenA * eigenX + *eigenB; - } else { - eigenResult.noalias() = *eigenA * eigenX; - } - } else { - if (b != nullptr) { - eigenResult = *eigenA * eigenX + *eigenB; - } else { - eigenResult = *eigenA * eigenX; - } - } - } - - template - LinearEquationSolverProblemFormat EigenLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { + LinearEquationSolverProblemFormat EigenLinearEquationSolver::getEquationProblemFormat(Environment const&) const { return LinearEquationSolverProblemFormat::EquationSystem; } @@ -284,7 +259,7 @@ namespace storm { } template - std::unique_ptr> EigenLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> EigenLinearEquationSolverFactory::create(Environment const&) const { return std::make_unique>(); } diff --git a/src/storm/solver/EigenLinearEquationSolver.h b/src/storm/solver/EigenLinearEquationSolver.h index a6bbae91a..63768563a 100644 --- a/src/storm/solver/EigenLinearEquationSolver.h +++ b/src/storm/solver/EigenLinearEquationSolver.h @@ -20,8 +20,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; protected: @@ -43,7 +41,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; }; diff --git a/src/storm/solver/EliminationLinearEquationSolver.cpp b/src/storm/solver/EliminationLinearEquationSolver.cpp index 3e84b7f0c..2873c04c4 100644 --- a/src/storm/solver/EliminationLinearEquationSolver.cpp +++ b/src/storm/solver/EliminationLinearEquationSolver.cpp @@ -93,23 +93,6 @@ namespace storm { return true; } - template - void EliminationLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - if (&x != &result) { - A->multiplyWithVector(x, result); - if (b != nullptr) { - storm::utility::vector::addVectors(result, *b, result); - } - } else { - // If the two vectors are aliases, we need to create a temporary. - std::vector tmp(result.size()); - A->multiplyWithVector(x, tmp); - if (b != nullptr) { - storm::utility::vector::addVectors(tmp, *b, result); - } - } - } - template LinearEquationSolverProblemFormat EliminationLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::FixedPointSystem; @@ -126,7 +109,7 @@ namespace storm { } template - std::unique_ptr> EliminationLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> EliminationLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/EliminationLinearEquationSolver.h b/src/storm/solver/EliminationLinearEquationSolver.h index 60403336e..d3c3f5992 100644 --- a/src/storm/solver/EliminationLinearEquationSolver.h +++ b/src/storm/solver/EliminationLinearEquationSolver.h @@ -21,8 +21,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; protected: @@ -46,7 +44,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; diff --git a/src/storm/solver/GameSolver.cpp b/src/storm/solver/GameSolver.cpp index 9c3e5ad8e..f5ccce0ad 100644 --- a/src/storm/solver/GameSolver.cpp +++ b/src/storm/solver/GameSolver.cpp @@ -10,7 +10,7 @@ namespace storm { namespace solver { template - GameSolver::GameSolver() : trackSchedulers(false), cachingEnabled(false) { + GameSolver::GameSolver() : trackSchedulers(false), uniqueSolution(false), cachingEnabled(false) { // Intentionally left empty } @@ -99,6 +99,16 @@ namespace storm { // Intentionally left empty. } + template + void GameSolver::setHasUniqueSolution(bool value) { + this->uniqueSolution = value; + } + + template + bool GameSolver::hasUniqueSolution() const { + return this->uniqueSolution; + } + template GameSolverFactory::GameSolverFactory() { // Intentionally left empty. @@ -114,6 +124,16 @@ namespace storm { return std::make_unique>(std::move(player1Matrix), std::move(player2Matrix), std::make_unique>()); } + template + std::unique_ptr> GameSolverFactory::create(Environment const& env, std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix) const { + return std::make_unique>(player1Grouping, player2Matrix, std::make_unique>()); + } + + template + std::unique_ptr> GameSolverFactory::create(Environment const& env, std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix) const { + return std::make_unique>(std::move(player1Grouping), std::move(player2Matrix), std::make_unique>()); + } + template class GameSolver; template class GameSolver; diff --git a/src/storm/solver/GameSolver.h b/src/storm/solver/GameSolver.h index fd9e63667..68f7c3559 100644 --- a/src/storm/solver/GameSolver.h +++ b/src/storm/solver/GameSolver.h @@ -39,8 +39,12 @@ namespace storm { * @param player2Dir Sets whether player 2 wants to minimize or maximize. * @param x The initial guess of the solution. For correctness, the guess has to be less (or equal) to the final solution (unless both players minimize) * @param b The vector to add after matrix-vector multiplication. + * @param player1Choices If provided along with the storage for player 2 choices, the scheduler decisions + * are tracked within these two vectors. + * @param player2Choices If provided along with the storage for player 1 choices, the scheduler decisions + * are tracked within these two vectors. */ - virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const = 0; + virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const = 0; /*! * Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes @@ -111,6 +115,16 @@ namespace storm { * Clears the currently cached data that has been stored during previous calls of the solver. */ virtual void clearCache() const; + + /*! + * Sets whether the solution to the min max equation system is known to be unique. + */ + void setHasUniqueSolution(bool value = true); + + /*! + * Retrieves whether the solution to the min max equation system is assumed to be unique + */ + bool hasUniqueSolution() const; protected: @@ -128,9 +142,11 @@ namespace storm { boost::optional> player2ChoicesHint; private: + /// Whether the solver can assume that the min-max equation system has a unique solution + bool uniqueSolution; + /// Whether some of the generated data during solver calls should be cached. bool cachingEnabled; - }; template @@ -142,9 +158,8 @@ namespace storm { virtual std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix) const; virtual std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix) const; - private: - bool trackScheduler; - + virtual std::unique_ptr> create(Environment const& env, std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix) const; + virtual std::unique_ptr> create(Environment const& env, std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix) const; }; } // namespace solver diff --git a/src/storm/solver/GmmxxLinearEquationSolver.cpp b/src/storm/solver/GmmxxLinearEquationSolver.cpp index 0f517d5a9..9ce51fa72 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.cpp +++ b/src/storm/solver/GmmxxLinearEquationSolver.cpp @@ -5,7 +5,6 @@ #include "storm/adapters/GmmxxAdapter.h" -#include "storm/solver/GmmxxMultiplier.h" #include "storm/environment/solver/GmmxxSolverEnvironment.h" #include "storm/utility/vector.h" @@ -66,7 +65,11 @@ namespace storm { } // Prepare an iteration object that determines the accuracy and the maximum number of iterations. - gmm::iteration iter(storm::utility::convertNumber(env.solver().gmmxx().getPrecision()), 0, env.solver().gmmxx().getMaximalNumberOfIterations()); + gmm::size_type maxIter = std::numeric_limits::max(); + if (env.solver().gmmxx().getMaximalNumberOfIterations() < static_cast(maxIter)) { + maxIter = env.solver().gmmxx().getMaximalNumberOfIterations(); + } + gmm::iteration iter(storm::utility::convertNumber(env.solver().gmmxx().getPrecision()), 0, maxIter); // Invoke gmm with the corresponding settings if (method == GmmxxLinearEquationSolverMethod::Bicgstab) { @@ -104,10 +107,10 @@ namespace storm { // Check if the solver converged and issue a warning otherwise. if (iter.converged()) { - STORM_LOG_INFO("Iterative solver converged after " << iter.get_iteration() << " iterations."); + STORM_LOG_INFO("Iterative solver converged after " << iter.get_iteration() << " iteration(s)."); return true; } else { - STORM_LOG_WARN("Iterative solver did not converge."); + STORM_LOG_WARN("Iterative solver did not converge within " << iter.get_iteration() << " iteration(s)."); return false; } } @@ -116,35 +119,6 @@ namespace storm { return false; } - template - void GmmxxLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - multiplier.multAdd(*gmmxxA, x, b, result); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - - template - void GmmxxLinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - multiplier.multAddReduce(dir, rowGroupIndices, *gmmxxA, x, b, result, choices); - } - - template - bool GmmxxLinearEquationSolver::supportsGaussSeidelMultiplication() const { - return true; - } - - template - void GmmxxLinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - multiplier.multAddGaussSeidelBackward(*gmmxxA, x, b); - } - - template - void GmmxxLinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - multiplier.multAddReduceGaussSeidel(dir, rowGroupIndices, *gmmxxA, x, b, choices); - } - template LinearEquationSolverProblemFormat GmmxxLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { return LinearEquationSolverProblemFormat::EquationSystem; @@ -168,7 +142,7 @@ namespace storm { } template - std::unique_ptr> GmmxxLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GmmxxLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/GmmxxLinearEquationSolver.h b/src/storm/solver/GmmxxLinearEquationSolver.h index bb08cf007..f288e9f58 100644 --- a/src/storm/solver/GmmxxLinearEquationSolver.h +++ b/src/storm/solver/GmmxxLinearEquationSolver.h @@ -5,10 +5,8 @@ #include "storm/utility/gmm.h" -#include "storm/solver/GmmxxMultiplier.h" - #include "storm/solver/LinearEquationSolver.h" -#include "SolverSelectionOptions.h" +#include "storm/solver/SolverSelectionOptions.h" namespace storm { namespace solver { @@ -27,12 +25,6 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual bool supportsGaussSeidelMultiplication() const override; - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const& env) const override; virtual void clearCache() const override; @@ -50,9 +42,6 @@ namespace storm { // The matrix in gmm++ format. std::unique_ptr> gmmxxA; - // A multiplier object used to dispatch the multiplication calls. - GmmxxMultiplier multiplier; - // cached data obtained during solving mutable std::unique_ptr>> iluPreconditioner; mutable std::unique_ptr>> diagonalPreconditioner; @@ -63,7 +52,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; diff --git a/src/storm/solver/GmmxxMultiplier.cpp b/src/storm/solver/GmmxxMultiplier.cpp index b05ef8bcc..95abf61fb 100644 --- a/src/storm/solver/GmmxxMultiplier.cpp +++ b/src/storm/solver/GmmxxMultiplier.cpp @@ -2,6 +2,9 @@ #include "storm/adapters/RationalNumberAdapter.h" #include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" #include "storm/utility/constants.h" #include "storm/exceptions/NotSupportedException.h" @@ -11,60 +14,124 @@ namespace storm { namespace solver { - template - GmmxxMultiplier::GmmxxMultiplier() : storm::utility::VectorHelper() { + template + GmmxxMultiplier::GmmxxMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { // Intentionally left empty. } - template - void GmmxxMultiplier::multAdd(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { - if (this->parallelize()) { - multAddParallel(matrix, x, b, result); - } else { - if (b) { - gmm::mult_add(matrix, x, *b, result); + template + void GmmxxMultiplier::initialize() const { + if (gmmMatrix.nrows() == 0) { + gmmMatrix = std::move(*storm::adapters::GmmxxAdapter().toGmmxxSparseMatrix(this->matrix)); + } + } + + template + void GmmxxMultiplier::clearCache() const { + gmmMatrix = gmm::csr_matrix(); + Multiplier::clearCache(); + } + + template + bool GmmxxMultiplier::parallelize(Environment const& env) const { +#ifdef STORM_HAVE_INTELTBB + return storm::settings::getModule().isUseIntelTbbSet(); +#else + return false; +#endif + } + + template + void GmmxxMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { + initialize(); + std::vector* target = &result; + if (&x == &result) { + if (this->cachedVector) { + this->cachedVector->resize(x.size()); } else { - gmm::mult(matrix, x, result); + this->cachedVector = std::make_unique>(x.size()); } + target = this->cachedVector.get(); + } + if (parallelize(env)) { + multAddParallel(x, b, *target); + } else { + multAdd(x, b, *target); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); } } - template - void GmmxxMultiplier::multAddGaussSeidelBackward(gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b) const { - STORM_LOG_ASSERT(matrix.nr == matrix.nc, "Expecting square matrix."); + template + void GmmxxMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { + initialize(); + STORM_LOG_ASSERT(gmmMatrix.nr == gmmMatrix.nc, "Expecting square matrix."); if (b) { - gmm::mult_add_by_row_bwd(matrix, x, *b, x, gmm::abstract_dense()); + gmm::mult_add_by_row_bwd(gmmMatrix, x, *b, x, gmm::abstract_dense()); } else { - gmm::mult_by_row_bwd(matrix, x, x, gmm::abstract_dense()); + gmm::mult_by_row_bwd(gmmMatrix, x, x, gmm::abstract_dense()); } } - template - void GmmxxMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - std::vector* target = &result; - std::unique_ptr> temporary; + template + void GmmxxMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + initialize(); + std::vector* target = &result; if (&x == &result) { - STORM_LOG_WARN("Using temporary in 'multAddReduce'."); - temporary = std::make_unique>(x.size()); - target = temporary.get(); + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); } - - if (this->parallelize()) { - multAddReduceParallel(dir, rowGroupIndices, matrix, x, b, *target, choices); + if (parallelize(env)) { + multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); } else { - multAddReduceHelper(dir, rowGroupIndices, matrix, x, b, *target, choices); + multAddReduceHelper(dir, rowGroupIndices, x, b, *target, choices); + } + if (&x == &result) { + std::swap(result, *this->cachedVector); } } - template - void GmmxxMultiplier::multAddReduceGaussSeidel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices) const { - multAddReduceHelper(dir, rowGroupIndices, matrix, x, b, x, choices); + template + void GmmxxMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + initialize(); + multAddReduceHelper(dir, rowGroupIndices, x, b, x, choices); } - template - void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { - typedef std::vector VectorType; - typedef gmm::csr_matrix MatrixType; + template + void GmmxxMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { + initialize(); + value += vect_sp(gmm::mat_const_row(gmmMatrix, rowIndex), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); + } + + template + void GmmxxMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + if (b) { + gmm::mult_add(gmmMatrix, x, *b, result); + } else { + gmm::mult(gmmMatrix, x, result); + } + } + + template + void GmmxxMultiplier::multAddReduceHelper(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + if (dir == storm::OptimizationDirection::Minimize) { + multAddReduceHelper>(rowGroupIndices, x, b, result, choices); + } else { + multAddReduceHelper>(rowGroupIndices, x, b, result, choices); + } + } + + template + template + void GmmxxMultiplier::multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + Compare compare; + typedef std::vector VectorType; + typedef gmm::csr_matrix MatrixType; typename gmm::linalg_traits::const_iterator add_it, add_ite; if (b) { @@ -72,19 +139,19 @@ namespace storm { add_ite = gmm::vect_begin(*b) - 1; } typename gmm::linalg_traits::iterator target_it = gmm::vect_end(result) - 1; - typename gmm::linalg_traits::const_row_iterator itr = mat_row_const_end(matrix) - 1; + typename gmm::linalg_traits::const_row_iterator itr = mat_row_const_end(gmmMatrix) - 1; typename std::vector::iterator choice_it; if (choices) { choice_it = choices->end() - 1; } - - uint64_t choice; - for (auto row_group_it = rowGroupIndices.end() - 2, row_group_ite = rowGroupIndices.begin() - 1; row_group_it != row_group_ite; --row_group_it, --choice_it, --target_it) { - if (choices) { - *choice_it = 0; - } - T currentValue = storm::utility::zero(); + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = gmmMatrix.nrows() - 1; + for (auto row_group_it = rowGroupIndices.end() - 2, row_group_ite = rowGroupIndices.begin() - 1; row_group_it != row_group_ite; --row_group_it, --choice_it, --target_it) { + ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if the row group is not empty. if (*row_group_it != *(row_group_it + 1)) { @@ -94,71 +161,79 @@ namespace storm { } currentValue += vect_sp(gmm::linalg_traits::row(itr), x); - + if (choices) { - choice = *(row_group_it + 1) - 1 - *row_group_it; - *choice_it = choice; + selectedChoice = currentRow - *row_group_it; + if (*choice_it == selectedChoice) { + oldSelectedChoiceValue = currentValue; + } } - + --itr; + --currentRow; - for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, --itr, --add_it) { - T newValue = b ? *add_it : storm::utility::zero(); + for (uint64_t row = *row_group_it + 1, rowEnd = *(row_group_it + 1); row < rowEnd; ++row, --currentRow, --itr, --add_it) { + ValueType newValue = b ? *add_it : storm::utility::zero(); newValue += vect_sp(gmm::linalg_traits::row(itr), x); - if (choices) { - --choice; + if (choices && currentRow == *choice_it + *row_group_it) { + oldSelectedChoiceValue = newValue; } - - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { - *choice_it = choice; + selectedChoice = currentRow - *row_group_it; } } } - } else if (choices) { - *choice_it = 0; + + // Finally write value to target vector. + *target_it = currentValue; + if (choices && compare(currentValue, oldSelectedChoiceValue)) { + *choice_it = selectedChoice; + } } - - // Write back final value. - *target_it = currentValue; } } template<> - void GmmxxMultiplier::multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void GmmxxMultiplier::multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported for this data type."); } - template - void GmmxxMultiplier::multAddParallel(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { + template + void GmmxxMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB if (b) { - gmm::mult_add_parallel(matrix, x, *b, result); + gmm::mult_add_parallel(gmmMatrix, x, *b, result); } else { - gmm::mult_parallel(matrix, x, result); + gmm::mult_parallel(gmmMatrix, x, result); } #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAdd(matrix, x, b, result); + multAdd(x, b, result); #endif } #ifdef STORM_HAVE_INTELTBB - template + template class TbbMultAddReduceFunctor { public: - TbbMultAddReduceFunctor(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { + TbbMultAddReduceFunctor(std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) : rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) { // Intentionally left empty. } void operator()(tbb::blocked_range const& range) const { + typedef std::vector VectorType; + typedef gmm::csr_matrix MatrixType; + auto groupIt = rowGroupIndices.begin() + range.begin(); auto groupIte = rowGroupIndices.begin() + range.end(); - + auto itr = mat_row_const_begin(matrix) + *groupIt; - typename std::vector::const_iterator bIt; + typename std::vector::const_iterator bIt; if (b) { bIt = b->begin() + *groupIt; } @@ -168,13 +243,14 @@ namespace storm { } auto resultIt = result.begin() + range.begin(); - + + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = *groupIt; for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) { - if (choices) { - *choiceIt = 0; - } - - T currentValue = storm::utility::zero(); + ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if the row group is not empty. if (*groupIt != *(groupIt + 1)) { @@ -183,51 +259,66 @@ namespace storm { ++bIt; } - ++itr; + currentValue += vect_sp(gmm::linalg_traits::row(itr), x); - for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr) { - T newValue = vect_sp(gmm::linalg_traits>::row(itr), x, typename gmm::linalg_traits>::storage_type(), typename gmm::linalg_traits>::storage_type()); - if (b) { - newValue += *bIt; - ++bIt; + if (choices) { + selectedChoice = currentRow - *groupIt; + if (*choiceIt == selectedChoice) { + oldSelectedChoiceValue = currentValue; } + } + + ++itr; + ++currentRow; + + for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr, ++bIt, ++currentRow) { + ValueType newValue = b ? *bIt : storm::utility::zero(); + newValue += vect_sp(gmm::linalg_traits::row(itr), x); - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(mat_row_const_begin(matrix), itr) - *groupIt; + selectedChoice = currentRow - *groupIt; } } } } + // Finally write value to target vector. *resultIt = currentValue; + if (choices && compare(currentValue, oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } } private: - storm::solver::OptimizationDirection dir; + Compare compare; std::vector const& rowGroupIndices; - gmm::csr_matrix const& matrix; - std::vector const& x; - std::vector const* b; - std::vector& result; + gmm::csr_matrix const& matrix; + std::vector const& x; + std::vector const* b; + std::vector& result; std::vector* choices; }; #endif - template - void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + template + void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 10), TbbMultAddReduceFunctor(dir, rowGroupIndices, matrix, x, b, result, choices)); + if (dir == storm::OptimizationDirection::Minimize) { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, this->gmmMatrix, x, b, result, choices)); + } else { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, this->gmmMatrix, x, b, result, choices)); + } #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAddReduce(dir, rowGroupIndices, matrix, x, b, result, choices); + multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices); #endif } template<> - void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + void GmmxxMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported."); } diff --git a/src/storm/solver/GmmxxMultiplier.h b/src/storm/solver/GmmxxMultiplier.h index 237f56b63..da70e2a05 100644 --- a/src/storm/solver/GmmxxMultiplier.h +++ b/src/storm/solver/GmmxxMultiplier.h @@ -1,30 +1,47 @@ #pragma once -#include "storm/utility/VectorHelper.h" +#include "storm/solver/Multiplier.h" #include "storm/adapters/GmmxxAdapter.h" #include "storm-config.h" namespace storm { + + namespace storage { + template + class SparseMatrix; + } + namespace solver { - template - class GmmxxMultiplier : public storm::utility::VectorHelper { + template + class GmmxxMultiplier : public Multiplier { public: - GmmxxMultiplier(); + GmmxxMultiplier(storm::storage::SparseMatrix const& matrix); + virtual ~GmmxxMultiplier() = default; + + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; + virtual void clearCache() const override; - void multAdd(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddGaussSeidelBackward(gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b) const; + private: + void initialize() const; - void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddReduceGaussSeidel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; + bool parallelize(Environment const& env) const; - void multAddParallel(gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + void multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + + template + void multAddReduceHelper(std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - private: - void multAddReduceHelper(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, gmm::csr_matrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + mutable gmm::csr_matrix gmmMatrix; }; } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp index fb71fa43f..51289fb52 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "storm/solver/IterativeMinMaxLinearEquationSolver.h" #include "storm/utility/ConstantsComparator.h" @@ -7,6 +10,7 @@ #include "storm/utility/KwekMehlhorn.h" #include "storm/utility/NumberTraits.h" +#include "storm/utility/Stopwatch.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidEnvironmentException.h" @@ -19,23 +23,23 @@ namespace storm { namespace solver { template - IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(linearEquationSolverFactory)) { + IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty } template - IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(A, std::move(linearEquationSolverFactory)) { + IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(A), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } template - IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A), std::move(linearEquationSolverFactory)) { + IterativeMinMaxLinearEquationSolver::IterativeMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A)), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { // Intentionally left empty. } template MinMaxMethod IterativeMinMaxLinearEquationSolver::getMethod(Environment const& env, bool isExactMode) const { - // Adjust the method if none was specified and we are using rational numbers. + // Adjust the method if none was specified and we want exact or sound computations. auto method = env.solver().minMax().getMethod(); if (isExactMode && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch) { @@ -45,8 +49,15 @@ namespace storm { } else { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } + } else if (env.solver().isForceSoundness() && method != MinMaxMethod::SoundValueIteration && method != MinMaxMethod::IntervalIteration && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch) { + if (env.solver().minMax().isMethodSetFromDefault()) { + STORM_LOG_INFO("Selecting 'sound value iteration' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method."); + method = MinMaxMethod::SoundValueIteration; + } else { + STORM_LOG_WARN("The selected solution method does not guarantee sound results."); + } } - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::SoundValueIteration || method == MinMaxMethod::IntervalIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); return method; } @@ -55,11 +66,7 @@ namespace storm { bool result = false; switch (getMethod(env, storm::NumberTraits::IsExact)) { case MinMaxMethod::ValueIteration: - if (env.solver().isForceSoundness()) { - result = solveEquationsSoundValueIteration(env, dir, x, b); - } else { - result = solveEquationsValueIteration(env, dir, x, b); - } + result = solveEquationsValueIteration(env, dir, x, b); break; case MinMaxMethod::PolicyIteration: result = solveEquationsPolicyIteration(env, dir, x, b); @@ -67,6 +74,12 @@ namespace storm { case MinMaxMethod::RationalSearch: result = solveEquationsRationalSearch(env, dir, x, b); break; + case MinMaxMethod::IntervalIteration: + result = solveEquationsIntervalIteration(env, dir, x, b); + break; + case MinMaxMethod::SoundValueIteration: + result = solveEquationsSoundValueIteration(env, dir, x, b); + break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method"); } @@ -114,19 +127,32 @@ namespace storm { // The solver that we will use throughout the procedure. std::unique_ptr> solver; // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } - + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + SolverStatus status = SolverStatus::InProgress; uint64_t iterations = 0; this->startMeasureProgress(); do { // Solve the equation system for the 'DTMC'. - solveInducedEquationSystem(environmentOfSolver ? *environmentOfSolver : env, solver, scheduler, x, subB, b); + solveInducedEquationSystem(environmentOfSolver, solver, scheduler, x, subB, b); // Go through the multiplication result and see whether we can improve any of the choices. bool schedulerImproved = false; @@ -193,26 +219,17 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { auto method = getMethod(env, storm::NumberTraits::IsExact); - // Start by getting the requirements of the linear equation solver. - LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified; - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::RationalSearch) { - if (!this->hasInitialScheduler() && assumeNoInitialScheduler) { - linEqTask = LinearEquationSolverTask::Multiply; - } - } - MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask)); + // Check whether a linear equation solver is needed and potentially start with its requirements + bool needsLinEqSolver = false; + needsLinEqSolver |= method == MinMaxMethod::PolicyIteration; + needsLinEqSolver |= method == MinMaxMethod::ValueIteration && (this->hasInitialScheduler() || hasInitialScheduler); + MinMaxLinearEquationSolverRequirements requirements = needsLinEqSolver ? MinMaxLinearEquationSolverRequirements(this->linearEquationSolverFactory->getRequirements(env)) : MinMaxLinearEquationSolverRequirements(); if (method == MinMaxMethod::ValueIteration) { - if (env.solver().isForceSoundness()) { - // Interval iteration requires a unique solution and lower+upper bounds - if (!this->hasUniqueSolution()) { - requirements.requireNoEndComponents(); - } - requirements.requireBounds(); - } else if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique. + 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(); @@ -226,6 +243,12 @@ namespace storm { } } } + } else if (method == MinMaxMethod::IntervalIteration) { + // Interval iteration requires a unique solution and lower+upper bounds + if (!this->hasUniqueSolution()) { + requirements.requireNoEndComponents(); + } + requirements.requireBounds(); } else if (method == MinMaxMethod::RationalSearch) { // Rational search needs to approach the solution from below. requirements.requireLowerBounds(); @@ -237,38 +260,40 @@ namespace storm { if (!this->hasUniqueSolution()) { requirements.requireValidInitialScheduler(); } + } else if (method == MinMaxMethod::SoundValueIteration) { + if (!this->hasUniqueSolution()) { + requirements.requireNoEndComponents(); + } + requirements.requireBounds(false); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver."); } - return requirements; } template - typename IterativeMinMaxLinearEquationSolver::ValueIterationResult IterativeMinMaxLinearEquationSolver::performValueIteration(OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { + typename IterativeMinMaxLinearEquationSolver::ValueIterationResult IterativeMinMaxLinearEquationSolver::performValueIteration(Environment const& env, OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { STORM_LOG_ASSERT(currentX != newX, "Vectors must not be aliased."); - // Get handle to linear equation solver. - storm::solver::LinearEquationSolver const& linearEquationSolver = *this->linEqSolverA; + // Get handle to multiplier. + storm::solver::Multiplier const& multiplier = *this->multiplierA; // Allow aliased multiplications. - bool useGaussSeidelMultiplication = linearEquationSolver.supportsGaussSeidelMultiplication() && multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; + bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = currentIterations; - std::vector* originalX = currentX; - SolverStatus status = SolverStatus::InProgress; while (status == SolverStatus::InProgress) { // Compute x' = min/max(A*x + b). if (useGaussSeidelMultiplication) { // Copy over the current vector so we can modify it in-place. *newX = *currentX; - linearEquationSolver.multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *newX, &b); + multiplier.multiplyAndReduceGaussSeidel(env, dir, *newX, &b); } else { - linearEquationSolver.multiplyAndReduce(dir, this->A->getRowGroupIndices(), *currentX, &b, *newX); + multiplier.multiplyAndReduce(env, dir, *currentX, &b, *newX); } // Determine whether the method converged. @@ -285,19 +310,13 @@ namespace storm { this->showProgressIterative(iterations); } - // Swap the pointers so that the output is always in currentX. - if (originalX == newX) { - std::swap(currentX, newX); - } - return ValueIterationResult(iterations - currentIterations, status); } template bool IterativeMinMaxLinearEquationSolver::solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -311,14 +330,27 @@ namespace storm { // Solve the equation system induced by the initial scheduler. std::unique_ptr> linEqSolver; // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; - solveInducedEquationSystem(environmentOfSolver ? *environmentOfSolver : env, linEqSolver, this->getInitialScheduler(), x, *auxiliaryRowGroupVector, b); + solveInducedEquationSystem(environmentOfSolver, linEqSolver, this->getInitialScheduler(), x, *auxiliaryRowGroupVector, b); // If we were given an initial scheduler and are maximizing (minimizing), our current solution becomes // always less-or-equal (greater-or-equal) than the actual solution. guarantee = maximize(dir) ? SolverGuarantee::LessOrEqual : SolverGuarantee::GreaterOrEqual; @@ -344,7 +376,7 @@ namespace storm { std::vector* currentX = &x; this->startMeasureProgress(); - ValueIterationResult result = performValueIteration(dir, currentX, newX, b, storm::utility::convertNumber(env.solver().minMax().getPrecision()), env.solver().minMax().getRelativeTerminationCriterion(), guarantee, 0, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); + ValueIterationResult result = performValueIteration(env, dir, currentX, newX, b, storm::utility::convertNumber(env.solver().minMax().getPrecision()), env.solver().minMax().getRelativeTerminationCriterion(), guarantee, 0, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); // Swap the result into the output x. if (currentX == auxiliaryRowGroupVector.get()) { @@ -356,7 +388,7 @@ namespace storm { // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); + this->multiplierA->multiplyAndReduce(env, dir, x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); } if (!this->isCachingEnabled()) { @@ -397,12 +429,11 @@ namespace storm { * Model Checker: Interval Iteration for Markov Decision Processes, CAV 2017). */ template - bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + bool IterativeMinMaxLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { STORM_LOG_THROW(this->hasUpperBound(), storm::exceptions::UnmetRequirementException, "Solver requires upper bound, but none was given."); - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -410,7 +441,7 @@ namespace storm { } // Allow aliased multiplications. - bool useGaussSeidelMultiplication = this->linEqSolverA->supportsGaussSeidelMultiplication() && env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; + bool useGaussSeidelMultiplication = env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel; std::vector* lowerX = &x; this->createLowerBoundsVector(*lowerX); @@ -428,7 +459,7 @@ namespace storm { SolverStatus status = SolverStatus::InProgress; bool doConvergenceCheck = true; - bool useDiffs = this->hasRelevantValues(); + bool useDiffs = this->hasRelevantValues() && !env.solver().minMax().isSymmetricUpdatesSet(); std::vector oldValues; if (useGaussSeidelMultiplication && useDiffs) { oldValues.resize(this->getRelevantValues().getNumberOfSetBits()); @@ -454,22 +485,22 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *lowerX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *upperX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } } else { - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *lowerX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(lowerX, tmp); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *upperX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -482,7 +513,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *lowerX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); } @@ -491,7 +522,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->linEqSolverA->multiplyAndReduceGaussSeidel(dir, this->A->getRowGroupIndices(), *upperX, &b); + this->multiplierA->multiplyAndReduceGaussSeidel(env, dir, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } @@ -499,14 +530,14 @@ namespace storm { } } else { if (maxLowerDiff >= maxUpperDiff) { - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *lowerX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(tmp, lowerX); lowerStep = true; } else { - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), *upperX, &b, *tmp); + this->multiplierA->multiplyAndReduce(env, dir, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -545,7 +576,7 @@ namespace storm { } reportStatus(status, iterations); - + // We take the means of the lower and upper bound so we guarantee the desired precision. ValueType two = storm::utility::convertNumber(2.0); storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [&two] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / two; }); @@ -560,8 +591,73 @@ namespace storm { // If requested, we store the scheduler for retrieval. if (this->isTrackSchedulerSet()) { this->schedulerChoices = std::vector(this->A->getRowGroupCount()); - this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); + this->multiplierA->multiplyAndReduce(env, dir, x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); + } + + if (!this->isCachingEnabled()) { + clearCache(); + } + + return status == SolverStatus::Converged; + } + + template + bool IterativeMinMaxLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + + // Prepare the solution vectors and the helper. + assert(x.size() == this->A->getRowGroupCount()); + if (!this->auxiliaryRowGroupVector) { + this->auxiliaryRowGroupVector = std::make_unique>(); + } + if (!this->soundValueIterationHelper) { + this->soundValueIterationHelper = std::make_unique>(*this->A, x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + } else { + this->soundValueIterationHelper = std::make_unique>(std::move(*this->soundValueIterationHelper), x, *this->auxiliaryRowGroupVector, env.solver().minMax().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().minMax().getPrecision())); + } + + // Prepare initial bounds for the solution (if given) + if (this->hasLowerBound()) { + this->soundValueIterationHelper->setLowerBound(this->getLowerBound(true)); + } + if (this->hasUpperBound()) { + this->soundValueIterationHelper->setUpperBound(this->getUpperBound(true)); + } + + storm::storage::BitVector const* relevantValuesPtr = nullptr; + if (this->hasRelevantValues()) { + relevantValuesPtr = &this->getRelevantValues(); + } + + SolverStatus status = SolverStatus::InProgress; + this->startMeasureProgress(); + uint64_t iterations = 0; + + while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) { + ++iterations; + this->soundValueIterationHelper->performIterationStep(dir, b); + if (this->soundValueIterationHelper->checkConvergenceUpdateBounds(dir, relevantValuesPtr)) { + status = SolverStatus::Converged; + } else { + // Update the status accordingly + if (this->hasCustomTerminationCondition() && this->soundValueIterationHelper->checkCustomTerminationCondition(this->getTerminationCondition())) { + status = SolverStatus::TerminatedEarly; + } else if (iterations >= env.solver().minMax().getMaximalNumberOfIterations()) { + status = SolverStatus::MaximalIterationsExceeded; + } + } + + // Potentially show progress. + this->showProgressIterative(iterations); + } + this->soundValueIterationHelper->setSolutionVector(); + + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + this->schedulerChoices = std::vector(this->A->getRowGroupCount()); + this->A->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get()); } + + reportStatus(status, iterations); if (!this->isCachingEnabled()) { clearCache(); @@ -617,11 +713,6 @@ namespace storm { return false; } - template - void IterativeMinMaxLinearEquationSolver::createLinearEquationSolver(Environment const& env) const { - this->linEqSolverA = this->linearEquationSolverFactory->create(env, *this->A, LinearEquationSolverTask::Multiply); - } - template template typename std::enable_if::value && !NumberTraits::IsExact, bool>::type IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { @@ -632,9 +723,8 @@ namespace storm { std::vector rationalX(x.size()); std::vector rationalB = storm::utility::vector::convertNumericVector(b); - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -662,9 +752,8 @@ namespace storm { typename std::enable_if::value && NumberTraits::IsExact, bool>::type IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { // Version for when the overall value type is exact and the same type is to be used for the imprecise part. - if (!this->linEqSolverA) { - this->createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } if (!auxiliaryRowGroupVector) { @@ -714,13 +803,14 @@ namespace storm { // Create imprecise solver from the imprecise data. IterativeMinMaxLinearEquationSolver impreciseSolver(std::make_unique>()); impreciseSolver.setMatrix(impreciseA); - impreciseSolver.createLinearEquationSolver(env); impreciseSolver.setCachingEnabled(true); + impreciseSolver.multiplierA = storm::solver::MultiplierFactory().create(env, impreciseA); bool converged = false; try { // Forward the call to the core rational search routine. converged = solveEquationsRationalSearchHelper(env, dir, impreciseSolver, *this->A, x, b, impreciseA, impreciseX, impreciseB, impreciseTmpX); + impreciseSolver.clearCache(); } catch (storm::exceptions::PrecisionExceededException const& e) { STORM_LOG_WARN("Precision of value type was exceeded, trying to recover by switching to rational arithmetic."); @@ -740,9 +830,8 @@ namespace storm { impreciseB = std::vector(); impreciseA = storm::storage::SparseMatrix(); - if (!this->linEqSolverA) { - createLinearEquationSolver(env); - this->linEqSolverA->setCachingEnabled(true); + if (!this->multiplierA) { + this->multiplierA = storm::solver::MultiplierFactory().create(env, *this->A); } // Forward the call to the core rational search routine, but now with our value type as the imprecise value type. @@ -791,7 +880,9 @@ namespace storm { template template bool IterativeMinMaxLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, OptimizationDirection dir, IterativeMinMaxLinearEquationSolver const& impreciseSolver, storm::storage::SparseMatrix const& rationalA, std::vector& rationalX, std::vector const& rationalB, storm::storage::SparseMatrix const& A, std::vector& x, std::vector const& b, std::vector& tmpX) const { - + + std::vector const* originalX = &x; + std::vector* currentX = &x; std::vector* newX = &tmpX; @@ -802,7 +893,7 @@ namespace storm { impreciseSolver.startMeasureProgress(); while (status == SolverStatus::InProgress && overallIterations < env.solver().minMax().getMaximalNumberOfIterations()) { // Perform value iteration with the current precision. - typename IterativeMinMaxLinearEquationSolver::ValueIterationResult result = impreciseSolver.performValueIteration(dir, currentX, newX, b, storm::utility::convertNumber(precision), env.solver().minMax().getRelativeTerminationCriterion(), SolverGuarantee::LessOrEqual, overallIterations, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); + typename IterativeMinMaxLinearEquationSolver::ValueIterationResult result = impreciseSolver.performValueIteration(env, dir, currentX, newX, b, storm::utility::convertNumber(precision), env.solver().minMax().getRelativeTerminationCriterion(), SolverGuarantee::LessOrEqual, overallIterations, env.solver().minMax().getMaximalNumberOfIterations(), env.solver().minMax().getMultiplicationStyle()); // At this point, the result of the imprecise value iteration is stored in the (imprecise) current x. @@ -833,6 +924,11 @@ namespace storm { } } + // Swap the two vectors if the current result is not in the original x. + if (currentX != originalX) { + std::swap(x, tmpX); + } + if (status == SolverStatus::InProgress && overallIterations == env.solver().minMax().getMaximalNumberOfIterations()) { status = SolverStatus::MaximalIterationsExceeded; } @@ -892,8 +988,8 @@ namespace storm { template void IterativeMinMaxLinearEquationSolver::reportStatus(SolverStatus status, uint64_t iterations) { switch (status) { - case SolverStatus::Converged: STORM_LOG_INFO("Iterative solver converged after " << iterations << " iterations."); break; - case SolverStatus::TerminatedEarly: STORM_LOG_INFO("Iterative solver terminated early after " << iterations << " iterations."); break; + case SolverStatus::Converged: STORM_LOG_TRACE("Iterative solver converged after " << iterations << " iterations."); break; + case SolverStatus::TerminatedEarly: STORM_LOG_TRACE("Iterative solver terminated early after " << iterations << " iterations."); break; case SolverStatus::MaximalIterationsExceeded: STORM_LOG_WARN("Iterative solver did not converge after " << iterations << " iterations."); break; default: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Iterative solver terminated unexpectedly."); @@ -902,45 +998,17 @@ namespace storm { template void IterativeMinMaxLinearEquationSolver::clearCache() const { + multiplierA.reset(); auxiliaryRowGroupVector.reset(); auxiliaryRowGroupVector2.reset(); - rowGroupOrdering.reset(); + soundValueIterationHelper.reset(); StandardMinMaxLinearEquationSolver::clearCache(); } - template - IterativeMinMaxLinearEquationSolverFactory::IterativeMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory() { - // Intentionally left empty - } - - template - IterativeMinMaxLinearEquationSolverFactory::IterativeMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory) : StandardMinMaxLinearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty - } - - template - IterativeMinMaxLinearEquationSolverFactory::IterativeMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType) : StandardMinMaxLinearEquationSolverFactory(solverType) { - // Intentionally left empty - } - - template - std::unique_ptr> IterativeMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized."); - - auto method = env.solver().minMax().getMethod(); - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); - - std::unique_ptr> result = std::make_unique>(this->linearEquationSolverFactory->clone()); - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; - } - template class IterativeMinMaxLinearEquationSolver; - template class IterativeMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class IterativeMinMaxLinearEquationSolver; - template class IterativeMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h index f29fa0318..33da6e68e 100644 --- a/src/storm/solver/IterativeMinMaxLinearEquationSolver.h +++ b/src/storm/solver/IterativeMinMaxLinearEquationSolver.h @@ -5,7 +5,9 @@ #include "storm/utility/NumberTraits.h" #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/StandardMinMaxLinearEquationSolver.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/solver/SolverStatus.h" @@ -26,7 +28,7 @@ namespace storm { virtual void clearCache() const override; - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override; private: @@ -37,7 +39,9 @@ namespace storm { bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; bool solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsIntervalIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; bool solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; + bool solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const; template @@ -66,31 +70,22 @@ namespace storm { template friend class IterativeMinMaxLinearEquationSolver; - ValueIterationResult performValueIteration(OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; + ValueIterationResult performValueIteration(Environment const& env, OptimizationDirection dir, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maximalNumberOfIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; void createLinearEquationSolver(Environment const& env) const; + /// The factory used to obtain linear equation solvers. + std::unique_ptr> linearEquationSolverFactory; + // possibly cached data + mutable std::unique_ptr> multiplierA; mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries mutable std::unique_ptr> auxiliaryRowGroupVector2; // A.rowGroupCount() entries - mutable std::unique_ptr> rowGroupOrdering; // A.rowGroupCount() entries + mutable std::unique_ptr> soundValueIterationHelper; SolverStatus updateStatusIfNotConverged(SolverStatus status, std::vector const& x, uint64_t iterations, uint64_t maximalNumberOfIterations, SolverGuarantee const& guarantee) const; static void reportStatus(SolverStatus status, uint64_t iterations); }; - template - class IterativeMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - IterativeMinMaxLinearEquationSolverFactory(); - IterativeMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory); - IterativeMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType); - - // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - }; } } diff --git a/src/storm/solver/LinearEquationSolver.cpp b/src/storm/solver/LinearEquationSolver.cpp index caff69756..8207efcff 100644 --- a/src/storm/solver/LinearEquationSolver.cpp +++ b/src/storm/solver/LinearEquationSolver.cpp @@ -7,6 +7,7 @@ #include "storm/solver/NativeLinearEquationSolver.h" #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/solver/EliminationLinearEquationSolver.h" +#include "storm/solver/TopologicalLinearEquationSolver.h" #include "storm/utility/vector.h" @@ -30,89 +31,7 @@ namespace storm { } template - void LinearEquationSolver::repeatedMultiply(std::vector& x, std::vector const* b, uint_fast64_t n) const { - if (!cachedRowVector) { - cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - // We enable caching for this. But remember how the old setting was - bool cachingWasEnabled = isCachingEnabled(); - setCachingEnabled(true); - - // Set up some temporary variables so that we can just swap pointers instead of copying the result after - // each iteration. - std::vector* currentX = &x; - std::vector* nextX = cachedRowVector.get(); - - // Now perform matrix-vector multiplication as long as we meet the bound. - this->startMeasureProgress(); - for (uint_fast64_t i = 0; i < n; ++i) { - this->multiply(*currentX, b, *nextX); - std::swap(nextX, currentX); - - // Potentially show progress. - this->showProgressIterative(i, n); - } - - // If we performed an odd number of repetitions, we need to swap the contents of currentVector and x, - // because the output is supposed to be stored in the input vector x. - if (currentX == cachedRowVector.get()) { - std::swap(x, *currentX); - } - - // restore the old caching setting - setCachingEnabled(cachingWasEnabled); - - if (!isCachingEnabled()) { - clearCache(); - } - } - - template - void LinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - if (!cachedRowVector) { - cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - // We enable caching for this. But remember how the old setting was - bool cachingWasEnabled = isCachingEnabled(); - setCachingEnabled(true); - - this->multiply(x, b, *cachedRowVector); - vectorHelper.reduceVector(dir, *cachedRowVector, result, rowGroupIndices, choices); - - // restore the old caching setting - setCachingEnabled(cachingWasEnabled); - - if (!isCachingEnabled()) { - clearCache(); - } - } - -#ifdef STORM_HAVE_CARL - template<> - void LinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices ) const { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Reducing rational function vector is not supported."); - } -#endif - - template - bool LinearEquationSolver::supportsGaussSeidelMultiplication() const { - return false; - } - - template - void LinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This solver does not support the function 'multiplyGaussSeidel'."); - } - - template - void LinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This solver does not support the function 'multiplyAndReduceGaussSeidel'."); - } - - template - LinearEquationSolverRequirements LinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { + LinearEquationSolverRequirements LinearEquationSolver::getRequirements(Environment const&) const { return LinearEquationSolverRequirements(); } @@ -136,15 +55,15 @@ namespace storm { } template - std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix, LinearEquationSolverTask const& task) const { - std::unique_ptr> solver = this->create(env, task); + std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) const { + std::unique_ptr> solver = this->create(env); solver->setMatrix(matrix); return solver; } template - std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix&& matrix, LinearEquationSolverTask const& task) const { - std::unique_ptr> solver = this->create(env, task); + std::unique_ptr> LinearEquationSolverFactory::create(Environment const& env, storm::storage::SparseMatrix&& matrix) const { + std::unique_ptr> solver = this->create(env); solver->setMatrix(std::move(matrix)); return solver; } @@ -155,8 +74,8 @@ namespace storm { } template - LinearEquationSolverRequirements LinearEquationSolverFactory::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { - return this->create(env)->getRequirements(env, task); + LinearEquationSolverRequirements LinearEquationSolverFactory::getRequirements(Environment const& env) const { + return this->create(env)->getRequirements(env); } template @@ -164,21 +83,21 @@ namespace storm { // Intentionally left empty. } - template<> - std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if it is not supported by this value type - if (type == EquationSolverType::Gmmxx) { - type = EquationSolverType::Eigen; - STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver since the selected one does not support exact computations."); + if (type != EquationSolverType::Eigen && type != EquationSolverType::Topological && (env.solver().isLinearEquationSolverTypeSetFromDefaultValue() || type == EquationSolverType::Gmmxx)) { + STORM_LOG_INFO("Selecting '" + toString(EquationSolverType::Eigen) + "' as the linear equation solver since the previously selected one (" << toString(type) << ") does not support exact computations."); + type = EquationSolverType::Eigen; } switch (type) { case EquationSolverType::Native: return std::make_unique>(); case EquationSolverType::Eigen: return std::make_unique>(); case EquationSolverType::Elimination: return std::make_unique>(); + case EquationSolverType::Topological: return std::make_unique>(); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unknown solver type."); return nullptr; @@ -186,18 +105,19 @@ namespace storm { } template<> - std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if it is not supported by this value type if (type == EquationSolverType::Gmmxx || type == EquationSolverType::Native) { + STORM_LOG_INFO("Selecting '" + toString(EquationSolverType::Eigen) + "' as the linear equation solver since the previously selected one (" << toString(type) << ") does not support parametric computations."); type = EquationSolverType::Eigen; - STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver since the selected one does not support parametric computations."); } switch (type) { case EquationSolverType::Eigen: return std::make_unique>(); case EquationSolverType::Elimination: return std::make_unique>(); + case EquationSolverType::Topological: return std::make_unique>(); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unknown solver type."); return nullptr; @@ -205,11 +125,11 @@ namespace storm { } template - std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> GeneralLinearEquationSolverFactory::create(Environment const& env) const { EquationSolverType type = env.solver().getLinearEquationSolverType(); // Adjust the solver type if none was specified and we want sound computations - if (env.solver().isForceSoundness() && task != LinearEquationSolverTask::Multiply && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination) { + if (env.solver().isForceSoundness() && type != EquationSolverType::Native && type != EquationSolverType::Eigen && type != EquationSolverType::Elimination && type != EquationSolverType::Topological) { if (env.solver().isLinearEquationSolverTypeSetFromDefaultValue()) { type = EquationSolverType::Native; STORM_LOG_INFO("Selecting '" + toString(type) + "' as the linear equation solver to guarantee sound results. If you want to override this, please explicitly specify a different solver."); @@ -223,6 +143,7 @@ namespace storm { case EquationSolverType::Native: return std::make_unique>(); case EquationSolverType::Eigen: return std::make_unique>(); case EquationSolverType::Elimination: return std::make_unique>(); + case EquationSolverType::Topological: return std::make_unique>(); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unknown solver type."); return nullptr; diff --git a/src/storm/solver/LinearEquationSolver.h b/src/storm/solver/LinearEquationSolver.h index b4b49d627..525623781 100644 --- a/src/storm/solver/LinearEquationSolver.h +++ b/src/storm/solver/LinearEquationSolver.h @@ -8,7 +8,6 @@ #include "storm/solver/MultiplicationStyle.h" #include "storm/solver/LinearEquationSolverProblemFormat.h" #include "storm/solver/LinearEquationSolverRequirements.h" -#include "storm/solver/LinearEquationSolverTask.h" #include "storm/solver/OptimizationDirection.h" #include "storm/utility/VectorHelper.h" @@ -22,8 +21,7 @@ namespace storm { namespace solver { /*! - * An interface that represents an abstract linear equation solver. In addition to solving a system of linear - * equations, the functionality to repeatedly multiply a matrix with a given vector is provided. + * An interface that represents an abstract linear equation solver. */ template class LinearEquationSolver : public AbstractEquationSolver { @@ -50,78 +48,6 @@ namespace storm { */ bool solveEquations(Environment const& env, std::vector& x, std::vector const& b) const; - /*! - * Performs on matrix-vector multiplication x' = A*x + b. - * - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - * @param result The target vector into which to write the multiplication result. Its length must be equal - * to the number of rows of A. - */ - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const = 0; - - /*! - * Performs on matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups - * so that the resulting vector has the size of number of row groups of A. - * - * @param dir The direction for the reduction step. - * @param rowGroupIndices A vector storing the row groups over which to reduce. - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - * @param result The target vector into which to write the multiplication result. Its length must be equal - * to the number of rows of A. - * @param choices If given, the choices made in the reduction process are written to this vector. - */ - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - - /*! - * Retrieves whether this solver offers the gauss-seidel style multiplications. - */ - virtual bool supportsGaussSeidelMultiplication() const; - - /*! - * Performs on matrix-vector multiplication x' = A*x + b. It does so in a gauss-seidel style, i.e. reusing - * the new x' components in the further multiplication. - * - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - */ - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const; - - /*! - * Performs on matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups - * so that the resulting vector has the size of number of row groups of A. It does so in a gauss-seidel - * style, i.e. reusing the new x' components in the further multiplication. - * - * @param dir The direction for the reduction step. - * @param rowGroupIndices A vector storing the row groups over which to reduce. - * @param x The input vector with which to multiply the matrix. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal - * to the number of rows of A. - * @param choices If given, the choices made in the reduction process are written to this vector. - */ - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; - - /*! - * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After - * performing the necessary multiplications, the result is written to the input vector x. Note that the - * matrix A has to be given upon construction time of the solver object. - * - * @param x The initial vector with which to perform matrix-vector multiplication. Its length must be equal - * to the number of columns of A. - * @param b If non-null, this vector is added after each multiplication. If given, its length must be equal - * to the number of rows of A. - * @param n The number of times to perform the multiplication. - */ - void repeatedMultiply(std::vector& x, std::vector const* b, uint_fast64_t n) const; - /*! * Retrieves the format in which this solver expects to solve equations. If the solver expects the equation * system format, it solves Ax = b. If it it expects a fixed point format, it solves Ax + b = x. @@ -132,7 +58,7 @@ namespace storm { * Retrieves the requirements of the solver under the current settings. Note that these requirements only * apply to solving linear equations and not to the matrix vector multiplications. */ - virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const; /*! * Sets whether some of the generated data during solver calls should be cached. @@ -187,7 +113,7 @@ namespace storm { * @param matrix The matrix that defines the equation system. * @return A pointer to the newly created solver. */ - std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix) const; /*! * Creates a new linear equation solver instance with the given matrix. The caller gives up posession of the @@ -196,12 +122,12 @@ namespace storm { * @param matrix The matrix that defines the equation system. * @return A pointer to the newly created solver. */ - std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& matrix, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix&& matrix) const; /*! * Creates an equation solver with the current settings, but without a matrix. */ - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const = 0; + virtual std::unique_ptr> create(Environment const& env) const = 0; /*! * Creates a copy of this factory. @@ -217,7 +143,7 @@ namespace storm { * Retrieves the requirements of the solver if it was created with the current settings. Note that these * requirements only apply to solving linear equations and not to the matrix vector multiplications. */ - LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const; + LinearEquationSolverRequirements getRequirements(Environment const& env) const; }; template @@ -227,7 +153,7 @@ namespace storm { using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; }; diff --git a/src/storm/solver/LinearEquationSolverRequirements.cpp b/src/storm/solver/LinearEquationSolverRequirements.cpp index 90662c6f9..445e776d7 100644 --- a/src/storm/solver/LinearEquationSolverRequirements.cpp +++ b/src/storm/solver/LinearEquationSolverRequirements.cpp @@ -3,52 +3,78 @@ namespace storm { namespace solver { - LinearEquationSolverRequirements::LinearEquationSolverRequirements() : lowerBounds(false), upperBounds(false) { + LinearEquationSolverRequirements::LinearEquationSolverRequirements() { // Intentionally left empty. } - LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireLowerBounds() { - lowerBounds = true; + LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireLowerBounds(bool critical) { + lowerBoundsRequirement.enable(critical); return *this; } - LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireUpperBounds() { - upperBounds = true; + LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireUpperBounds(bool critical) { + upperBoundsRequirement.enable(critical); return *this; } - LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireBounds() { - requireLowerBounds(); - requireUpperBounds(); + LinearEquationSolverRequirements& LinearEquationSolverRequirements::requireBounds(bool critical) { + requireLowerBounds(critical); + requireUpperBounds(critical); return *this; } - bool LinearEquationSolverRequirements::requiresLowerBounds() const { - return lowerBounds; + SolverRequirement const& LinearEquationSolverRequirements::lowerBounds() const { + return lowerBoundsRequirement; } - bool LinearEquationSolverRequirements::requiresUpperBounds() const { - return upperBounds; + SolverRequirement const& LinearEquationSolverRequirements::upperBounds() const { + return upperBoundsRequirement; } - bool LinearEquationSolverRequirements::requires(Element const& element) const { + SolverRequirement const& LinearEquationSolverRequirements::get(Element const& element) const { switch (element) { - case Element::LowerBounds: return lowerBounds; break; - case Element::UpperBounds: return upperBounds; break; + case Element::LowerBounds: return lowerBounds(); break; + case Element::UpperBounds: return upperBounds(); break; } } void LinearEquationSolverRequirements::clearLowerBounds() { - lowerBounds = false; + lowerBoundsRequirement.clear(); } void LinearEquationSolverRequirements::clearUpperBounds() { - upperBounds = false; + upperBoundsRequirement.clear(); } - bool LinearEquationSolverRequirements::empty() const { - return !lowerBounds && !upperBounds; + bool LinearEquationSolverRequirements::hasEnabledRequirement() const { + return lowerBoundsRequirement || upperBoundsRequirement; } + bool LinearEquationSolverRequirements::hasEnabledCriticalRequirement() const { + return lowerBoundsRequirement.isCritical() || upperBoundsRequirement.isCritical(); + } + + + std::string LinearEquationSolverRequirements::getEnabledRequirementsAsString() const { + std::string res = "["; + bool first = true; + if (lowerBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "lowerBounds"; + if (lowerBounds().isCritical()) { + res += "(mandatory)"; + } + } + if (upperBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "upperBounds"; + if (upperBounds().isCritical()) { + res += "(mandatory)"; + } + } + res += "]"; + return res; + } + } } diff --git a/src/storm/solver/LinearEquationSolverRequirements.h b/src/storm/solver/LinearEquationSolverRequirements.h index 8f5a126a7..a7e23d248 100644 --- a/src/storm/solver/LinearEquationSolverRequirements.h +++ b/src/storm/solver/LinearEquationSolverRequirements.h @@ -1,5 +1,9 @@ #pragma once +#include + +#include "storm/solver/SolverRequirement.h" + namespace storm { namespace solver { @@ -14,22 +18,29 @@ namespace storm { LinearEquationSolverRequirements(); - LinearEquationSolverRequirements& requireLowerBounds(); - LinearEquationSolverRequirements& requireUpperBounds(); - LinearEquationSolverRequirements& requireBounds(); + LinearEquationSolverRequirements& requireLowerBounds(bool critical = true); + LinearEquationSolverRequirements& requireUpperBounds(bool critical = true); + LinearEquationSolverRequirements& requireBounds(bool critical = true); - bool requiresLowerBounds() const; - bool requiresUpperBounds() const; - bool requires(Element const& element) const; + SolverRequirement const& lowerBounds() const; + SolverRequirement const& upperBounds() const; + SolverRequirement const& get(Element const& element) const; void clearLowerBounds(); void clearUpperBounds(); - bool empty() const; + bool hasEnabledRequirement() const; + bool hasEnabledCriticalRequirement() const; + + /*! + * Checks whether there are no critical requirements left. + * In case there is a critical requirement left an exception is thrown. + */ + std::string getEnabledRequirementsAsString() const; private: - bool lowerBounds; - bool upperBounds; + SolverRequirement lowerBoundsRequirement; + SolverRequirement upperBoundsRequirement; }; } diff --git a/src/storm/solver/LinearEquationSolverTask.cpp b/src/storm/solver/LinearEquationSolverTask.cpp deleted file mode 100644 index 91783ae36..000000000 --- a/src/storm/solver/LinearEquationSolverTask.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "storm/solver/LinearEquationSolverTask.h" - -namespace storm { - namespace solver { - - std::ostream& operator<<(std::ostream& out, LinearEquationSolverTask const& task) { - switch (task) { - case LinearEquationSolverTask::Unspecified: out << "unspecified"; break; - case LinearEquationSolverTask::SolveEquations: out << "solve equations"; break; - case LinearEquationSolverTask::Multiply: out << "multiply"; break; - } - return out; - } - - } -} diff --git a/src/storm/solver/LinearEquationSolverTask.h b/src/storm/solver/LinearEquationSolverTask.h deleted file mode 100644 index 5d3a401dd..000000000 --- a/src/storm/solver/LinearEquationSolverTask.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -namespace storm { - namespace solver { - - enum class LinearEquationSolverTask { Unspecified, SolveEquations, Multiply }; - - std::ostream& operator<<(std::ostream& out, LinearEquationSolverTask const& style); - - } -} diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp index 80668c4fc..78bc75752 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.cpp @@ -10,17 +10,17 @@ namespace storm { namespace solver { template - LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { + LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(std::unique_ptr>&& lpSolverFactory) : lpSolverFactory(std::move(lpSolverFactory)) { // Intentionally left empty. } template - LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(A, std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { + LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(A), lpSolverFactory(std::move(lpSolverFactory)) { // Intentionally left empty. } template - LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A), std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { + LpMinMaxLinearEquationSolver::LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolver(std::move(A)), lpSolverFactory(std::move(lpSolverFactory)) { // Intentionally left empty. } @@ -111,50 +111,24 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { - MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, LinearEquationSolverTask::Multiply)); + MinMaxLinearEquationSolverRequirements requirements; // In case we need to retrieve a scheduler, the solution has to be unique if (!this->hasUniqueSolution() && this->isTrackSchedulerSet()) { requirements.requireNoEndComponents(); } + requirements.requireBounds(false); + return requirements; } - template - LpMinMaxLinearEquationSolverFactory::LpMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(), lpSolverFactory(std::make_unique>()) { - // Intentionally left empty - } - - template - LpMinMaxLinearEquationSolverFactory::LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolverFactory(), lpSolverFactory(std::move(lpSolverFactory)) { - // Intentionally left empty - } - - template - LpMinMaxLinearEquationSolverFactory::LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory) : StandardMinMaxLinearEquationSolverFactory(std::move(linearEquationSolverFactory)), lpSolverFactory(std::move(lpSolverFactory)) { - // Intentionally left empty - } - - template - std::unique_ptr> LpMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::LinearProgramming, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); - STORM_LOG_ASSERT(this->lpSolverFactory, "Lp solver factory not initialized."); - STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized."); - - std::unique_ptr> result = std::make_unique>(this->linearEquationSolverFactory->clone(), this->lpSolverFactory->clone()); - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; - } - template class LpMinMaxLinearEquationSolver; - template class LpMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class LpMinMaxLinearEquationSolver; - template class LpMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/LpMinMaxLinearEquationSolver.h b/src/storm/solver/LpMinMaxLinearEquationSolver.h index df20e120f..72ba6871e 100644 --- a/src/storm/solver/LpMinMaxLinearEquationSolver.h +++ b/src/storm/solver/LpMinMaxLinearEquationSolver.h @@ -13,34 +13,19 @@ namespace storm { template class LpMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: - LpMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); - LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); - LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); + LpMinMaxLinearEquationSolver(std::unique_ptr>&& lpSolverFactory); + LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& lpSolverFactory); + LpMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& lpSolverFactory); virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; virtual void clearCache() const override; - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const override; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override; private: std::unique_ptr> lpSolverFactory; }; - template - class LpMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - LpMinMaxLinearEquationSolverFactory(); - LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& lpSolverFactory); - LpMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory, std::unique_ptr>&& lpSolverFactory); - - // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - private: - std::unique_ptr> lpSolverFactory; - }; } } diff --git a/src/storm/solver/MathsatSmtSolver.cpp b/src/storm/solver/MathsatSmtSolver.cpp index 9b6f7da2b..219efe530 100644 --- a/src/storm/solver/MathsatSmtSolver.cpp +++ b/src/storm/solver/MathsatSmtSolver.cpp @@ -139,7 +139,13 @@ namespace storm { void MathsatSmtSolver::add(storm::expressions::Expression const& e) { #ifdef STORM_HAVE_MSAT - msat_assert_formula(env, expressionAdapter->translateExpression(e)); + msat_term expression = expressionAdapter->translateExpression(e); + msat_assert_formula(env, expression); + if (expressionAdapter->hasAdditionalConstraints()) { + for (auto const& constraint : expressionAdapter->getAdditionalConstraints()) { + msat_assert_formula(env, constraint); + } + } #else STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without MathSAT support."); #endif diff --git a/src/storm/solver/MinMaxLinearEquationSolver.cpp b/src/storm/solver/MinMaxLinearEquationSolver.cpp index a061c451d..f7cbf4bfe 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolver.cpp @@ -5,6 +5,7 @@ #include "storm/solver/LinearEquationSolver.h" #include "storm/solver/IterativeMinMaxLinearEquationSolver.h" #include "storm/solver/TopologicalMinMaxLinearEquationSolver.h" +#include "storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h" #include "storm/solver/LpMinMaxLinearEquationSolver.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" @@ -39,12 +40,6 @@ namespace storm { solveEquations(env, convert(this->direction), x, b); } - template - void MinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, std::vector& x, std::vector* b, uint_fast64_t n) const { - STORM_LOG_THROW(isSet(this->direction), storm::exceptions::IllegalFunctionCallException, "Optimization direction not set."); - return repeatedMultiply(env, convert(this->direction), x, b, n); - } - template void MinMaxLinearEquationSolver::setOptimizationDirection(OptimizationDirection d) { direction = convert(d); @@ -136,7 +131,7 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver::getRequirements(Environment const&, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver::getRequirements(Environment const&, boost::optional const& direction, bool const& hasInitialScheduler) const { return MinMaxLinearEquationSolverRequirements(); } @@ -166,11 +161,11 @@ namespace storm { } template - MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory::getRequirements(Environment const& env, bool hasUniqueSolution, boost::optional const& direction, bool const& assumeNoInitialScheduler) const { + MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory::getRequirements(Environment const& env, bool hasUniqueSolution, boost::optional const& direction, bool const& hasInitialScheduler) const { // Create dummy solver and ask it for requirements. std::unique_ptr> solver = this->create(env); solver->setHasUniqueSolution(hasUniqueSolution); - return solver->getRequirements(env, direction, assumeNoInitialScheduler); + return solver->getRequirements(env, direction, hasInitialScheduler); } template @@ -196,12 +191,14 @@ namespace storm { std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::Topological) { result = std::make_unique>(); + } else if (method == MinMaxMethod::TopologicalCuda) { + result = std::make_unique>(); } else if (method == MinMaxMethod::LinearProgramming) { - result = std::make_unique>(std::make_unique>(), std::make_unique>()); + result = std::make_unique>(std::make_unique>()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } @@ -213,10 +210,12 @@ namespace storm { std::unique_ptr> GeneralMinMaxLinearEquationSolverFactory::create(Environment const& env) const { std::unique_ptr> result; auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) { + if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::IntervalIteration || method == MinMaxMethod::SoundValueIteration) { result = std::make_unique>(std::make_unique>()); } else if (method == MinMaxMethod::LinearProgramming) { - result = std::make_unique>(std::make_unique>(), std::make_unique>()); + result = std::make_unique>(std::make_unique>()); + } else if (method == MinMaxMethod::Topological) { + result = std::make_unique>(); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique."); } diff --git a/src/storm/solver/MinMaxLinearEquationSolver.h b/src/storm/solver/MinMaxLinearEquationSolver.h index cb442e0f4..9ea9ac90a 100644 --- a/src/storm/solver/MinMaxLinearEquationSolver.h +++ b/src/storm/solver/MinMaxLinearEquationSolver.h @@ -60,32 +60,6 @@ namespace storm { */ void solveEquations(Environment const& env, std::vector& x, std::vector const& b) const; - /*! - * Performs (repeated) matrix-vector multiplication with the given parameters, i.e. computes - * x[i+1] = min/max(A*x[i] + b) until x[n], where x[0] = x. After each multiplication and addition, the - * minimal/maximal value out of each row group is selected to reduce the resulting vector to obtain the - * vector for the next iteration. Note that the matrix A has to be given upon construction time of the - * solver object. - * - * @param d For minimum, all the value of a group of rows is the taken as the minimum over all rows and as - * the maximum otherwise. - * @param x The initial vector that is to be multiplied with the matrix. This is also the output parameter, - * i.e. after the method returns, this vector will contain the computed values. - * @param b If not null, this vector is added after each multiplication. - * @param n Specifies the number of iterations the matrix-vector multiplication is performed. - * @param multiplyResult If non-null, this memory is used as a scratch memory. If given, the length of this - * vector must be equal to the number of rows of A. - * @return The result of the repeated matrix-vector multiplication as the content of the vector x. - */ - virtual void repeatedMultiply(Environment const& env, OptimizationDirection d, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const = 0; - - /*! - * Behaves the same as the other variant of multiply, with the - * distinction that instead of providing the optimization direction as an argument, the internally set - * optimization direction is used. Note: this method can only be called after setting the optimization direction. - */ - virtual void repeatedMultiply(Environment const& env, std::vector& x, std::vector* b , uint_fast64_t n) const; - /*! * Sets an optimization direction to use for calls to methods that do not explicitly provide one. */ @@ -167,7 +141,7 @@ namespace storm { * Retrieves the requirements of this solver for solving equations with the current settings. The requirements * are guaranteed to be ordered according to their appearance in the SolverRequirement type. */ - virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const; + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const; /*! * Notifies the solver that the requirements for solving equations have been checked. If this has not been @@ -196,7 +170,7 @@ namespace storm { boost::optional> initialScheduler; private: - // Whether the solver can assume that the min-max equation system has a unique solution + /// Whether the solver can assume that the min-max equation system has a unique solution bool uniqueSolution; /// Whether some of the generated data during solver calls should be cached. @@ -220,7 +194,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 const& direction = boost::none, bool const& assumeNoInitialScheduler = false) const; + MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, bool hasUniqueSolution = false, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const; void setRequirementsChecked(bool value = true); bool isRequirementsCheckedSet() const; diff --git a/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp b/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp index 005d57977..e16bbdf54 100644 --- a/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp +++ b/src/storm/solver/MinMaxLinearEquationSolverRequirements.cpp @@ -3,76 +3,76 @@ namespace storm { namespace solver { - MinMaxLinearEquationSolverRequirements::MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements) : noEndComponents(false), validInitialScheduler(false), lowerBounds(linearEquationSolverRequirements.requiresLowerBounds()), upperBounds(linearEquationSolverRequirements.requiresUpperBounds()) { + MinMaxLinearEquationSolverRequirements::MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements) : lowerBoundsRequirement(linearEquationSolverRequirements.lowerBounds()), upperBoundsRequirement(linearEquationSolverRequirements.upperBounds()) { // Intentionally left empty. } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireNoEndComponents() { - noEndComponents = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireNoEndComponents(bool critical) { + noEndComponentsRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireValidInitialScheduler() { - validInitialScheduler = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireValidInitialScheduler(bool critical) { + validInitialSchedulerRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireLowerBounds() { - lowerBounds = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireLowerBounds(bool critical) { + lowerBoundsRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireUpperBounds() { - upperBounds = true; + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireUpperBounds(bool critical) { + upperBoundsRequirement.enable(critical); return *this; } - MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireBounds() { - requireLowerBounds(); - requireUpperBounds(); + MinMaxLinearEquationSolverRequirements& MinMaxLinearEquationSolverRequirements::requireBounds(bool critical) { + requireLowerBounds(critical); + requireUpperBounds(critical); return *this; } - bool MinMaxLinearEquationSolverRequirements::requiresNoEndComponents() const { - return noEndComponents; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::noEndComponents() const { + return noEndComponentsRequirement; } - bool MinMaxLinearEquationSolverRequirements::requiresValidInitialScheduler() const { - return validInitialScheduler; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::validInitialScheduler() const { + return validInitialSchedulerRequirement; } - bool MinMaxLinearEquationSolverRequirements::requiresLowerBounds() const { - return lowerBounds; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::lowerBounds() const { + return lowerBoundsRequirement; } - bool MinMaxLinearEquationSolverRequirements::requiresUpperBounds() const { - return upperBounds; + SolverRequirement const& MinMaxLinearEquationSolverRequirements::upperBounds() const { + return upperBoundsRequirement; } - bool MinMaxLinearEquationSolverRequirements::requires(Element const& element) const { + SolverRequirement const& MinMaxLinearEquationSolverRequirements::get(Element const& element) const { switch (element) { - case Element::NoEndComponents: return noEndComponents; break; - case Element::ValidInitialScheduler: return validInitialScheduler; break; - case Element::LowerBounds: return lowerBounds; break; - case Element::UpperBounds: return upperBounds; break; + case Element::NoEndComponents: return noEndComponents(); break; + case Element::ValidInitialScheduler: return validInitialScheduler(); break; + case Element::LowerBounds: return lowerBounds(); break; + case Element::UpperBounds: return upperBounds(); break; } } void MinMaxLinearEquationSolverRequirements::clearNoEndComponents() { - noEndComponents = false; - validInitialScheduler = false; + noEndComponentsRequirement.clear(); + validInitialSchedulerRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearValidInitialScheduler() { - validInitialScheduler = false; + validInitialSchedulerRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearLowerBounds() { - lowerBounds = false; + lowerBoundsRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearUpperBounds() { - upperBounds = false; + upperBoundsRequirement.clear(); } void MinMaxLinearEquationSolverRequirements::clearBounds() { @@ -80,8 +80,47 @@ namespace storm { clearUpperBounds(); } - bool MinMaxLinearEquationSolverRequirements::empty() const { - return !noEndComponents && !validInitialScheduler && !lowerBounds && !upperBounds; + bool MinMaxLinearEquationSolverRequirements::hasEnabledRequirement() const { + return noEndComponentsRequirement || validInitialSchedulerRequirement || lowerBoundsRequirement || upperBoundsRequirement; + } + + bool MinMaxLinearEquationSolverRequirements::hasEnabledCriticalRequirement() const { + return noEndComponentsRequirement.isCritical() || validInitialSchedulerRequirement.isCritical() || lowerBoundsRequirement.isCritical() || upperBoundsRequirement.isCritical(); + } + + std::string MinMaxLinearEquationSolverRequirements::getEnabledRequirementsAsString() const { + std::string res = "["; + bool first = true; + if (noEndComponents()) { + if (!first) { res += ", "; } else {first = false;} + res += "NoEndComponents"; + if (noEndComponents().isCritical()) { + res += "(mandatory)"; + } + } + if (validInitialScheduler()) { + if (!first) { res += ", "; } else {first = false;} + res += "validInitialScheduler"; + if (validInitialScheduler().isCritical()) { + res += "(mandatory)"; + } + } + if (lowerBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "lowerBounds"; + if (lowerBounds().isCritical()) { + res += "(mandatory)"; + } + } + if (upperBounds()) { + if (!first) { res += ", "; } else {first = false;} + res += "upperBounds"; + if (upperBounds().isCritical()) { + res += "(mandatory)"; + } + } + res += "]"; + return res; } } diff --git a/src/storm/solver/MinMaxLinearEquationSolverRequirements.h b/src/storm/solver/MinMaxLinearEquationSolverRequirements.h index 33e3511ad..06ba623c1 100644 --- a/src/storm/solver/MinMaxLinearEquationSolverRequirements.h +++ b/src/storm/solver/MinMaxLinearEquationSolverRequirements.h @@ -1,6 +1,9 @@ #pragma once +#include + #include "storm/solver/LinearEquationSolverRequirements.h" +#include "storm/solver/SolverRequirement.h" namespace storm { namespace solver { @@ -20,19 +23,21 @@ namespace storm { UpperBounds }; + // The type of a requirement. + MinMaxLinearEquationSolverRequirements(LinearEquationSolverRequirements const& linearEquationSolverRequirements = LinearEquationSolverRequirements()); - MinMaxLinearEquationSolverRequirements& requireNoEndComponents(); - MinMaxLinearEquationSolverRequirements& requireValidInitialScheduler(); - MinMaxLinearEquationSolverRequirements& requireLowerBounds(); - MinMaxLinearEquationSolverRequirements& requireUpperBounds(); - MinMaxLinearEquationSolverRequirements& requireBounds(); + MinMaxLinearEquationSolverRequirements& requireNoEndComponents(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireValidInitialScheduler(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireLowerBounds(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireUpperBounds(bool critical = true); + MinMaxLinearEquationSolverRequirements& requireBounds(bool critical = true); - bool requiresNoEndComponents() const; - bool requiresValidInitialScheduler() const; - bool requiresLowerBounds() const; - bool requiresUpperBounds() const; - bool requires(Element const& element) const; + SolverRequirement const& noEndComponents() const; + SolverRequirement const& validInitialScheduler() const; + SolverRequirement const& lowerBounds() const; + SolverRequirement const& upperBounds() const; + SolverRequirement const& get(Element const& element) const; void clearNoEndComponents(); void clearValidInitialScheduler(); @@ -40,13 +45,19 @@ namespace storm { void clearUpperBounds(); void clearBounds(); - bool empty() const; + bool hasEnabledRequirement() const; + bool hasEnabledCriticalRequirement() const; + + /*! + * Returns a string that enumerates the enabled requirements + */ + std::string getEnabledRequirementsAsString() const; private: - bool noEndComponents; - bool validInitialScheduler; - bool lowerBounds; - bool upperBounds; + SolverRequirement noEndComponentsRequirement; + SolverRequirement validInitialSchedulerRequirement; + SolverRequirement lowerBoundsRequirement; + SolverRequirement upperBoundsRequirement; }; } diff --git a/src/storm/solver/Multiplier.cpp b/src/storm/solver/Multiplier.cpp new file mode 100644 index 000000000..3347ef2dc --- /dev/null +++ b/src/storm/solver/Multiplier.cpp @@ -0,0 +1,95 @@ +#include "storm/solver/Multiplier.h" + +#include "storm-config.h" + +#include "storm/storage/SparseMatrix.h" + +#include "storm/adapters/RationalNumberAdapter.h" +#include "storm/adapters/RationalFunctionAdapter.h" + +#include "storm/utility/macros.h" +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/solver/NativeMultiplier.h" +#include "storm/solver/GmmxxMultiplier.h" +#include "storm/environment/solver/MultiplierEnvironment.h" + +namespace storm { + namespace solver { + + template + Multiplier::Multiplier(storm::storage::SparseMatrix const& matrix) : matrix(matrix) { + // Intentionally left empty. + } + + template + void Multiplier::clearCache() const { + cachedVector.reset(); + } + + template + void Multiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + multiplyAndReduce(env, dir, this->matrix.getRowGroupIndices(), x, b, result, choices); + } + + template + void Multiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices) const { + multiplyAndReduceGaussSeidel(env, dir, this->matrix.getRowGroupIndices(), x, b, choices); + } + + template + void Multiplier::repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const { + for (uint64_t i = 0; i < n; ++i) { + multiply(env, x, b, x); + } + } + + template + void Multiplier::repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const { + for (uint64_t i = 0; i < n; ++i) { + multiplyAndReduce(env, dir, x, b, x); + } + } + + template + void Multiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + multiplyRow(rowIndex, x1, val1); + multiplyRow(rowIndex, x2, val2); + } + + template + std::unique_ptr> MultiplierFactory::create(Environment const& env, storm::storage::SparseMatrix const& matrix) { + auto type = env.solver().multiplier().getType(); + + // Adjust the multiplier type if an eqsolver was specified but not a multiplier + if (!env.solver().isLinearEquationSolverTypeSetFromDefaultValue() && env.solver().multiplier().isTypeSetFromDefault()) { + bool changed = false; + if (env.solver().getLinearEquationSolverType() == EquationSolverType::Gmmxx && type != MultiplierType::Gmmxx) { + type = MultiplierType::Gmmxx; + changed = true; + } else if (env.solver().getLinearEquationSolverType() == EquationSolverType::Native && type != MultiplierType::Native) { + type = MultiplierType::Native; + changed = true; + } + STORM_LOG_INFO_COND(!changed, "Selecting '" + toString(type) + "' as the multiplier type to match the selected equation solver. If you want to override this, please explicitly specify a different multiplier type."); + } + + switch (type) { + case MultiplierType::Gmmxx: + return std::make_unique>(matrix); + case MultiplierType::Native: + return std::make_unique>(matrix); + } + } + + template class Multiplier; + template class MultiplierFactory; + +#ifdef STORM_HAVE_CARL + template class Multiplier; + template class MultiplierFactory; + template class Multiplier; + template class MultiplierFactory; +#endif + + } +} diff --git a/src/storm/solver/Multiplier.h b/src/storm/solver/Multiplier.h new file mode 100644 index 000000000..5f9036022 --- /dev/null +++ b/src/storm/solver/Multiplier.h @@ -0,0 +1,150 @@ +#pragma once + +#include +#include + +#include "storm/solver/OptimizationDirection.h" +#include "storm/solver/MultiplicationStyle.h" + +namespace storm { + + class Environment; + + namespace storage { + template + class SparseMatrix; + } + + namespace solver { + + template + class Multiplier { + public: + + Multiplier(storm::storage::SparseMatrix const& matrix); + + virtual ~Multiplier() = default; + + /* + * Clears the currently cached data of this multiplier in order to free some memory. + */ + virtual void clearCache() const; + + /*! + * Performs a matrix-vector multiplication x' = A*x + b. + * + * @param x The input vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. Can be the same as the x vector. + */ + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const = 0; + + /*! + * Performs a matrix-vector multiplication in gauss-seidel style. + * + * @param x The input/output vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + */ + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const = 0; + + /*! + * Performs a matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups + * so that the resulting vector has the size of number of row groups of A. + * + * @param dir The direction for the reduction step. + * @param rowGroupIndices A vector storing the row groups over which to reduce. + * @param x The input vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. Can be the same as the x vector. + * @param choices If given, the choices made in the reduction process are written to this vector. + */ + void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const = 0; + + /*! + * Performs a matrix-vector multiplication in gauss-seidel style and then minimizes/maximizes over the row groups + * so that the resulting vector has the size of number of row groups of A. + * + * @param dir The direction for the reduction step. + * @param rowGroupIndices A vector storing the row groups over which to reduce. + * @param x The input/output vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. Can be the same as the x vector. + * @param choices If given, the choices made in the reduction process are written to this vector. + */ + void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const = 0; + + /*! + * Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After + * performing the necessary multiplications, the result is written to the input vector x. Note that the + * matrix A has to be given upon construction time of the solver object. + * + * @param x The initial vector with which to perform matrix-vector multiplication. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after each multiplication. If given, its length must be equal + * to the number of rows of A. + * @param n The number of times to perform the multiplication. + */ + void repeatedMultiply(Environment const& env, std::vector& x, std::vector const* b, uint64_t n) const; + + /*! + * Performs repeated matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups + * so that the resulting vector has the size of number of row groups of A. + * + * @param dir The direction for the reduction step. + * @param x The input vector with which to multiply the matrix. Its length must be equal + * to the number of columns of A. + * @param b If non-null, this vector is added after the multiplication. If given, its length must be equal + * to the number of rows of A. + * @param result The target vector into which to write the multiplication result. Its length must be equal + * to the number of rows of A. + * @param n The number of times to perform the multiplication. + */ + void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector& x, std::vector const* b, uint64_t n) const; + + /*! + * Multiplies the row with the given index with x and adds the result to the provided value + * @param rowIndex The index of the considered row + * @param x The input vector with which the row is multiplied + * @param value The multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. + */ + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const = 0; + + /*! + * Multiplies the row with the given index with x1 and x2 and adds the given offset o1 and o2, respectively + * @param rowIndex The index of the considered row + * @param x1 The first input vector with which the row is multiplied. + * @param val1 The first multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. + * @param x2 The second input vector with which the row is multiplied. + * @param val2 The second multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix. + */ + virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const; + + protected: + mutable std::unique_ptr> cachedVector; + storm::storage::SparseMatrix const& matrix; + }; + + template + class MultiplierFactory { + public: + MultiplierFactory() = default; + ~MultiplierFactory() = default; + + std::unique_ptr> create(Environment const& env, storm::storage::SparseMatrix const& matrix); + }; + + } +} diff --git a/src/storm/solver/NativeLinearEquationSolver.cpp b/src/storm/solver/NativeLinearEquationSolver.cpp index d6de61266..ca0142249 100644 --- a/src/storm/solver/NativeLinearEquationSolver.cpp +++ b/src/storm/solver/NativeLinearEquationSolver.cpp @@ -1,5 +1,7 @@ #include "storm/solver/NativeLinearEquationSolver.h" +#include + #include "storm/environment/solver/NativeSolverEnvironment.h" #include "storm/utility/ConstantsComparator.h" @@ -7,10 +9,13 @@ #include "storm/utility/NumberTraits.h" #include "storm/utility/constants.h" #include "storm/utility/vector.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" +#include "storm/solver/Multiplier.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidEnvironmentException.h" #include "storm/exceptions/UnmetRequirementException.h" #include "storm/exceptions/PrecisionExceededException.h" +#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace solver { @@ -90,6 +95,14 @@ namespace storm { return converged; } + template + NativeLinearEquationSolver::JacobiDecomposition::JacobiDecomposition(Environment const& env, storm::storage::SparseMatrix const& A) { + auto decomposition = A.getJacobiDecomposition(); + this->LUMatrix = std::move(decomposition.first); + this->DVector = std::move(decomposition.second); + this->multiplier = storm::solver::MultiplierFactory().create(env, this->LUMatrix); + } + template bool NativeLinearEquationSolver::solveEquationsJacobi(Environment const& env, std::vector& x, std::vector const& b) const { STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (Jacobi)"); @@ -100,16 +113,13 @@ namespace storm { // Get a Jacobi decomposition of the matrix A. if (!jacobiDecomposition) { - jacobiDecomposition = std::make_unique, std::vector>>(A->getJacobiDecomposition()); + jacobiDecomposition = std::make_unique(env, *A); } ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); uint64_t maxIter = env.solver().native().getMaximalNumberOfIterations(); bool relative = env.solver().native().getRelativeTerminationCriterion(); - storm::storage::SparseMatrix const& jacobiLU = jacobiDecomposition->first; - std::vector const& jacobiD = jacobiDecomposition->second; - std::vector* currentX = &x; std::vector* nextX = this->cachedRowVector.get(); @@ -121,10 +131,9 @@ namespace storm { this->startMeasureProgress(); while (!converged && !terminate && iterations < maxIter) { // Compute D^-1 * (b - LU * x) and store result in nextX. - multiplier.multAdd(jacobiLU, *currentX, nullptr, *nextX); - + jacobiDecomposition->multiplier->multiply(env, *currentX, nullptr, *nextX); storm::utility::vector::subtractVectors(b, *nextX, *nextX); - storm::utility::vector::multiplyVectorsPointwise(jacobiD, *nextX, *nextX); + storm::utility::vector::multiplyVectorsPointwise(jacobiDecomposition->DVector, *nextX, *nextX); // Now check if the process already converged within our precision. converged = storm::utility::vector::equalModuloPrecision(*currentX, *nextX, precision, relative); @@ -156,10 +165,11 @@ namespace storm { } template - NativeLinearEquationSolver::WalkerChaeData::WalkerChaeData(storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB) : t(storm::utility::convertNumber(1000.0)) { + NativeLinearEquationSolver::WalkerChaeData::WalkerChaeData(Environment const& env, storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB) : t(storm::utility::convertNumber(1000.0)) { computeWalkerChaeMatrix(originalMatrix); computeNewB(originalB); precomputeAuxiliaryData(); + multiplier = storm::solver::MultiplierFactory().create(env, this->matrix); } template @@ -218,7 +228,7 @@ namespace storm { // (1) Compute an equivalent equation system that has only non-negative coefficients. if (!walkerChaeData) { - walkerChaeData = std::make_unique(*this->A, b); + walkerChaeData = std::make_unique(env, *this->A, b); } // (2) Enlarge the vectors x and b to account for additional variables. @@ -235,14 +245,14 @@ namespace storm { std::vector* nextX = &walkerChaeData->newX; std::vector tmp = walkerChaeData->matrix.getRowSumVector(); - storm::utility::vector::applyPointwise(tmp, walkerChaeData->b, walkerChaeData->b, [this] (ValueType const& first, ValueType const& second) { return walkerChaeData->t * first + second; } ); + storm::utility::vector::applyPointwise(tmp, walkerChaeData->b, walkerChaeData->b, [this] (ValueType const& first, ValueType const& second) -> ValueType { return walkerChaeData->t * first + second; } ); // Add t to all entries of x. - storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) { return value + walkerChaeData->t; }); + storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) -> ValueType { return value + walkerChaeData->t; }); // Create a vector that always holds Ax. std::vector currentAx(x.size()); - multiplier.multAdd(walkerChaeData->matrix, *currentX, nullptr, currentAx); + walkerChaeData->multiplier->multiply(env, *currentX, nullptr, currentAx); // (3) Perform iterations until convergence. bool converged = false; @@ -253,7 +263,7 @@ namespace storm { walkerChaeData->matrix.performWalkerChaeStep(*currentX, walkerChaeData->columnSums, walkerChaeData->b, currentAx, *nextX); // Compute new Ax. - multiplier.multAdd(walkerChaeData->matrix, *nextX, nullptr, currentAx); + walkerChaeData->multiplier->multiply(env, *nextX, nullptr, currentAx); // Check for convergence. converged = storm::utility::vector::computeSquaredNorm2Difference(currentAx, walkerChaeData->b) <= squaredErrorBound; @@ -278,7 +288,7 @@ namespace storm { x.resize(this->A->getRowCount()); // Finalize solution vector. - storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) { return value - walkerChaeData->t; } ); + storm::utility::vector::applyPointwise(x, x, [this] (ValueType const& value) -> ValueType { return value - walkerChaeData->t; } ); if (!this->isCachingEnabled()) { clearCache(); @@ -294,38 +304,31 @@ namespace storm { } template - typename NativeLinearEquationSolver::PowerIterationResult NativeLinearEquationSolver::performPowerIteration(std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { + typename NativeLinearEquationSolver::PowerIterationResult NativeLinearEquationSolver::performPowerIteration(Environment const& env, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const { bool useGaussSeidelMultiplication = multiplicationStyle == storm::solver::MultiplicationStyle::GaussSeidel; - std::vector* originalX = currentX; - bool converged = false; bool terminate = this->terminateNow(*currentX, guarantee); uint64_t iterations = currentIterations; while (!converged && !terminate && iterations < maxIterations) { if (useGaussSeidelMultiplication) { *newX = *currentX; - this->multiplier.multAddGaussSeidelBackward(*this->A, *newX, &b); + this->multiplier->multiplyGaussSeidel(env, *newX, &b); } else { - this->multiplier.multAdd(*this->A, *currentX, &b, *newX); + this->multiplier->multiply(env, *currentX, &b, *newX); } - // Now check for termination. + // Check for convergence. converged = storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative); + + // Check for termination. + std::swap(currentX, newX); + ++iterations; terminate = this->terminateNow(*currentX, guarantee); // Potentially show progress. this->showProgressIterative(iterations); - - // Set up next iteration. - std::swap(currentX, newX); - ++iterations; - } - - // Swap the pointers so that the output is always in currentX. - if (originalX == newX) { - std::swap(currentX, newX); } return PowerIterationResult(iterations - currentIterations, converged ? SolverStatus::Converged : (terminate ? SolverStatus::TerminatedEarly : SolverStatus::MaximalIterationsExceeded)); @@ -339,6 +342,9 @@ namespace storm { if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(getMatrixRowCount()); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } std::vector* currentX = &x; SolverGuarantee guarantee = SolverGuarantee::None; if (this->hasCustomTerminationCondition()) { @@ -355,7 +361,7 @@ namespace storm { // Forward call to power iteration implementation. this->startMeasureProgress(); ValueType precision = storm::utility::convertNumber(env.solver().native().getPrecision()); - PowerIterationResult result = this->performPowerIteration(currentX, newX, b, precision, env.solver().native().getRelativeTerminationCriterion(), guarantee, 0, env.solver().native().getMaximalNumberOfIterations(), env.solver().native().getPowerMethodMultiplicationStyle()); + PowerIterationResult result = this->performPowerIteration(env, currentX, newX, b, precision, env.solver().native().getRelativeTerminationCriterion(), guarantee, 0, env.solver().native().getMaximalNumberOfIterations(), env.solver().native().getPowerMethodMultiplicationStyle()); // Swap the result in place. if (currentX == this->cachedRowVector.get()) { @@ -396,10 +402,10 @@ namespace storm { } template - bool NativeLinearEquationSolver::solveEquationsSoundPower(Environment const& env, std::vector& x, std::vector const& b) const { + bool NativeLinearEquationSolver::solveEquationsIntervalIteration(Environment const& env, std::vector& x, std::vector const& b) const { STORM_LOG_THROW(this->hasLowerBound(), storm::exceptions::UnmetRequirementException, "Solver requires lower bound, but none was given."); STORM_LOG_THROW(this->hasUpperBound(), storm::exceptions::UnmetRequirementException, "Solver requires upper bound, but none was given."); - STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (SoundPower)"); + STORM_LOG_INFO("Solving linear equation system (" << x.size() << " rows) with NativeLinearEquationSolver (IntervalIteration)"); std::vector* lowerX = &x; this->createLowerBoundsVector(*lowerX); @@ -413,11 +419,15 @@ namespace storm { tmp = cachedRowVector2.get(); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } + bool converged = false; bool terminate = false; uint64_t iterations = 0; bool doConvergenceCheck = true; - bool useDiffs = this->hasRelevantValues(); + bool useDiffs = this->hasRelevantValues() && !env.solver().native().isSymmetricUpdatesSet(); std::vector oldValues; if (useGaussSeidelMultiplication && useDiffs) { oldValues.resize(this->getRelevantValues().getNumberOfSetBits()); @@ -444,22 +454,22 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *lowerX, &b); + this->multiplier->multiplyGaussSeidel(env, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *upperX, &b); + this->multiplier->multiplyGaussSeidel(env, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } } else { - this->multiplier.multAdd(*this->A, *lowerX, &b, *tmp); + this->multiplier->multiply(env, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(tmp, lowerX); - this->multiplier.multAdd(*this->A, *upperX, &b, *tmp); + this->multiplier->multiply(env, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -472,7 +482,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*lowerX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *lowerX, &b); + this->multiplier->multiplyGaussSeidel(env, *lowerX, &b); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, this->getRelevantValues(), oldValues); } @@ -481,7 +491,7 @@ namespace storm { if (useDiffs) { preserveOldRelevantValues(*upperX, this->getRelevantValues(), oldValues); } - this->multiplier.multAddGaussSeidelBackward(*this->A, *upperX, &b); + this->multiplier->multiplyGaussSeidel(env, *upperX, &b); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, this->getRelevantValues(), oldValues); } @@ -489,14 +499,14 @@ namespace storm { } } else { if (maxLowerDiff >= maxUpperDiff) { - this->multiplier.multAdd(*this->A, *lowerX, &b, *tmp); + this->multiplier->multiply(env, *lowerX, &b, *tmp); if (useDiffs) { maxLowerDiff = computeMaxAbsDiff(*lowerX, *tmp, this->getRelevantValues()); } std::swap(tmp, lowerX); lowerStep = true; } else { - this->multiplier.multAdd(*this->A, *upperX, &b, *tmp); + this->multiplier->multiply(env, *upperX, &b, *tmp); if (useDiffs) { maxUpperDiff = computeMaxAbsDiff(*upperX, *tmp, this->getRelevantValues()); } @@ -537,7 +547,7 @@ namespace storm { } // We take the means of the lower and upper bound so we guarantee the desired precision. - storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [] (ValueType const& a, ValueType const& b) { return (a + b) / storm::utility::convertNumber(2.0); }); + storm::utility::vector::applyPointwise(*lowerX, *upperX, *lowerX, [] (ValueType const& a, ValueType const& b) -> ValueType { return (a + b) / storm::utility::convertNumber(2.0); }); // Since we shuffled the pointer around, we need to write the actual results to the input/output vector x. if (&x == tmp) { @@ -549,12 +559,70 @@ namespace storm { if (!this->isCachingEnabled()) { clearCache(); } - this->logIterations(converged, terminate, iterations); return converged; } + + template + bool NativeLinearEquationSolver::solveEquationsSoundValueIteration(Environment const& env, std::vector& x, std::vector const& b) const { + + // Prepare the solution vectors and the helper. + assert(x.size() == this->A->getRowCount()); + if (!this->cachedRowVector) { + this->cachedRowVector = std::make_unique>(); + } + if (!this->soundValueIterationHelper) { + this->soundValueIterationHelper = std::make_unique>(*this->A, x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + } else { + this->soundValueIterationHelper = std::make_unique>(std::move(*this->soundValueIterationHelper), x, *this->cachedRowVector, env.solver().native().getRelativeTerminationCriterion(), storm::utility::convertNumber(env.solver().native().getPrecision())); + } + + // Prepare initial bounds for the solution (if given) + if (this->hasLowerBound()) { + this->soundValueIterationHelper->setLowerBound(this->getLowerBound(true)); + } + if (this->hasUpperBound()) { + this->soundValueIterationHelper->setUpperBound(this->getUpperBound(true)); + } + + storm::storage::BitVector const* relevantValuesPtr = nullptr; + if (this->hasRelevantValues()) { + relevantValuesPtr = &this->getRelevantValues(); + } + + bool converged = false; + bool terminate = false; + this->startMeasureProgress(); + uint64_t iterations = 0; + + while (!converged && iterations < env.solver().native().getMaximalNumberOfIterations()) { + this->soundValueIterationHelper->performIterationStep(b); + if (this->soundValueIterationHelper->checkConvergenceUpdateBounds(relevantValuesPtr)) { + converged = true; + } + + // Check whether we terminate early. + terminate = this->hasCustomTerminationCondition() && this->soundValueIterationHelper->checkCustomTerminationCondition(this->getTerminationCondition()); + + // Update environment variables. + ++iterations; + + // Potentially show progress. + this->showProgressIterative(iterations); + } + this->soundValueIterationHelper->setSolutionVector(); + + this->logIterations(converged, terminate, iterations); + + if (!this->isCachingEnabled()) { + clearCache(); + } + + return converged; + } + template bool NativeLinearEquationSolver::solveEquationsRationalSearch(Environment const& env, std::vector& x, std::vector const& b) const { return solveEquationsRationalSearchHelper(env, x, b); @@ -601,6 +669,8 @@ namespace storm { bool relative = env.solver().native().getRelativeTerminationCriterion(); auto multiplicationStyle = env.solver().native().getPowerMethodMultiplicationStyle(); + std::vector const* originalX = &x; + std::vector* currentX = &x; std::vector* newX = &tmpX; @@ -610,7 +680,7 @@ namespace storm { impreciseSolver.startMeasureProgress(); while (status == SolverStatus::InProgress && overallIterations < maxIter) { // Perform value iteration with the current precision. - typename NativeLinearEquationSolver::PowerIterationResult result = impreciseSolver.performPowerIteration(currentX, newX, b, storm::utility::convertNumber(precision), relative, SolverGuarantee::LessOrEqual, overallIterations, maxIter, multiplicationStyle); + typename NativeLinearEquationSolver::PowerIterationResult result = impreciseSolver.performPowerIteration(env, currentX, newX, b, storm::utility::convertNumber(precision), relative, SolverGuarantee::LessOrEqual, overallIterations, maxIter, multiplicationStyle); // At this point, the result of the imprecise value iteration is stored in the (imprecise) current x. @@ -625,10 +695,10 @@ namespace storm { // Make sure that currentX and rationalX are not aliased. std::vector* temporaryRational = TemporaryHelper::getTemporary(rationalX, currentX, newX); - + // Sharpen solution and place it in the temporary rational. bool foundSolution = sharpen(p, rationalA, *currentX, rationalB, *temporaryRational); - + // After sharpen, if a solution was found, it is contained in the free rational. if (foundSolution) { @@ -641,6 +711,11 @@ namespace storm { } } + // Swap the two vectors if the current result is not in the original x. + if (currentX != originalX) { + std::swap(x, tmpX); + } + if (status == SolverStatus::InProgress && overallIterations == maxIter) { status = SolverStatus::MaximalIterationsExceeded; } @@ -663,6 +738,9 @@ namespace storm { if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(this->A->getRowCount()); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } // Forward the call to the core rational search routine. bool converged = solveEquationsRationalSearchHelper(env, *this, rationalA, rationalX, rationalB, *this->A, x, b, *this->cachedRowVector); @@ -685,14 +763,12 @@ namespace storm { typename std::enable_if::value && NumberTraits::IsExact, bool>::type NativeLinearEquationSolver::solveEquationsRationalSearchHelper(Environment const& env, std::vector& x, std::vector const& b) const { // Version for when the overall value type is exact and the same type is to be used for the imprecise part. - if (!this->linEqSolverA) { - this->linEqSolverA = this->linearEquationSolverFactory->create(*this->A); - this->linEqSolverA->setCachingEnabled(true); - } - if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(this->A->getRowCount()); } + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } // Forward the call to the core rational search routine. bool converged = solveEquationsRationalSearchHelper(env, *this, *this->A, x, b, *this->A, *this->cachedRowVector, b, x); @@ -738,18 +814,22 @@ namespace storm { NativeLinearEquationSolver impreciseSolver; impreciseSolver.setMatrix(impreciseA); impreciseSolver.setCachingEnabled(true); - + impreciseSolver.multiplier = storm::solver::MultiplierFactory().create(env, impreciseA); + bool converged = false; try { // Forward the call to the core rational search routine. converged = solveEquationsRationalSearchHelper(env, impreciseSolver, *this->A, x, b, impreciseA, impreciseX, impreciseB, impreciseTmpX); + impreciseSolver.clearCache(); } catch (storm::exceptions::PrecisionExceededException const& e) { STORM_LOG_WARN("Precision of value type was exceeded, trying to recover by switching to rational arithmetic."); if (!this->cachedRowVector) { this->cachedRowVector = std::make_unique>(this->A->getRowGroupCount()); } - + if (!this->multiplier) { + this->multiplier = storm::solver::MultiplierFactory().create(env, *A); + } // Translate the imprecise value iteration result to the one we are going to use from now on. auto targetIt = this->cachedRowVector->begin(); for (auto it = impreciseX.begin(), ite = impreciseX.end(); it != ite; ++it, ++targetIt) { @@ -828,9 +908,9 @@ namespace storm { } else { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } - } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::Power && method != NativeLinearEquationSolverMethod::RationalSearch) { + } else if (env.solver().isForceSoundness() && method != NativeLinearEquationSolverMethod::SoundValueIteration && method != NativeLinearEquationSolverMethod::IntervalIteration && method != NativeLinearEquationSolverMethod::RationalSearch) { if (env.solver().native().isMethodSetFromDefault()) { - method = NativeLinearEquationSolverMethod::Power; + method = NativeLinearEquationSolverMethod::SoundValueIteration; STORM_LOG_INFO("Selecting '" + toString(method) + "' as the solution technique to guarantee sound results. If you want to override this, please explicitly specify a different method."); } else { STORM_LOG_WARN("The selected solution method does not guarantee sound results."); @@ -852,11 +932,11 @@ namespace storm { case NativeLinearEquationSolverMethod::WalkerChae: return this->solveEquationsWalkerChae(env, x, b); case NativeLinearEquationSolverMethod::Power: - if (env.solver().isForceSoundness()) { - return this->solveEquationsSoundPower(env, x, b); - } else { - return this->solveEquationsPower(env, x, b); - } + return this->solveEquationsPower(env, x, b); + case NativeLinearEquationSolverMethod::SoundValueIteration: + return this->solveEquationsSoundValueIteration(env, x, b); + case NativeLinearEquationSolverMethod::IntervalIteration: + return this->solveEquationsIntervalIteration(env, x, b); case NativeLinearEquationSolverMethod::RationalSearch: return this->solveEquationsRationalSearch(env, x, b); } @@ -864,64 +944,10 @@ namespace storm { return false; } - template - void NativeLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { - if (&x != &result) { - multiplier.multAdd(*A, x, b, result); - } else { - // If the two vectors are aliases, we need to create a temporary. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - multiplier.multAdd(*A, x, b, *this->cachedRowVector); - result.swap(*this->cachedRowVector); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - } - - template - void NativeLinearEquationSolver::multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices) const { - if (&x != &result) { - multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, result, choices); - } else { - // If the two vectors are aliases, we need to create a temporary. - if (!this->cachedRowVector) { - this->cachedRowVector = std::make_unique>(getMatrixRowCount()); - } - - multiplier.multAddReduce(dir, rowGroupIndices, *A, x, b, *this->cachedRowVector, choices); - result.swap(*this->cachedRowVector); - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - } - - template - bool NativeLinearEquationSolver::supportsGaussSeidelMultiplication() const { - return true; - } - - template - void NativeLinearEquationSolver::multiplyGaussSeidel(std::vector& x, std::vector const* b) const { - STORM_LOG_ASSERT(this->A->getRowCount() == this->A->getColumnCount(), "This function is only applicable for square matrices."); - multiplier.multAddGaussSeidelBackward(*A, x, b); - } - - template - void NativeLinearEquationSolver::multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { - multiplier.multAddReduceGaussSeidelBackward(dir, rowGroupIndices, *A, x, b, choices); - } - template LinearEquationSolverProblemFormat NativeLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::RationalSearch) { + if (method == NativeLinearEquationSolverMethod::Power || method == NativeLinearEquationSolverMethod::SoundValueIteration || method == NativeLinearEquationSolverMethod::RationalSearch || method == NativeLinearEquationSolverMethod::IntervalIteration) { return LinearEquationSolverProblemFormat::FixedPointSystem; } else { return LinearEquationSolverProblemFormat::EquationSystem; @@ -929,15 +955,15 @@ namespace storm { } template - LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env, LinearEquationSolverTask const& task) const { + LinearEquationSolverRequirements NativeLinearEquationSolver::getRequirements(Environment const& env) const { LinearEquationSolverRequirements requirements; - if (task != LinearEquationSolverTask::Multiply) { - auto method = getMethod(env, storm::NumberTraits::IsExact); - if (method == NativeLinearEquationSolverMethod::Power && env.solver().isForceSoundness()) { - requirements.requireBounds(); - } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { - requirements.requireLowerBounds(); - } + auto method = getMethod(env, storm::NumberTraits::IsExact); + if (method == NativeLinearEquationSolverMethod::IntervalIteration) { + requirements.requireBounds(); + } else if (method == NativeLinearEquationSolverMethod::RationalSearch) { + requirements.requireLowerBounds(); + } else if (method == NativeLinearEquationSolverMethod::SoundValueIteration) { + requirements.requireBounds(false); } return requirements; } @@ -947,6 +973,8 @@ namespace storm { jacobiDecomposition.reset(); cachedRowVector2.reset(); walkerChaeData.reset(); + multiplier.reset(); + soundValueIterationHelper.reset(); LinearEquationSolver::clearCache(); } @@ -961,7 +989,7 @@ namespace storm { } template - std::unique_ptr> NativeLinearEquationSolverFactory::create(Environment const& env, LinearEquationSolverTask const& task) const { + std::unique_ptr> NativeLinearEquationSolverFactory::create(Environment const& env) const { return std::make_unique>(); } diff --git a/src/storm/solver/NativeLinearEquationSolver.h b/src/storm/solver/NativeLinearEquationSolver.h index 136c8f68f..0cc493535 100644 --- a/src/storm/solver/NativeLinearEquationSolver.h +++ b/src/storm/solver/NativeLinearEquationSolver.h @@ -8,6 +8,7 @@ #include "storm/solver/SolverSelectionOptions.h" #include "storm/solver/NativeMultiplier.h" #include "storm/solver/SolverStatus.h" +#include "storm/solver/helper/SoundValueIterationHelper.h" #include "storm/utility/NumberTraits.h" @@ -30,14 +31,8 @@ namespace storm { virtual void setMatrix(storm::storage::SparseMatrix const& A) override; virtual void setMatrix(storm::storage::SparseMatrix&& A) override; - virtual void multiply(std::vector& x, std::vector const* b, std::vector& result) const override; - virtual void multiplyAndReduce(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; - virtual bool supportsGaussSeidelMultiplication() const override; - virtual void multiplyGaussSeidel(std::vector& x, std::vector const* b) const override; - virtual void multiplyAndReduceGaussSeidel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; - virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; - virtual LinearEquationSolverRequirements getRequirements(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const override; virtual void clearCache() const override; @@ -57,7 +52,7 @@ namespace storm { template friend class NativeLinearEquationSolver; - PowerIterationResult performPowerIteration(std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; + PowerIterationResult performPowerIteration(Environment const& env, std::vector*& currentX, std::vector*& newX, std::vector const& b, ValueType const& precision, bool relative, SolverGuarantee const& guarantee, uint64_t currentIterations, uint64_t maxIterations, storm::solver::MultiplicationStyle const& multiplicationStyle) const; void logIterations(bool converged, bool terminate, uint64_t iterations) const; @@ -70,7 +65,8 @@ namespace storm { virtual bool solveEquationsJacobi(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsWalkerChae(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; - virtual bool solveEquationsSoundPower(storm::Environment const& env, std::vector& x, std::vector const& b) const; + virtual bool solveEquationsSoundValueIteration(storm::Environment const& env, std::vector& x, std::vector const& b) const; + virtual bool solveEquationsIntervalIteration(storm::Environment const& env, std::vector& x, std::vector const& b) const; virtual bool solveEquationsRationalSearch(storm::Environment const& env, std::vector& x, std::vector const& b) const; template @@ -94,14 +90,23 @@ namespace storm { storm::storage::SparseMatrix const* A; // An object to dispatch all multiplication operations. - NativeMultiplier multiplier; + mutable std::unique_ptr> multiplier; // cached auxiliary data - mutable std::unique_ptr, std::vector>> jacobiDecomposition; mutable std::unique_ptr> cachedRowVector2; // A.getRowCount() rows + mutable std::unique_ptr> soundValueIterationHelper; + + struct JacobiDecomposition { + JacobiDecomposition(Environment const& env, storm::storage::SparseMatrix const& A); + + storm::storage::SparseMatrix LUMatrix; + std::vector DVector; + std::unique_ptr> multiplier; + }; + mutable std::unique_ptr jacobiDecomposition; struct WalkerChaeData { - WalkerChaeData(storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB); + WalkerChaeData(Environment const& env, storm::storage::SparseMatrix const& originalMatrix, std::vector const& originalB); void computeWalkerChaeMatrix(storm::storage::SparseMatrix const& originalMatrix); void computeNewB(std::vector const& originalB); @@ -110,6 +115,7 @@ namespace storm { storm::storage::SparseMatrix matrix; std::vector b; ValueType t; + std::unique_ptr> multiplier; // Auxiliary data. std::vector columnSums; @@ -123,7 +129,7 @@ namespace storm { public: using LinearEquationSolverFactory::create; - virtual std::unique_ptr> create(Environment const& env, LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) const override; + virtual std::unique_ptr> create(Environment const& env) const override; virtual std::unique_ptr> clone() const override; diff --git a/src/storm/solver/NativeMultiplier.cpp b/src/storm/solver/NativeMultiplier.cpp index f5fc1d903..7dd2457df 100644 --- a/src/storm/solver/NativeMultiplier.cpp +++ b/src/storm/solver/NativeMultiplier.cpp @@ -2,6 +2,10 @@ #include "storm-config.h" +#include "storm/environment/solver/MultiplierEnvironment.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + #include "storm/storage/SparseMatrix.h" #include "storm/adapters/RationalNumberAdapter.h" @@ -13,85 +17,117 @@ namespace storm { namespace solver { template - NativeMultiplier::NativeMultiplier() : storm::utility::VectorHelper() { + NativeMultiplier::NativeMultiplier(storm::storage::SparseMatrix const& matrix) : Multiplier(matrix) { // Intentionally left empty. } - + template - void NativeMultiplier::multAdd(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { + bool NativeMultiplier::parallelize(Environment const& env) const { +#ifdef STORM_HAVE_INTELTBB + return storm::settings::getModule().isUseIntelTbbSet(); +#else + return false; +#endif + } + + template + void NativeMultiplier::multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const { std::vector* target = &result; - std::unique_ptr> temporary; if (&x == &result) { - STORM_LOG_WARN("Using temporary in 'multAdd'."); - temporary = std::make_unique>(x.size()); - target = temporary.get(); + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); } - - if (this->parallelize()) { - multAddParallel(matrix, x, b, result); + if (parallelize(env)) { + multAddParallel(x, b, *target); } else { - matrix.multiplyWithVector(x, result, b); + multAdd(x, b, *target); } - - if (target == temporary.get()) { - std::swap(result, *temporary); + if (&x == &result) { + std::swap(result, *this->cachedVector); } } template - void NativeMultiplier::multAddGaussSeidelBackward(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b) const { - matrix.multiplyWithVectorBackward(x, x, b); + void NativeMultiplier::multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const { + this->matrix.multiplyWithVectorBackward(x, x, b); } template - void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + void NativeMultiplier::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { std::vector* target = &result; - std::unique_ptr> temporary; if (&x == &result) { - STORM_LOG_WARN("Using temporary in 'multAddReduce'."); - temporary = std::make_unique>(x.size()); - target = temporary.get(); + if (this->cachedVector) { + this->cachedVector->resize(x.size()); + } else { + this->cachedVector = std::make_unique>(x.size()); + } + target = this->cachedVector.get(); } - - if (this->parallelize()) { - multAddReduceParallel(dir, rowGroupIndices, matrix, x, b, *target, choices); + if (parallelize(env)) { + multAddReduceParallel(dir, rowGroupIndices, x, b, *target, choices); } else { - matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, *target, choices); + multAddReduce(dir, rowGroupIndices, x, b, *target, choices); } - - if (target == temporary.get()) { - std::swap(result, *temporary); + if (&x == &result) { + std::swap(result, *this->cachedVector); } } template - void NativeMultiplier::multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices) const { - matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); + void NativeMultiplier::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices) const { + this->matrix.multiplyAndReduceBackward(dir, rowGroupIndices, x, b, x, choices); } - + template - void NativeMultiplier::multAddParallel(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const { + void NativeMultiplier::multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + value += entry.getValue() * x[entry.getColumn()]; + } + } + + template + void NativeMultiplier::multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const { + for (auto const& entry : this->matrix.getRow(rowIndex)) { + val1 += entry.getValue() * x1[entry.getColumn()]; + val2 += entry.getValue() * x2[entry.getColumn()]; + } + } + + template + void NativeMultiplier::multAdd(std::vector const& x, std::vector const* b, std::vector& result) const { + this->matrix.multiplyWithVector(x, result, b); + } + + template + void NativeMultiplier::multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + this->matrix.multiplyAndReduce(dir, rowGroupIndices, x, b, result, choices); + } + + template + void NativeMultiplier::multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const { #ifdef STORM_HAVE_INTELTBB - matrix.multiplyWithVectorParallel(x, result, b); + this->matrix.multiplyWithVectorParallel(x, result, b); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAdd(matrix, x, b, result); + multAdd(x, b, result); #endif } template - void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { + void NativeMultiplier::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices) const { #ifdef STORM_HAVE_INTELTBB - matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); + this->matrix.multiplyAndReduceParallel(dir, rowGroupIndices, x, b, result, choices); #else STORM_LOG_WARN("Storm was built without support for Intel TBB, defaulting to sequential version."); - multAddReduce(dir, rowGroupIndices, matrix, x, b, result, choices); + multAddReduce(dir, rowGroupIndices, x, b, result, choices); #endif } - template class NativeMultiplier; - #ifdef STORM_HAVE_CARL template class NativeMultiplier; template class NativeMultiplier; diff --git a/src/storm/solver/NativeMultiplier.h b/src/storm/solver/NativeMultiplier.h index 01233b1ba..3d9e31a02 100644 --- a/src/storm/solver/NativeMultiplier.h +++ b/src/storm/solver/NativeMultiplier.h @@ -1,6 +1,6 @@ #pragma once -#include "storm/utility/VectorHelper.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/OptimizationDirection.h" @@ -13,18 +13,28 @@ namespace storm { namespace solver { template - class NativeMultiplier : public storm::utility::VectorHelper { + class NativeMultiplier : public Multiplier { public: - NativeMultiplier(); + NativeMultiplier(storm::storage::SparseMatrix const& matrix); + virtual ~NativeMultiplier() = default; - void multAdd(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddGaussSeidelBackward(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b) const; + virtual void multiply(Environment const& env, std::vector const& x, std::vector const* b, std::vector& result) const override; + virtual void multiplyGaussSeidel(Environment const& env, std::vector& x, std::vector const* b) const override; + virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const override; + virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const override; + virtual void multiplyRow(uint64_t const& rowIndex, std::vector const& x, ValueType& value) const override; + virtual void multiplyRow2(uint64_t const& rowIndex, std::vector const& x1, ValueType& val1, std::vector const& x2, ValueType& val2) const override; + + private: + bool parallelize(Environment const& env) const; + + void multAdd(std::vector const& x, std::vector const* b, std::vector& result) const; + + void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddReduceGaussSeidelBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector const* b, std::vector* choices = nullptr) const; + void multAddParallel(std::vector const& x, std::vector const* b, std::vector& result) const; + void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; - void multAddParallel(storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result) const; - void multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, storm::storage::SparseMatrix const& matrix, std::vector const& x, std::vector const* b, std::vector& result, std::vector* choices = nullptr) const; }; } diff --git a/src/storm/solver/SolveGoal.h b/src/storm/solver/SolveGoal.h index d93b86b91..9bd6f7e73 100644 --- a/src/storm/solver/SolveGoal.h +++ b/src/storm/solver/SolveGoal.h @@ -7,7 +7,6 @@ #include "storm/solver/OptimizationDirection.h" #include "storm/logic/ComparisonType.h" #include "storm/storage/BitVector.h" -#include "storm/solver/LinearEquationSolverTask.h" #include "storm/solver/LinearEquationSolver.h" #include "storm/solver/MinMaxLinearEquationSolver.h" @@ -111,8 +110,8 @@ namespace storm { } template - std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix, storm::solver::LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) { - std::unique_ptr> solver = factory.create(env, std::forward(matrix), task); + std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix) { + std::unique_ptr> solver = factory.create(env, std::forward(matrix)); if (goal.isBounded()) { solver->setTerminationCondition(std::make_unique>(goal.relevantValues(), goal.boundIsStrict(), goal.thresholdValue(), goal.minimize())); } @@ -120,8 +119,8 @@ namespace storm { } template - std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix, storm::solver::LinearEquationSolverTask const& task = LinearEquationSolverTask::Unspecified) { - std::unique_ptr> solver = factory.create(env, std::forward(matrix), task); + std::unique_ptr> configureLinearEquationSolver(Environment const& env, SolveGoal&& goal, storm::solver::LinearEquationSolverFactory const& factory, MatrixType&& matrix) { + std::unique_ptr> solver = factory.create(env, std::forward(matrix)); return solver; } diff --git a/src/storm/solver/SolverRequirement.cpp b/src/storm/solver/SolverRequirement.cpp new file mode 100644 index 000000000..c898840aa --- /dev/null +++ b/src/storm/solver/SolverRequirement.cpp @@ -0,0 +1,32 @@ +#include "storm/solver/SolverRequirement.h" + +#include + +#include "storm/utility/vector.h" + +namespace storm { + namespace solver { + SolverRequirement::SolverRequirement() : enabled(false), critical(false) { + // Intentionally left empty + } + + SolverRequirement::operator bool() const { + return enabled; + } + + void SolverRequirement::enable(bool critical) { + this->enabled = true; + this->critical = critical; + } + + void SolverRequirement::clear() { + enabled = false; + critical = false; + } + + bool SolverRequirement::isCritical() const { + return this->critical; + } + + } +} diff --git a/src/storm/solver/SolverRequirement.h b/src/storm/solver/SolverRequirement.h new file mode 100644 index 000000000..cfdac2e18 --- /dev/null +++ b/src/storm/solver/SolverRequirement.h @@ -0,0 +1,39 @@ +#pragma once + +namespace storm { + namespace solver { + + class SolverRequirement { + public: + + SolverRequirement(); + SolverRequirement(SolverRequirement const& other) = default; + + /*! + * Returns true if this is a requirement of the considered solver. + */ + operator bool() const; + + /*! + * Enables this requirement. + * @param critical if set, it is assumed that the solver will fail in case this requirement is not met + */ + void enable(bool critical = true); + + /*! + * Clears this requirement. + */ + void clear(); + + /*! + * Returns true if the solver fails in case this requirement is not met. + */ + bool isCritical() const; + + private: + bool enabled; + bool critical; + }; + + } +} diff --git a/src/storm/solver/SolverSelectionOptions.cpp b/src/storm/solver/SolverSelectionOptions.cpp index 504f3e2a7..d50d4875f 100644 --- a/src/storm/solver/SolverSelectionOptions.cpp +++ b/src/storm/solver/SolverSelectionOptions.cpp @@ -14,6 +14,22 @@ namespace storm { return "topological"; case MinMaxMethod::RationalSearch: return "ratsearch"; + case MinMaxMethod::IntervalIteration: + return "intervaliteration"; + case MinMaxMethod::SoundValueIteration: + return "soundvalueiteration"; + case MinMaxMethod::TopologicalCuda: + return "topologicalcuda"; + } + return "invalid"; + } + + std::string toString(MultiplierType t) { + switch(t) { + case MultiplierType::Native: + return "Native"; + case MultiplierType::Gmmxx: + return "Gmmxx"; } return "invalid"; } @@ -50,6 +66,8 @@ namespace storm { return "Eigen"; case EquationSolverType::Elimination: return "Elimination"; + case EquationSolverType::Topological: + return "Topological"; } return "invalid"; } @@ -65,7 +83,7 @@ namespace storm { } std::string toString(NativeLinearEquationSolverMethod t) { - switch( t) { + switch(t) { case NativeLinearEquationSolverMethod::Jacobi: return "Jacobi"; case NativeLinearEquationSolverMethod::GaussSeidel: @@ -76,6 +94,10 @@ namespace storm { return "WalkerChae"; case NativeLinearEquationSolverMethod::Power: return "Power"; + case NativeLinearEquationSolverMethod::SoundValueIteration: + return "SoundValueIteration"; + case NativeLinearEquationSolverMethod::IntervalIteration: + return "IntervalIteration"; case NativeLinearEquationSolverMethod::RationalSearch: return "RationalSearch"; } diff --git a/src/storm/solver/SolverSelectionOptions.h b/src/storm/solver/SolverSelectionOptions.h index ed4605ecb..baea29dc1 100644 --- a/src/storm/solver/SolverSelectionOptions.h +++ b/src/storm/solver/SolverSelectionOptions.h @@ -6,15 +6,16 @@ namespace storm { namespace solver { - ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch) + ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, IntervalIteration, SoundValueIteration, TopologicalCuda) + ExtendEnumsWithSelectionField(MultiplierType, Native, Gmmxx) ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration) ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration) ExtendEnumsWithSelectionField(LpSolverType, Gurobi, Glpk, Z3) - ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination) + ExtendEnumsWithSelectionField(EquationSolverType, Native, Gmmxx, Eigen, Elimination, Topological) ExtendEnumsWithSelectionField(SmtSolverType, Z3, Mathsat) - ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, RationalSearch) + ExtendEnumsWithSelectionField(NativeLinearEquationSolverMethod, Jacobi, GaussSeidel, SOR, WalkerChae, Power, SoundValueIteration, IntervalIteration, RationalSearch) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverMethod, Bicgstab, Qmr, Gmres) ExtendEnumsWithSelectionField(GmmxxLinearEquationSolverPreconditioner, Ilu, Diagonal, None) ExtendEnumsWithSelectionField(EigenLinearEquationSolverMethod, SparseLU, Bicgstab, DGmres, Gmres) diff --git a/src/storm/solver/StandardGameSolver.cpp b/src/storm/solver/StandardGameSolver.cpp index 26d4cc3d0..837a149b3 100644 --- a/src/storm/solver/StandardGameSolver.cpp +++ b/src/storm/solver/StandardGameSolver.cpp @@ -7,22 +7,46 @@ #include "storm/environment/solver/GameSolverEnvironment.h" +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/GeneralSettings.h" + +#include "storm/utility/ConstantsComparator.h" +#include "storm/utility/graph.h" #include "storm/utility/vector.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidEnvironmentException.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/NotImplementedException.h" + namespace storm { namespace solver { template - StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localP1Matrix(nullptr), localP2Matrix(nullptr), player1Matrix(player1Matrix), player2Matrix(player2Matrix) { - // Intentionally left empty. + StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(nullptr), player1Matrix(&player1Matrix), player2Matrix(player2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); + } + + template + StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(std::make_unique>(std::move(player1Matrix))), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(nullptr), player1Matrix(localPlayer1Matrix.get()), player2Matrix(*localPlayer2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); + } + + template + StandardGameSolver::StandardGameSolver(std::vector const& player1Grouping, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(nullptr), localPlayer1Matrix(nullptr), localPlayer2Matrix(nullptr), player1Grouping(&player1Grouping), player1Matrix(nullptr), player2Matrix(player2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); } template - StandardGameSolver::StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localP1Matrix(std::make_unique>(std::move(player1Matrix))), localP2Matrix(std::make_unique>(std::move(player2Matrix))), player1Matrix(*localP1Matrix), player2Matrix(*localP2Matrix) { - // Intentionally left empty. + StandardGameSolver::StandardGameSolver(std::vector&& player1Grouping, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localPlayer1Grouping(std::make_unique>(std::move(player1Grouping))), localPlayer1Matrix(nullptr), localPlayer2Matrix(std::make_unique>(std::move(player2Matrix))), player1Grouping(localPlayer1Grouping.get()), player1Matrix(nullptr), player2Matrix(*localPlayer2Matrix), linearEquationSolverIsExact(false) { + + // Determine whether the linear equation solver is assumed to produce exact results. + linearEquationSolverIsExact = storm::settings::getModule().isExactSet(); } template @@ -47,12 +71,12 @@ namespace storm { } template - bool StandardGameSolver::solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { + bool StandardGameSolver::solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices, std::vector* player2Choices) const { switch (getMethod(env, std::is_same::value)) { case GameMethod::ValueIteration: - return solveGameValueIteration(env, player1Dir, player2Dir, x, b); + return solveGameValueIteration(env, player1Dir, player2Dir, x, b, player1Choices, player2Choices); case GameMethod::PolicyIteration: - return solveGamePolicyIteration(env, player1Dir, player2Dir, x, b); + return solveGamePolicyIteration(env, player1Dir, player2Dir, x, b, player1Choices, player2Choices); default: STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method"); } @@ -60,49 +84,143 @@ namespace storm { } template - bool StandardGameSolver::solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { + bool StandardGameSolver::solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* providedPlayer1Choices, std::vector* providedPlayer2Choices) const { // Create the initial choice selections. - std::vector player1Choices = this->hasSchedulerHints() ? this->player1ChoicesHint.get() : std::vector(this->player1Matrix.getRowGroupCount(), 0); - std::vector player2Choices = this->hasSchedulerHints() ? this->player2ChoicesHint.get() : std::vector(this->player2Matrix.getRowGroupCount(), 0); - - if(!auxiliaryP2RowGroupVector) { + std::vector* player1Choices; + std::unique_ptr> localPlayer1Choices; + std::vector* player2Choices; + std::unique_ptr> localPlayer2Choices; + + if (providedPlayer1Choices && providedPlayer2Choices) { + player1Choices = providedPlayer1Choices; + player2Choices = providedPlayer2Choices; + } else { + localPlayer1Choices = std::make_unique>(); + player1Choices = localPlayer1Choices.get(); + localPlayer2Choices = std::make_unique>(); + player2Choices = localPlayer2Choices.get(); + } + + if (this->hasSchedulerHints()) { + *player1Choices = this->player1ChoicesHint.get(); + } else if (this->player1RepresentedByMatrix()) { + // Player 1 represented by matrix. + *player1Choices = std::vector(this->getPlayer1Matrix().getRowGroupCount(), 0); + } else { + // Player 1 represented by grouping of player 2 states. + player1Choices->resize(player1Choices->size() - 1); + } + if (this->hasSchedulerHints()) { + *player2Choices = this->player2ChoicesHint.get(); + } else if (!(providedPlayer1Choices && providedPlayer2Choices)) { + player2Choices->resize(this->player2Matrix.getRowGroupCount()); + } + + if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(this->player2Matrix.getRowGroupCount()); } - if(!auxiliaryP1RowGroupVector) { - auxiliaryP1RowGroupVector = std::make_unique>(this->player1Matrix.getRowGroupCount()); + if (!auxiliaryP1RowGroupVector) { + auxiliaryP1RowGroupVector = std::make_unique>(this->player1RepresentedByMatrix() ? this->player1Matrix->getRowGroupCount() : this->player1Grouping->size() - 1); } std::vector& subB = *auxiliaryP1RowGroupVector; uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); + // The linear equation solver should be at least as precise as this solver. + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().game().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().game().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().game().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } + } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; - getInducedMatrixVector(x, b, player1Choices, player2Choices, submatrix, subB); - if (this->linearEquationSolverFactory->getEquationProblemFormat(env) == LinearEquationSolverProblemFormat::EquationSystem) { + getInducedMatrixVector(x, b, *player1Choices, *player2Choices, submatrix, subB); + + storm::storage::BitVector targetStates; + storm::storage::BitVector zeroStates; + if (!this->hasUniqueSolution()) { + // If there is no unique solution, we need to compute the states with probability 0 and set their values explicitly. + targetStates = storm::utility::vector::filterGreaterZero(subB); + zeroStates = ~storm::utility::graph::performProbGreater0(submatrix.transpose(), storm::storage::BitVector(targetStates.size(), true), targetStates); + } + bool asEquationSystem = false; + if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { submatrix.convertToEquationSystem(); + asEquationSystem = true; + } + if (!this->hasUniqueSolution()) { + for (auto state : zeroStates) { + for (auto& element : submatrix.getRow(state)) { + if (element.getColumn() == state) { + element.setValue(asEquationSystem ? storm::utility::one() : storm::utility::zero()); + } else { + element.setValue(storm::utility::zero()); + } + } + subB[state] = storm::utility::zero(); + } + } + auto submatrixSolver = linearEquationSolverFactory->create(environmentOfSolver, std::move(submatrix)); + if (this->lowerBound) { + submatrixSolver->setLowerBound(this->lowerBound.get()); + } + if (this->upperBound) { + submatrixSolver->setUpperBound(this->upperBound.get()); } - auto submatrixSolver = linearEquationSolverFactory->create(env, std::move(submatrix)); - if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); } - if (this->upperBound) { submatrixSolver->setUpperBound(this->upperBound.get()); } submatrixSolver->setCachingEnabled(true); Status status = Status::InProgress; uint64_t iterations = 0; do { - // Solve the equation system for the 'DTMC'. - // FIXME: we need to remove the 0- and 1- states to make the solution unique. - submatrixSolver->solveEquations(env, x, subB); - - bool schedulerImproved = extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, player1Choices, player2Choices); + submatrixSolver->solveEquations(environmentOfSolver, x, subB); + + // Check whether we can improve local choices. + bool schedulerImproved = extractChoices(environmentOfSolver, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); // If the scheduler did not improve, we are done. if (!schedulerImproved) { status = Status::Converged; } else { // Update the solver. - getInducedMatrixVector(x, b, player1Choices, player2Choices, submatrix, subB); - submatrix.convertToEquationSystem(); + getInducedMatrixVector(x, b, *player1Choices, *player2Choices, submatrix, subB); + + if (!this->hasUniqueSolution()) { + // If there is no unique solution, we need to compute the states with probability 0 and set their values explicitly. + targetStates = storm::utility::vector::filterGreaterZero(subB); + zeroStates = ~storm::utility::graph::performProbGreater0(submatrix.transpose(), storm::storage::BitVector(targetStates.size(), true), targetStates); + } + if (this->linearEquationSolverFactory->getEquationProblemFormat(environmentOfSolver) == LinearEquationSolverProblemFormat::EquationSystem) { + submatrix.convertToEquationSystem(); + } + if (!this->hasUniqueSolution()) { + for (auto state : zeroStates) { + for (auto& element : submatrix.getRow(state)) { + if (element.getColumn() == state) { + element.setValue(asEquationSystem ? storm::utility::one() : storm::utility::zero()); + } else { + element.setValue(storm::utility::zero()); + } + } + subB[state] = storm::utility::zero(); + } + } + submatrixSolver->setMatrix(std::move(submatrix)); } @@ -114,12 +232,12 @@ namespace storm { reportStatus(status, iterations); // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulersSet()) { - this->player1SchedulerChoices = std::move(player1Choices); - this->player2SchedulerChoices = std::move(player2Choices); + if (this->isTrackSchedulersSet() && !(providedPlayer1Choices && providedPlayer2Choices)) { + this->player1SchedulerChoices = std::move(*player1Choices); + this->player2SchedulerChoices = std::move(*player2Choices); } - if(!this->isCachingEnabled()) { + if (!this->isCachingEnabled()) { clearCache(); } @@ -127,41 +245,38 @@ namespace storm { } template - bool StandardGameSolver::valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const { + bool StandardGameSolver::valueImproved(OptimizationDirection dir, storm::utility::ConstantsComparator const& comparator, ValueType const& value1, ValueType const& value2) const { if (dir == OptimizationDirection::Minimize) { - return value2 < value1; + return comparator.isLess(value2, value1); } else { - return value2 > value1; + return comparator.isLess(value1, value2); } } template - bool StandardGameSolver::solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const { + bool StandardGameSolver::solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices, std::vector* player2Choices) const { - if(!linEqSolverPlayer2Matrix) { - linEqSolverPlayer2Matrix = linearEquationSolverFactory->create(env, player2Matrix, storm::solver::LinearEquationSolverTask::Multiply); - linEqSolverPlayer2Matrix->setCachingEnabled(true); + if (!multiplierPlayer2Matrix) { + multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); } - if (!auxiliaryP2RowVector) { - auxiliaryP2RowVector = std::make_unique>(player2Matrix.getRowCount()); - } - if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(player2Matrix.getRowGroupCount()); } if (!auxiliaryP1RowGroupVector) { - auxiliaryP1RowGroupVector = std::make_unique>(player1Matrix.getRowGroupCount()); + auxiliaryP1RowGroupVector = std::make_unique>(this->getNumberOfPlayer1States()); } ValueType precision = storm::utility::convertNumber(env.solver().game().getPrecision()); bool relative = env.solver().game().getRelativeTerminationCriterion(); uint64_t maxIter = env.solver().game().getMaximalNumberOfIterations(); - std::vector& multiplyResult = *auxiliaryP2RowVector; - std::vector& reducedMultiplyResult = *auxiliaryP2RowGroupVector; - + std::vector& reducedPlayer2Result = *auxiliaryP2RowGroupVector; + + bool trackingSchedulersInProvidedStorage = player1Choices && player2Choices; + bool trackSchedulers = this->isTrackSchedulersSet() || trackingSchedulersInProvidedStorage; + bool trackSchedulersInValueIteration = trackSchedulers && !this->hasUniqueSolution(); if (this->hasSchedulerHints()) { // Solve the equation system induced by the two schedulers. storm::storage::SparseMatrix submatrix; @@ -170,20 +285,38 @@ namespace storm { submatrix.convertToEquationSystem(); } auto submatrixSolver = linearEquationSolverFactory->create(env, std::move(submatrix)); - if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); } - if (this->upperBound) { submatrixSolver->setUpperBound(this->upperBound.get()); } + if (this->lowerBound) { + submatrixSolver->setLowerBound(this->lowerBound.get()); + + } + if (this->upperBound) { + submatrixSolver->setUpperBound(this->upperBound.get()); + } submatrixSolver->solveEquations(env, x, *auxiliaryP1RowGroupVector); + + // If requested, we store the scheduler for retrieval. Initialize the schedulers to the hint we have. + if (trackSchedulersInValueIteration && !trackingSchedulersInProvidedStorage) { + this->player1SchedulerChoices = this->player1ChoicesHint.get(); + this->player2SchedulerChoices = this->player2ChoicesHint.get(); + } + } else if (trackSchedulersInValueIteration && !trackingSchedulersInProvidedStorage) { + // If requested, we store the scheduler for retrieval. Create empty schedulers here so we can fill them + // during VI. + this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); + this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); } std::vector* newX = auxiliaryP1RowGroupVector.get(); std::vector* currentX = &x; - + // Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations. uint64_t iterations = 0; Status status = Status::InProgress; while (status == Status::InProgress) { - multiplyAndReduce(player1Dir, player2Dir, *currentX, &b, *linEqSolverPlayer2Matrix, multiplyResult, reducedMultiplyResult, *newX); + multiplyAndReduce(env, player1Dir, player2Dir, *currentX, &b, *multiplierPlayer2Matrix, reducedPlayer2Result, *newX, + trackSchedulersInValueIteration ? (trackingSchedulersInProvidedStorage ? player1Choices : &this->player1SchedulerChoices.get()) : nullptr, + trackSchedulersInValueIteration ? (trackingSchedulersInProvidedStorage ? player2Choices : &this->player2SchedulerChoices.get()) : nullptr); // Determine whether the method converged. if (storm::utility::vector::equalModuloPrecision(*currentX, *newX, precision, relative)) { @@ -205,13 +338,17 @@ namespace storm { } // If requested, we store the scheduler for retrieval. - if (this->isTrackSchedulersSet()) { - this->player1SchedulerChoices = std::vector(player1Matrix.getRowGroupCount(), 0); - this->player2SchedulerChoices = std::vector(player2Matrix.getRowGroupCount(), 0); - extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); + if (trackSchedulers && this->hasUniqueSolution()) { + if (trackingSchedulersInProvidedStorage) { + extractChoices(env, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, *player1Choices, *player2Choices); + } else { + this->player1SchedulerChoices = std::vector(this->getNumberOfPlayer1States(), 0); + this->player2SchedulerChoices = std::vector(this->getNumberOfPlayer2States(), 0); + extractChoices(env, player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get()); + } } - if(!this->isCachingEnabled()) { + if (!this->isCachingEnabled()) { clearCache(); } @@ -221,73 +358,73 @@ namespace storm { template void StandardGameSolver::repeatedMultiply(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - if(!linEqSolverPlayer2Matrix) { - linEqSolverPlayer2Matrix = linearEquationSolverFactory->create(env, player2Matrix, storm::solver::LinearEquationSolverTask::Multiply); - linEqSolverPlayer2Matrix->setCachingEnabled(true); + if (!multiplierPlayer2Matrix) { + multiplierPlayer2Matrix = storm::solver::MultiplierFactory().create(env, player2Matrix); } - if (!auxiliaryP2RowVector) { - auxiliaryP2RowVector = std::make_unique>(player2Matrix.getRowCount()); - } - if (!auxiliaryP2RowGroupVector) { auxiliaryP2RowGroupVector = std::make_unique>(player2Matrix.getRowGroupCount()); } - std::vector& multiplyResult = *auxiliaryP2RowVector; - std::vector& reducedMultiplyResult = *auxiliaryP2RowGroupVector; + std::vector& reducedPlayer2Result = *auxiliaryP2RowGroupVector; for (uint_fast64_t iteration = 0; iteration < n; ++iteration) { - multiplyAndReduce(player1Dir, player2Dir, x, b, *linEqSolverPlayer2Matrix, multiplyResult, reducedMultiplyResult, x); + multiplyAndReduce(env, player1Dir, player2Dir, x, b, *multiplierPlayer2Matrix, reducedPlayer2Result, x); } - if(!this->isCachingEnabled()) { + if (!this->isCachingEnabled()) { clearCache(); } } template - void StandardGameSolver::multiplyAndReduce(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::LinearEquationSolver const& linEqSolver, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const { + void StandardGameSolver::multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& player2ReducedResult, std::vector& player1ReducedResult, std::vector* player1SchedulerChoices, std::vector* player2SchedulerChoices) const { - linEqSolver.multiply(x, b, multiplyResult); + multiplier.multiplyAndReduce(env, player2Dir, x, b, player2ReducedResult, player2SchedulerChoices); - storm::utility::vector::reduceVectorMinOrMax(player2Dir, multiplyResult, p2ReducedMultiplyResult, player2Matrix.getRowGroupIndices()); - - uint_fast64_t pl1State = 0; - for (auto& result : p1ReducedMultiplyResult) { - storm::storage::SparseMatrix::const_rows relevantRows = player1Matrix.getRowGroup(pl1State); - STORM_LOG_ASSERT(relevantRows.getNumberOfEntries() != 0, "There is a choice of player 1 that does not lead to any player 2 choice"); - auto it = relevantRows.begin(); - auto ite = relevantRows.end(); - - // Set the first value. - result = p2ReducedMultiplyResult[it->getColumn()]; - ++it; - - // Now iterate through the different values and pick the extremal one. - if (player1Dir == OptimizationDirection::Minimize) { - for (; it != ite; ++it) { - result = std::min(result, p2ReducedMultiplyResult[it->getColumn()]); - } - } else { - for (; it != ite; ++it) { - result = std::max(result, p2ReducedMultiplyResult[it->getColumn()]); + if (this->player1RepresentedByMatrix()) { + // Player 1 represented by matrix. + uint_fast64_t player1State = 0; + for (auto& result : player1ReducedResult) { + storm::storage::SparseMatrix::const_rows relevantRows = this->getPlayer1Matrix().getRowGroup(player1State); + STORM_LOG_ASSERT(relevantRows.getNumberOfEntries() != 0, "There is a choice of player 1 that does not lead to any player 2 choice"); + auto it = relevantRows.begin(); + auto ite = relevantRows.end(); + + // Set the first value. + result = player2ReducedResult[it->getColumn()]; + ++it; + + // Now iterate through the different values and pick the extremal one. + if (player1Dir == OptimizationDirection::Minimize) { + for (; it != ite; ++it) { + result = std::min(result, player2ReducedResult[it->getColumn()]); + } + } else { + for (; it != ite; ++it) { + result = std::max(result, player2ReducedResult[it->getColumn()]); + } } + ++player1State; } - ++pl1State; + } else { + // Player 1 represented by grouping of player 2 states (vector). + storm::utility::vector::reduceVectorMinOrMax(player1Dir, player2ReducedResult, player1ReducedResult, this->getPlayer1Grouping(), player1SchedulerChoices); } } template - bool StandardGameSolver::extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { + bool StandardGameSolver::extractChoices(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const { + + storm::utility::ConstantsComparator comparator(linearEquationSolverIsExact ? storm::utility::zero() : storm::utility::convertNumber(env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()).first.get()), false); // get the choices of player 2 and the corresponding values. bool schedulerImproved = false; auto currentValueIt = player2ChoiceValues.begin(); - for (uint_fast64_t p2Group = 0; p2Group < this->player2Matrix.getRowGroupCount(); ++p2Group) { + for (uint_fast64_t p2Group = 0; p2Group < this->player2Matrix.getRowGroupCount(); ++p2Group, ++currentValueIt) { uint_fast64_t firstRowInGroup = this->player2Matrix.getRowGroupIndices()[p2Group]; uint_fast64_t rowGroupSize = this->player2Matrix.getRowGroupIndices()[p2Group + 1] - firstRowInGroup; - // We need to check whether the scheduler improved. Therefore, we first have to evaluate the current choice + // We need to check whether the scheduler improved. Therefore, we first have to evaluate the current choice. uint_fast64_t currentP2Choice = player2Choices[p2Group]; *currentValueIt = storm::utility::zero(); for (auto const& entry : this->player2Matrix.getRow(firstRowInGroup + currentP2Choice)) { @@ -295,7 +432,7 @@ namespace storm { } *currentValueIt += b[firstRowInGroup + currentP2Choice]; - // now check the other choices + // Now check other choices improve the value. for (uint_fast64_t p2Choice = 0; p2Choice < rowGroupSize; ++p2Choice) { if (p2Choice == currentP2Choice) { continue; @@ -305,8 +442,8 @@ namespace storm { choiceValue += entry.getValue() * x[entry.getColumn()]; } choiceValue += b[firstRowInGroup + p2Choice]; - - if (valueImproved(player2Dir, *currentValueIt, choiceValue)) { + + if (valueImproved(player2Dir, comparator, *currentValueIt, choiceValue)) { schedulerImproved = true; player2Choices[p2Group] = p2Choice; *currentValueIt = std::move(choiceValue); @@ -314,22 +451,45 @@ namespace storm { } } - // Now extract the choices of player 1 - for (uint_fast64_t p1Group = 0; p1Group < this->player1Matrix.getRowGroupCount(); ++p1Group) { - uint_fast64_t firstRowInGroup = this->player1Matrix.getRowGroupIndices()[p1Group]; - uint_fast64_t rowGroupSize = this->player1Matrix.getRowGroupIndices()[p1Group + 1] - firstRowInGroup; - uint_fast64_t currentChoice = player1Choices[p1Group]; - ValueType currentValue = player2ChoiceValues[this->player1Matrix.getRow(firstRowInGroup + currentChoice).begin()->getColumn()]; - for (uint_fast64_t p1Choice = 0; p1Choice < rowGroupSize; ++p1Choice) { - // If the choice is the currently selected one, we can skip it. - if (p1Choice == currentChoice) { - continue; + // Now extract the choices of player 1. + if (this->player1RepresentedByMatrix()) { + // Player 1 represented by matrix. + for (uint_fast64_t p1Group = 0; p1Group < this->getPlayer1Matrix().getRowGroupCount(); ++p1Group) { + uint_fast64_t firstRowInGroup = this->getPlayer1Matrix().getRowGroupIndices()[p1Group]; + uint_fast64_t rowGroupSize = this->getPlayer1Matrix().getRowGroupIndices()[p1Group + 1] - firstRowInGroup; + uint_fast64_t currentChoice = player1Choices[p1Group]; + ValueType currentValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + currentChoice).begin()->getColumn()]; + for (uint_fast64_t p1Choice = 0; p1Choice < rowGroupSize; ++p1Choice) { + // If the choice is the currently selected one, we can skip it. + if (p1Choice == currentChoice) { + continue; + } + ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Matrix().getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; + if (valueImproved(player1Dir, comparator, currentValue, choiceValue)) { + schedulerImproved = true; + player1Choices[p1Group] = p1Choice; + currentValue = choiceValue; + } } - ValueType const& choiceValue = player2ChoiceValues[this->player1Matrix.getRow(firstRowInGroup + p1Choice).begin()->getColumn()]; - if (valueImproved(player1Dir, currentValue, choiceValue)) { - schedulerImproved = true; - player1Choices[p1Group] = p1Choice; - currentValue = choiceValue; + } + } else { + // Player 1 represented by grouping of player 2 states (vector). + for (uint64_t player1State = 0; player1State < this->getPlayer1Grouping().size() - 1; ++player1State) { + uint64_t currentChoice = player1Choices[player1State]; + ValueType currentValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + currentChoice]; + uint64_t numberOfPlayer2Successors = this->getPlayer1Grouping()[player1State + 1] - this->getPlayer1Grouping()[player1State]; + for (uint64_t player2State = 0; player2State < numberOfPlayer2Successors; ++player2State) { + // If the choice is the currently selected one, we can skip it. + if (currentChoice == player2State) { + continue; + } + + ValueType const& choiceValue = player2ChoiceValues[this->getPlayer1Grouping()[player1State] + player2State]; + if (valueImproved(player1Dir, comparator, currentValue, choiceValue)) { + schedulerImproved = true; + player1Choices[player1State] = player2State; + currentValue = choiceValue; + } } } } @@ -338,26 +498,67 @@ namespace storm { } template - void StandardGameSolver::getInducedMatrixVector(std::vector& x, std::vector const& b, std::vector const& player1Choices, std::vector const& player2Choices, storm::storage::SparseMatrix& inducedMatrix, std::vector& inducedVector) const { - //Get the rows of the player2matrix that are selected by the schedulers - //Note that rows can be selected more then once and in an arbitrary order. + void StandardGameSolver::getInducedMatrixVector(std::vector&, std::vector const& b, std::vector const& player1Choices, std::vector const& player2Choices, storm::storage::SparseMatrix& inducedMatrix, std::vector& inducedVector) const { + // Get the rows of the player 2 matrix that are selected by the schedulers. + // Note that rows can be selected more than once and in an arbitrary order. std::vector selectedRows; - selectedRows.reserve(player1Matrix.getRowGroupCount()); - uint_fast64_t pl1State = 0; - for (auto const& pl1Choice : player1Choices){ - auto const& pl1Row = player1Matrix.getRow(pl1State, pl1Choice); - STORM_LOG_ASSERT(pl1Row.getNumberOfEntries() == 1, "It is assumed that rows of player one have one entry, but this is not the case."); - uint_fast64_t const& pl2State = pl1Row.begin()->getColumn(); - selectedRows.push_back(player2Matrix.getRowGroupIndices()[pl2State] + player2Choices[pl2State]); - ++pl1State; + if (this->player1RepresentedByMatrix()) { + // Player 1 is represented by a matrix. + selectedRows.reserve(this->getPlayer1Matrix().getRowGroupCount()); + uint_fast64_t player1State = 0; + for (auto const& player1Choice : player1Choices) { + auto const& player1Row = this->getPlayer1Matrix().getRow(player1State, player1Choice); + STORM_LOG_ASSERT(player1Row.getNumberOfEntries() == 1, "It is assumed that rows of player one have one entry, but this is not the case."); + uint_fast64_t player2State = player1Row.begin()->getColumn(); + selectedRows.push_back(player2Matrix.getRowGroupIndices()[player2State] + player2Choices[player2State]); + ++player1State; + } + } else { + // Player 1 is represented by the grouping of player 2 states (vector). + selectedRows.reserve(this->player2Matrix.getRowGroupCount()); + for (uint64_t player1State = 0; player1State < this->getPlayer1Grouping().size() - 1; ++player1State) { + uint64_t player2State = this->getPlayer1Grouping()[player1State] + player1Choices[player1State]; + selectedRows.emplace_back(player2Matrix.getRowGroupIndices()[player2State] + player2Choices[player2State]); + } } - //Get the matrix and the vector induced by this selection. Note that we add entries at the diagonal + // Get the matrix and the vector induced by this selection and add entries on the diagonal in the process. inducedMatrix = player2Matrix.selectRowsFromRowIndexSequence(selectedRows, true); inducedVector.resize(inducedMatrix.getRowCount()); storm::utility::vector::selectVectorValues(inducedVector, selectedRows, b); } + template + bool StandardGameSolver::player1RepresentedByMatrix() const { + return player1Matrix != nullptr; + } + + template + storm::storage::SparseMatrix const& StandardGameSolver::getPlayer1Matrix() const { + STORM_LOG_ASSERT(player1RepresentedByMatrix(), "Player 1 is represented by a matrix."); + return *player1Matrix; + } + + template + std::vector const& StandardGameSolver::getPlayer1Grouping() const { + STORM_LOG_ASSERT(!player1RepresentedByMatrix(), "Player 1 is represented by a matrix."); + return *player1Grouping; + } + + template + uint64_t StandardGameSolver::getNumberOfPlayer1States() const { + if (this->player1RepresentedByMatrix()) { + return this->getPlayer1Matrix().getRowGroupCount(); + } else { + return this->getPlayer1Grouping().size() - 1; + } + } + + template + uint64_t StandardGameSolver::getNumberOfPlayer2States() const { + return this->player2Matrix.getRowGroupCount(); + } + template typename StandardGameSolver::Status StandardGameSolver::updateStatusIfNotConverged(Status status, std::vector const& x, uint64_t iterations, uint64_t maximalNumberOfIterations) const { if (status != Status::Converged) { @@ -383,7 +584,7 @@ namespace storm { template void StandardGameSolver::clearCache() const { - linEqSolverPlayer2Matrix.reset(); + multiplierPlayer2Matrix.reset(); auxiliaryP2RowVector.reset(); auxiliaryP2RowGroupVector.reset(); auxiliaryP1RowGroupVector.reset(); diff --git a/src/storm/solver/StandardGameSolver.h b/src/storm/solver/StandardGameSolver.h index 336be3911..7c7519231 100644 --- a/src/storm/solver/StandardGameSolver.h +++ b/src/storm/solver/StandardGameSolver.h @@ -1,6 +1,7 @@ #pragma once #include "storm/solver/LinearEquationSolver.h" +#include "storm/solver/Multiplier.h" #include "storm/solver/GameSolver.h" #include "SolverSelectionOptions.h" @@ -10,11 +11,15 @@ namespace storm { template class StandardGameSolver : public GameSolver { public: + // Constructors for when the first player is represented using a matrix. StandardGameSolver(storm::storage::SparseMatrix const& player1Matrix, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); - StandardGameSolver(storm::storage::SparseMatrix&& player1Matrix, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); - virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const override; + // Constructor for when the first player is represented by a grouping of the player 2 states (row groups). + StandardGameSolver(std::vector const& player1Groups, storm::storage::SparseMatrix const& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); + StandardGameSolver(std::vector&& player1Groups, storm::storage::SparseMatrix&& player2Matrix, std::unique_ptr>&& linearEquationSolverFactory); + + virtual bool solveGame(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const override; virtual void repeatedMultiply(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, uint_fast64_t n = 1) const override; virtual void clearCache() const override; @@ -22,28 +27,33 @@ namespace storm { private: GameMethod getMethod(Environment const& env, bool isExactMode) const; - bool solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const; - bool solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b) const; + bool solveGamePolicyIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const; + bool solveGameValueIteration(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const& b, std::vector* player1Choices = nullptr, std::vector* player2Choices = nullptr) const; // Computes p2Matrix * x + b, reduces the result w.r.t. player 2 choices, and then reduces the result w.r.t. player 1 choices. - void multiplyAndReduce(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, - storm::solver::LinearEquationSolver const& linEqSolver, std::vector& multiplyResult, std::vector& p2ReducedMultiplyResult, std::vector& p1ReducedMultiplyResult) const; + void multiplyAndReduce(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector& x, std::vector const* b, storm::solver::Multiplier const& multiplier, std::vector& player2ReducedResult, std::vector& player1ReducedResult, std::vector* player1SchedulerChoices = nullptr, std::vector* player2SchedulerChoices = nullptr) const; // Solves the equation system given by the two choice selections void getInducedMatrixVector(std::vector& x, std::vector const& b, std::vector const& player1Choices, std::vector const& player2Choices, storm::storage::SparseMatrix& inducedMatrix, std::vector& inducedVector) const; // Extracts the choices of the different players for the given solution x. // Returns true iff the newly extracted choices yield "better" values then the given choices for one of the players. - bool extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; - - bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const; + bool extractChoices(Environment const& env, OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector const& x, std::vector const& b, std::vector& player2ChoiceValues, std::vector& player1Choices, std::vector& player2Choices) const; + + bool valueImproved(OptimizationDirection dir, storm::utility::ConstantsComparator const& comparator, ValueType const& value1, ValueType const& value2) const; + bool player1RepresentedByMatrix() const; + storm::storage::SparseMatrix const& getPlayer1Matrix() const; + std::vector const& getPlayer1Grouping() const; + uint64_t getNumberOfPlayer1States() const; + uint64_t getNumberOfPlayer2States() const; + enum class Status { Converged, TerminatedEarly, MaximalIterationsExceeded, InProgress }; // possibly cached data - mutable std::unique_ptr> linEqSolverPlayer2Matrix; + mutable std::unique_ptr> multiplierPlayer2Matrix; mutable std::unique_ptr> auxiliaryP2RowVector; // player2Matrix.rowCount() entries mutable std::unique_ptr> auxiliaryP2RowGroupVector; // player2Matrix.rowGroupCount() entries mutable std::unique_ptr> auxiliaryP1RowGroupVector; // player1Matrix.rowGroupCount() entries @@ -56,14 +66,19 @@ namespace storm { // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted // when the solver is destructed. - std::unique_ptr> localP1Matrix; - std::unique_ptr> localP2Matrix; + std::unique_ptr> localPlayer1Grouping; + std::unique_ptr> localPlayer1Matrix; + std::unique_ptr> localPlayer2Matrix; // A reference to the original sparse matrix given to this solver. If the solver takes posession of the matrix // the reference refers to localA. - storm::storage::SparseMatrix const& player1Matrix; + std::vector const* player1Grouping; + storm::storage::SparseMatrix const* player1Matrix; storm::storage::SparseMatrix const& player2Matrix; + /// A flag indicating whether the linear equation solver is exact. This influences how choices are updated + /// in policy iteration. + bool linearEquationSolverIsExact; }; } } diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp index a8b042dc7..c2878cebb 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.cpp @@ -5,6 +5,7 @@ #include "storm/solver/EigenLinearEquationSolver.h" #include "storm/solver/NativeLinearEquationSolver.h" #include "storm/solver/EliminationLinearEquationSolver.h" +#include "storm/solver/TopologicalLinearEquationSolver.h" #include "storm/environment/solver/MinMaxSolverEnvironment.h" @@ -17,17 +18,17 @@ namespace storm { namespace solver { template - StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), A(nullptr) { + StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver() : A(nullptr) { // Intentionally left empty. } template - StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localA(nullptr), A(&A) { + StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(&A) { // Intentionally left empty. } template - StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory) : linearEquationSolverFactory(std::move(linearEquationSolverFactory)), localA(std::make_unique>(std::move(A))), A(localA.get()) { + StandardMinMaxLinearEquationSolver::StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(std::make_unique>(std::move(A))), A(localA.get()) { // Intentionally left empty. } @@ -35,121 +36,20 @@ namespace storm { void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { this->localA = nullptr; this->A = &matrix; + this->clearCache(); } template void StandardMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { this->localA = std::make_unique>(std::move(matrix)); this->A = this->localA.get(); - } - - template - void StandardMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - if (!linEqSolverA) { - linEqSolverA = linearEquationSolverFactory->create(env, *A, LinearEquationSolverTask::Multiply); - linEqSolverA->setCachingEnabled(true); - } - - if (!auxiliaryRowGroupVector) { - auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); - } - - this->startMeasureProgress(); - for (uint64_t i = 0; i < n; ++i) { - linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, b, *auxiliaryRowGroupVector); - std::swap(x, *auxiliaryRowGroupVector); - - // Potentially show progress. - this->showProgressIterative(i, n); - } - - if (!this->isCachingEnabled()) { - clearCache(); - } - } - - template - void StandardMinMaxLinearEquationSolver::clearCache() const { - linEqSolverA.reset(); - auxiliaryRowVector.reset(); - MinMaxLinearEquationSolver::clearCache(); - } - - template - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory() : MinMaxLinearEquationSolverFactory(), linearEquationSolverFactory(std::make_unique>()) { - // Intentionally left empty. - } - - template - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory) : MinMaxLinearEquationSolverFactory(), linearEquationSolverFactory(std::move(linearEquationSolverFactory)) { - // Intentionally left empty. - } - - template - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType) : MinMaxLinearEquationSolverFactory() { - switch (solverType) { - case EquationSolverType::Gmmxx: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Eigen: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Native: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Elimination: linearEquationSolverFactory = std::make_unique>(); break; - } - } - - template<> - StandardMinMaxLinearEquationSolverFactory::StandardMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType) : MinMaxLinearEquationSolverFactory() { - switch (solverType) { - case EquationSolverType::Eigen: linearEquationSolverFactory = std::make_unique>(); break; - case EquationSolverType::Elimination: linearEquationSolverFactory = std::make_unique>(); break; - default: - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported equation solver for this data type."); - } - } - - template - std::unique_ptr> StandardMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - std::unique_ptr> result; - auto method = env.solver().minMax().getMethod(); - if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) { - result = std::make_unique>(this->linearEquationSolverFactory->clone()); - } else { - STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "The selected min max method is not supported by this solver."); - } - result->setRequirementsChecked(this->isRequirementsCheckedSet()); - return result; - } - - template - GmmxxMinMaxLinearEquationSolverFactory::GmmxxMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Gmmxx) { - // Intentionally left empty. - } - - template - EigenMinMaxLinearEquationSolverFactory::EigenMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Eigen) { - // Intentionally left empty. - } - - template - NativeMinMaxLinearEquationSolverFactory::NativeMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Native) { - // Intentionally left empty. - } - - template - EliminationMinMaxLinearEquationSolverFactory::EliminationMinMaxLinearEquationSolverFactory() : StandardMinMaxLinearEquationSolverFactory(EquationSolverType::Elimination) { - // Intentionally left empty. + this->clearCache(); } template class StandardMinMaxLinearEquationSolver; - template class StandardMinMaxLinearEquationSolverFactory; - template class GmmxxMinMaxLinearEquationSolverFactory; - template class EigenMinMaxLinearEquationSolverFactory; - template class NativeMinMaxLinearEquationSolverFactory; - template class EliminationMinMaxLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class StandardMinMaxLinearEquationSolver; - template class StandardMinMaxLinearEquationSolverFactory; - template class EigenMinMaxLinearEquationSolverFactory; - template class EliminationMinMaxLinearEquationSolverFactory; #endif } } diff --git a/src/storm/solver/StandardMinMaxLinearEquationSolver.h b/src/storm/solver/StandardMinMaxLinearEquationSolver.h index 580e89347..9e79f482b 100644 --- a/src/storm/solver/StandardMinMaxLinearEquationSolver.h +++ b/src/storm/solver/StandardMinMaxLinearEquationSolver.h @@ -12,29 +12,17 @@ namespace storm { template class StandardMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { public: - StandardMinMaxLinearEquationSolver(std::unique_ptr>&& linearEquationSolverFactory); - StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, std::unique_ptr>&& linearEquationSolverFactory); - StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A, std::unique_ptr>&& linearEquationSolverFactory); + StandardMinMaxLinearEquationSolver(); + explicit StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); + explicit StandardMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A); virtual void setMatrix(storm::storage::SparseMatrix const& matrix) override; virtual void setMatrix(storm::storage::SparseMatrix&& matrix) override; virtual ~StandardMinMaxLinearEquationSolver() = default; - virtual void repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const override; - - virtual void clearCache() const override; - protected: - // possibly cached data - mutable std::unique_ptr> linEqSolverA; - mutable std::unique_ptr> auxiliaryRowVector; // A.rowCount() entries - mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowCount() entries - - /// The factory used to obtain linear equation solvers. - std::unique_ptr> linearEquationSolverFactory; - // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted // when the solver is destructed. std::unique_ptr> localA; @@ -44,48 +32,5 @@ namespace storm { storm::storage::SparseMatrix const* A; }; - template - class StandardMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { - public: - StandardMinMaxLinearEquationSolverFactory(); - StandardMinMaxLinearEquationSolverFactory(std::unique_ptr>&& linearEquationSolverFactory); - StandardMinMaxLinearEquationSolverFactory(EquationSolverType const& solverType); - - // Make the other create methods visible. - using MinMaxLinearEquationSolverFactory::create; - - virtual std::unique_ptr> create(Environment const& env) const override; - - protected: - std::unique_ptr> linearEquationSolverFactory; - - private: - void createLinearEquationSolverFactory() const; - }; - - template - class GmmxxMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - GmmxxMinMaxLinearEquationSolverFactory(); - }; - - template - class EigenMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - EigenMinMaxLinearEquationSolverFactory(); - }; - - template - class NativeMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - NativeMinMaxLinearEquationSolverFactory(); - }; - - template - class EliminationMinMaxLinearEquationSolverFactory : public StandardMinMaxLinearEquationSolverFactory { - public: - EliminationMinMaxLinearEquationSolverFactory(); - }; - } } diff --git a/src/storm/solver/SymbolicGameSolver.cpp b/src/storm/solver/SymbolicGameSolver.cpp index 7ed466650..957a5de78 100644 --- a/src/storm/solver/SymbolicGameSolver.cpp +++ b/src/storm/solver/SymbolicGameSolver.cpp @@ -156,9 +156,11 @@ namespace storm { template class SymbolicGameSolver; template class SymbolicGameSolver; - + template class SymbolicGameSolver; + template class SymbolicGameSolverFactory; template class SymbolicGameSolverFactory; - + template class SymbolicGameSolverFactory; + } } diff --git a/src/storm/solver/SymbolicGameSolver.h b/src/storm/solver/SymbolicGameSolver.h index 69446f3d1..6ca502ef9 100644 --- a/src/storm/solver/SymbolicGameSolver.h +++ b/src/storm/solver/SymbolicGameSolver.h @@ -73,10 +73,10 @@ namespace storm { storm::dd::Bdd allRows; // An ADD that can be used to compensate for the illegal choices of player 1. - storm::dd::Add illegalPlayer1Mask; + storm::dd::Add illegalPlayer1Mask; // An ADD that can be used to compensate for the illegal choices of player 2. - storm::dd::Add illegalPlayer2Mask; + storm::dd::Add illegalPlayer2Mask; // The row variables. std::set rowMetaVariables; diff --git a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp index b1501fd32..c54df3acf 100644 --- a/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp @@ -40,7 +40,10 @@ namespace storm { STORM_LOG_WARN("The selected solution method does not guarantee exact results."); } } - STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method."); + if (method != MinMaxMethod::ValueIteration && method != MinMaxMethod::PolicyIteration && method != MinMaxMethod::RationalSearch) { + STORM_LOG_WARN("Selected method is not supported for this solver, switching to value iteration."); + method = MinMaxMethod::ValueIteration; + } return method; } @@ -244,13 +247,26 @@ namespace storm { // If we were given an initial scheduler, we take its solution as the starting point. if (this->hasInitialScheduler()) { // The linear equation solver should be at least as precise as this solver - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } - localX = solveEquationsWithScheduler(environmentOfSolver ? *environmentOfSolver : env, this->getInitialScheduler(), x, b); + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; + localX = solveEquationsWithScheduler(environmentOfSolver, this->getInitialScheduler(), x, b); } else { localX = this->getLowerBoundsVector(); } @@ -311,20 +327,33 @@ namespace storm { // Initialize linear equation solver. // It should be at least as precise as this solver. - std::unique_ptr environmentOfSolver; - boost::optional precOfSolver = env.solver().getPrecisionOfCurrentLinearEquationSolver(); - if (!storm::NumberTraits::IsExact && precOfSolver && precOfSolver.get() > env.solver().minMax().getPrecision()) { - environmentOfSolver = std::make_unique(env); - environmentOfSolver->solver().setLinearEquationSolverPrecision(env.solver().minMax().getPrecision()); + std::unique_ptr environmentOfSolverStorage; + auto precOfSolver = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()); + if (!storm::NumberTraits::IsExact) { + bool changePrecision = precOfSolver.first && precOfSolver.first.get() > env.solver().minMax().getPrecision(); + bool changeRelative = precOfSolver.second && !precOfSolver.second.get() && env.solver().minMax().getRelativeTerminationCriterion(); + if (changePrecision || changeRelative) { + environmentOfSolverStorage = std::make_unique(env); + boost::optional newPrecision; + boost::optional newRelative; + if (changePrecision) { + newPrecision = env.solver().minMax().getPrecision(); + } + if (changeRelative) { + newRelative = true; + } + environmentOfSolverStorage->solver().setLinearEquationSolverPrecision(newPrecision, newRelative); + } } + storm::Environment const& environmentOfSolver = environmentOfSolverStorage ? *environmentOfSolverStorage : env; - std::unique_ptr> linearEquationSolver = linearEquationSolverFactory->create(environmentOfSolver ? *environmentOfSolver : env, this->allRows, this->rowMetaVariables, this->columnMetaVariables, this->rowColumnMetaVariablePairs); + std::unique_ptr> linearEquationSolver = linearEquationSolverFactory->create(environmentOfSolver, this->allRows, this->rowMetaVariables, this->columnMetaVariables, this->rowColumnMetaVariablePairs); this->forwardBounds(*linearEquationSolver); // Iteratively solve and improve the scheduler. uint64_t maxIter = env.solver().minMax().getMaximalNumberOfIterations(); while (!converged && iterations < maxIter) { - storm::dd::Add schedulerX = solveEquationsWithScheduler(environmentOfSolver ? *environmentOfSolver : env, *linearEquationSolver, scheduler, currentSolution, b, diagonal); + storm::dd::Add schedulerX = solveEquationsWithScheduler(environmentOfSolver, *linearEquationSolver, scheduler, currentSolution, b, diagonal); // Policy improvement step. storm::dd::Add choiceValues = this->A.multiplyMatrix(schedulerX.swapVariables(this->rowColumnMetaVariablePairs), this->columnMetaVariables) + b; diff --git a/src/storm/solver/TerminationCondition.cpp b/src/storm/solver/TerminationCondition.cpp index 745cc8a51..db3f12efd 100644 --- a/src/storm/solver/TerminationCondition.cpp +++ b/src/storm/solver/TerminationCondition.cpp @@ -4,12 +4,18 @@ #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" namespace storm { namespace solver { template - bool NoTerminationCondition::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminationCondition::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + return terminateNow([¤tValues] (uint64_t const& i) {return currentValues[i];}, guarantee); + } + + template + bool NoTerminationCondition::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { return false; } @@ -24,14 +30,17 @@ namespace storm { } template - bool TerminateIfFilteredSumExceedsThreshold::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminateIfFilteredSumExceedsThreshold::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { if (guarantee != SolverGuarantee::LessOrEqual) { return false; } - STORM_LOG_ASSERT(currentValues.size() == filter.size(), "Vectors sizes mismatch."); - ValueType currentThreshold = storm::utility::vector::sum_if(currentValues, filter); - return strict ? currentThreshold > this->threshold : currentThreshold >= this->threshold; + ValueType sum = storm::utility::zero(); + for (auto pos : filter) { + sum += valueGetter(pos); + // Exiting this loop early is not possible as values might be negative + } + return strict ? sum > this->threshold : sum >= this->threshold; } template @@ -42,17 +51,47 @@ namespace storm { template TerminateIfFilteredExtremumExceedsThreshold::TerminateIfFilteredExtremumExceedsThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum) : TerminateIfFilteredSumExceedsThreshold(filter, threshold, strict), useMinimum(useMinimum) { // Intentionally left empty. + STORM_LOG_THROW(!this->filter.empty(), storm::exceptions::InvalidArgumentException, "Empty Filter; Can not take extremum over empty set."); + cachedExtremumIndex = this->filter.getNextSetIndex(0); } template - bool TerminateIfFilteredExtremumExceedsThreshold::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminateIfFilteredExtremumExceedsThreshold::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { if (guarantee != SolverGuarantee::LessOrEqual) { return false; } - STORM_LOG_ASSERT(currentValues.size() == this->filter.size(), "Vectors sizes mismatch."); - ValueType currentValue = useMinimum ? storm::utility::vector::min_if(currentValues, this->filter) : storm::utility::vector::max_if(currentValues, this->filter); - return this->strict ? currentValue > this->threshold : currentValue >= this->threshold; + ValueType extremum = valueGetter(cachedExtremumIndex); + if (useMinimum && (this->strict ? extremum <= this->threshold : extremum < this->threshold)) { + // The extremum can only become smaller so we can return right now. + return false; + } + + if (useMinimum) { + if (this->strict) { + for (auto const& pos : this->filter) { + extremum = std::min(valueGetter(pos), extremum); + if (extremum <= this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } else { + for (auto const& pos : this->filter) { + extremum = std::min(valueGetter(pos), extremum); + if (extremum < this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } + } else { + for (auto const& pos : this->filter) { + extremum = std::max(valueGetter(pos), extremum); + } + } + + return this->strict ? extremum > this->threshold : extremum >= this->threshold; } template @@ -62,18 +101,47 @@ namespace storm { template TerminateIfFilteredExtremumBelowThreshold::TerminateIfFilteredExtremumBelowThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum) : TerminateIfFilteredSumExceedsThreshold(filter, threshold, strict), useMinimum(useMinimum) { - // Intentionally left empty. + STORM_LOG_THROW(!this->filter.empty(), storm::exceptions::InvalidArgumentException, "Empty Filter; Can not take extremum over empty set."); + cachedExtremumIndex = this->filter.getNextSetIndex(0); } template - bool TerminateIfFilteredExtremumBelowThreshold::terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee) const { + bool TerminateIfFilteredExtremumBelowThreshold::terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee) const { if (guarantee != SolverGuarantee::GreaterOrEqual) { return false; } - STORM_LOG_ASSERT(currentValues.size() == this->filter.size(), "Vectors sizes mismatch."); - ValueType currentValue = useMinimum ? storm::utility::vector::min_if(currentValues, this->filter) : storm::utility::vector::max_if(currentValues, this->filter); - return this->strict ? currentValue < this->threshold : currentValue <= this->threshold; + ValueType extremum = valueGetter(cachedExtremumIndex); + if (!useMinimum && (this->strict ? extremum >= this->threshold : extremum > this->threshold)) { + // The extremum can only become larger so we can return right now. + return false; + } + + if (useMinimum) { + for (auto const& pos : this->filter) { + extremum = std::min(valueGetter(pos), extremum); + } + } else { + if (this->strict) { + for (auto const& pos : this->filter) { + extremum = std::max(valueGetter(pos), extremum); + if (extremum >= this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } else { + for (auto const& pos : this->filter) { + extremum = std::max(valueGetter(pos), extremum); + if (extremum > this->threshold) { + cachedExtremumIndex = pos; + return false; + } + } + } + } + + return this->strict ? extremum < this->threshold : extremum <= this->threshold; } template @@ -81,10 +149,14 @@ namespace storm { return guarantee == SolverGuarantee::GreaterOrEqual; } + template class TerminationCondition; + template class NoTerminationCondition; template class TerminateIfFilteredSumExceedsThreshold; template class TerminateIfFilteredExtremumExceedsThreshold; template class TerminateIfFilteredExtremumBelowThreshold; #ifdef STORM_HAVE_CARL + template class TerminationCondition; + template class NoTerminationCondition; template class TerminateIfFilteredSumExceedsThreshold; template class TerminateIfFilteredExtremumExceedsThreshold; template class TerminateIfFilteredExtremumBelowThreshold; diff --git a/src/storm/solver/TerminationCondition.h b/src/storm/solver/TerminationCondition.h index a8e21697e..98402d1af 100644 --- a/src/storm/solver/TerminationCondition.h +++ b/src/storm/solver/TerminationCondition.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "storm/solver/SolverGuarantee.h" #include "storm/storage/BitVector.h" @@ -15,7 +15,8 @@ namespace storm { /*! * Retrieves whether the guarantee provided by the solver for the current result is sufficient to terminate. */ - virtual bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const = 0; + virtual bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const; + virtual bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const = 0; /*! * Retrieves whether the termination criterion requires the given guarantee in order to decide termination. @@ -27,7 +28,7 @@ namespace storm { template class NoTerminationCondition : public TerminationCondition { public: - virtual bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + virtual bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; }; @@ -36,7 +37,7 @@ namespace storm { public: TerminateIfFilteredSumExceedsThreshold(storm::storage::BitVector const& filter, ValueType const& threshold, bool strict); - bool terminateNow(std::vector const& currentValues, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; protected: @@ -50,11 +51,12 @@ namespace storm { public: TerminateIfFilteredExtremumExceedsThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum); - bool terminateNow(std::vector const& currentValue, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; protected: bool useMinimum; + mutable uint64_t cachedExtremumIndex; }; template @@ -62,11 +64,12 @@ namespace storm { public: TerminateIfFilteredExtremumBelowThreshold(storm::storage::BitVector const& filter, bool strict, ValueType const& threshold, bool useMinimum); - bool terminateNow(std::vector const& currentValue, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; + bool terminateNow(std::function const& valueGetter, SolverGuarantee const& guarantee = SolverGuarantee::None) const override; virtual bool requiresGuarantee(SolverGuarantee const& guarantee) const override; protected: bool useMinimum; + mutable uint64_t cachedExtremumIndex; }; } } diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp new file mode 100644 index 000000000..f31d1cde3 --- /dev/null +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.cpp @@ -0,0 +1,466 @@ +#include "storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h" + +#include "storm/utility/vector.h" +#include "storm/utility/graph.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/exceptions/IllegalArgumentException.h" +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidEnvironmentException.h" + +#include "storm/environment/solver/MinMaxSolverEnvironment.h" + +#include "storm/settings/SettingsManager.h" +#include "storm/settings/modules/CoreSettings.h" + +#include "storm/utility/macros.h" +#include "storm-config.h" +#ifdef STORM_HAVE_CUDA +# include "cudaForStorm.h" +#endif + +namespace storm { + namespace solver { + + template + TopologicalCudaMinMaxLinearEquationSolver::TopologicalCudaMinMaxLinearEquationSolver() { + // Get the settings object to customize solving. + this->enableCuda = storm::settings::getModule().isUseCudaSet(); +#ifdef STORM_HAVE_CUDA + STORM_LOG_INFO_COND(this->enableCuda, "Option CUDA was not set, but the topological value iteration solver will use it anyways."); +#endif + } + + template + TopologicalCudaMinMaxLinearEquationSolver::TopologicalCudaMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : TopologicalCudaMinMaxLinearEquationSolver() { + this->setMatrix(A); + } + + template + void TopologicalCudaMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { + this->localA = nullptr; + this->A = &matrix; + } + + template + void TopologicalCudaMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { + this->localA = std::make_unique>(std::move(matrix)); + this->A = this->localA.get(); + } + + template + bool TopologicalCudaMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::TopologicalCuda, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); + + ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + uint64_t maxIters = env.solver().minMax().getMaximalNumberOfIterations(); + bool relative = env.solver().minMax().getMaximalNumberOfIterations(); + +#ifdef GPU_USE_FLOAT +#define __FORCE_FLOAT_CALCULATION true +#else +#define __FORCE_FLOAT_CALCULATION false +#endif + if (__FORCE_FLOAT_CALCULATION && std::is_same::value) { + // FIXME: This actually allocates quite some storage, because of this conversion, is it really necessary? + storm::storage::SparseMatrix newA = this->A->template toValueType(); + + TopologicalCudaMinMaxLinearEquationSolver newSolver(newA); + + std::vector new_x = storm::utility::vector::toValueType(x); + std::vector const new_b = storm::utility::vector::toValueType(b); + + bool callConverged = newSolver.solveEquations(env, dir, new_x, new_b); + + for (size_t i = 0, size = new_x.size(); i < size; ++i) { + x.at(i) = new_x.at(i); + } + return callConverged; + } + + // For testing only + if (sizeof(ValueType) == sizeof(double)) { + //std::cout << "<<< Using CUDA-DOUBLE Kernels >>>" << std::endl; + STORM_LOG_INFO("<<< Using CUDA-DOUBLE Kernels >>>"); + } else { + //std::cout << "<<< Using CUDA-FLOAT Kernels >>>" << std::endl; + STORM_LOG_INFO("<<< Using CUDA-FLOAT Kernels >>>"); + } + + // Now, we need to determine the SCCs of the MDP and perform a topological sort. + std::vector const& nondeterministicChoiceIndices = this->A->getRowGroupIndices(); + + // Check if the decomposition is necessary +#ifdef STORM_HAVE_CUDA +#define __USE_CUDAFORSTORM_OPT true + size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(A->getRowCount()), nondeterministicChoiceIndices.size(), static_cast(A->getEntryCount())); + size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); +#else +#define __USE_CUDAFORSTORM_OPT false + size_t const gpuSizeOfCompleteSystem = 0; + size_t const cudaFreeMemory = 0; +#endif + std::vector> sccDecomposition; + if (__USE_CUDAFORSTORM_OPT && (gpuSizeOfCompleteSystem < cudaFreeMemory)) { + // Dummy output for SCC Times + //std::cout << "Computing the SCC Decomposition took 0ms" << std::endl; + +#ifdef STORM_HAVE_CUDA + STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA Equation Solver."); + + bool result = false; + size_t globalIterations = 0; + if (dir == OptimizationDirection::Minimize) { + result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); + } else { + result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); + } + STORM_LOG_INFO("Executed " << globalIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); + + bool converged = false; + if (!result) { + converged = false; + STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); + throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; + } else { + converged = true; + } + + // Check if the solver converged and issue a warning otherwise. + if (converged) { + STORM_LOG_INFO("Iterative solver converged after " << globalIterations << " iterations."); + } else { + STORM_LOG_WARN("Iterative solver did not converged after " << globalIterations << " iterations."); + } +#else + STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); + throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; +#endif + } else { + storm::storage::BitVector fullSystem(this->A->getRowGroupCount(), true); + storm::storage::StronglyConnectedComponentDecomposition sccDecomposition(*this->A, fullSystem, false, false); + + STORM_LOG_THROW(sccDecomposition.size() > 0, storm::exceptions::IllegalArgumentException, "Can not solve given equation system as the SCC decomposition returned no SCCs."); + + storm::storage::SparseMatrix stronglyConnectedComponentsDependencyGraph = sccDecomposition.extractPartitionDependencyGraph(*this->A); + std::vector topologicalSort = storm::utility::graph::getTopologicalSort(stronglyConnectedComponentsDependencyGraph); + + // Calculate the optimal distribution of sccs + std::vector> optimalSccs = this->getOptimalGroupingFromTopologicalSccDecomposition(sccDecomposition, topologicalSort, *this->A); + STORM_LOG_INFO("Optimized SCC Decomposition, originally " << topologicalSort.size() << " SCCs, optimized to " << optimalSccs.size() << " SCCs."); + + std::vector* currentX = nullptr; + std::vector* swap = nullptr; + size_t currentMaxLocalIterations = 0; + size_t localIterations = 0; + size_t globalIterations = 0; + bool converged = true; + + // Iterate over all SCCs of the MDP as specified by the topological sort. This guarantees that an SCC is only + // solved after all SCCs it depends on have been solved. + for (auto sccIndexIt = optimalSccs.cbegin(); sccIndexIt != optimalSccs.cend() && converged; ++sccIndexIt) { + bool const useGpu = sccIndexIt->first; + storm::storage::StateBlock const& scc = sccIndexIt->second; + + // Generate a sub matrix + storm::storage::BitVector subMatrixIndices(this->A->getColumnCount(), scc.cbegin(), scc.cend()); + storm::storage::SparseMatrix sccSubmatrix = this->A->getSubmatrix(true, subMatrixIndices, subMatrixIndices); + std::vector sccSubB(sccSubmatrix.getRowCount()); + storm::utility::vector::selectVectorValues(sccSubB, subMatrixIndices, nondeterministicChoiceIndices, b); + std::vector sccSubX(sccSubmatrix.getColumnCount()); + std::vector sccSubXSwap(sccSubmatrix.getColumnCount()); + std::vector sccMultiplyResult(sccSubmatrix.getRowCount()); + + // Prepare the pointers for swapping in the calculation + currentX = &sccSubX; + swap = &sccSubXSwap; + + storm::utility::vector::selectVectorValues(sccSubX, subMatrixIndices, x); // x is getCols() large, where as b and multiplyResult are getRows() (nondet. choices times states) + std::vector sccSubNondeterministicChoiceIndices(sccSubmatrix.getColumnCount() + 1); + sccSubNondeterministicChoiceIndices.at(0) = 0; + + // Pre-process all dependent states + // Remove outgoing transitions and create the ChoiceIndices + uint_fast64_t innerIndex = 0; + uint_fast64_t outerIndex = 0; + for (uint_fast64_t state : scc) { + // Choice Indices + sccSubNondeterministicChoiceIndices.at(outerIndex + 1) = sccSubNondeterministicChoiceIndices.at(outerIndex) + (nondeterministicChoiceIndices[state + 1] - nondeterministicChoiceIndices[state]); + + for (auto rowGroupIt = nondeterministicChoiceIndices[state]; rowGroupIt != nondeterministicChoiceIndices[state + 1]; ++rowGroupIt) { + typename storm::storage::SparseMatrix::const_rows row = this->A->getRow(rowGroupIt); + for (auto rowIt = row.begin(); rowIt != row.end(); ++rowIt) { + if (!subMatrixIndices.get(rowIt->getColumn())) { + // This is an outgoing transition of a state in the SCC to a state not included in the SCC + // Subtracting Pr(tau) * x_other from b fixes that + sccSubB.at(innerIndex) = sccSubB.at(innerIndex) + (rowIt->getValue() * x.at(rowIt->getColumn())); + } + } + ++innerIndex; + } + ++outerIndex; + } + + // For the current SCC, we need to perform value iteration until convergence. + if (useGpu) { +#ifdef STORM_HAVE_CUDA + STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA-based equation solver."); + + //STORM_LOG_INFO("Device has " << getTotalCudaMemory() << " Bytes of Memory with " << getFreeCudaMemory() << "Bytes free (" << (static_cast(getFreeCudaMemory()) / static_cast(getTotalCudaMemory())) * 100 << "%)."); + //STORM_LOG_INFO("We will allocate " << (sizeof(uint_fast64_t)* sccSubmatrix.rowIndications.size() + sizeof(uint_fast64_t)* sccSubmatrix.columnsAndValues.size() * 2 + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubB.size() + sizeof(double)* sccSubB.size() + sizeof(uint_fast64_t)* sccSubNondeterministicChoiceIndices.size()) << " Bytes."); + //STORM_LOG_INFO("The CUDA Runtime Version is " << getRuntimeCudaVersion()); + + bool result = false; + localIterations = 0; + if (dir == OptimizationDirection::Minimum) { + result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); + } else { + result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); + } + STORM_LOG_INFO("Executed " << localIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); + + if (!result) { + converged = false; + STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); + throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; + } else { + converged = true; + } + + // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep + // track of the maximum. + if (localIterations > currentMaxLocalIterations) { + currentMaxLocalIterations = localIterations; + } + globalIterations += localIterations; +#else + STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); + throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; +#endif + } else { + //std::cout << "WARNING: Using CPU based TopoSolver! (double)" << std::endl; + STORM_LOG_INFO("Performance Warning: Using CPU based TopoSolver! (double)"); + localIterations = 0; + converged = false; + while (!converged && localIterations < maxIters) { + // Compute x' = A*x + b. + sccSubmatrix.multiplyWithVector(*currentX, sccMultiplyResult); + storm::utility::vector::addVectors(sccMultiplyResult, sccSubB, sccMultiplyResult); + + //A.multiplyWithVector(scc, nondeterministicChoiceIndices, *currentX, multiplyResult); + //storm::utility::addVectors(scc, nondeterministicChoiceIndices, multiplyResult, b); + + /* + Versus: + A.multiplyWithVector(*currentX, *multiplyResult); + storm::utility::vector::addVectorsInPlace(*multiplyResult, b); + */ + + // Reduce the vector x' by applying min/max for all non-deterministic choices. + storm::utility::vector::reduceVectorMinOrMax(dir,sccMultiplyResult, *swap, sccSubNondeterministicChoiceIndices); + + // Determine whether the method converged. + // TODO: It seems that the equalModuloPrecision call that compares all values should have a higher + // running time. In fact, it is faster. This has to be investigated. + // converged = storm::utility::equalModuloPrecision(*currentX, *newX, scc, precision, relative); + converged = storm::utility::vector::equalModuloPrecision(*currentX, *swap, precision, relative); + + // Update environment variables. + std::swap(currentX, swap); + + ++localIterations; + ++globalIterations; + } + STORM_LOG_INFO("Executed " << localIterations << " of max. " << maxIters << " Iterations."); + } + + + // The Result of this SCC has to be taken back into the main result vector + innerIndex = 0; + for (uint_fast64_t state : scc) { + x.at(state) = currentX->at(innerIndex); + ++innerIndex; + } + + // Since the pointers for swapping in the calculation point to temps they should not be valid anymore + currentX = nullptr; + swap = nullptr; + + // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep + // track of the maximum. + if (localIterations > currentMaxLocalIterations) { + currentMaxLocalIterations = localIterations; + } + } + + //std::cout << "Used a total of " << globalIterations << " iterations with a maximum of " << localIterations << " iterations in a single block." << std::endl; + + // Check if the solver converged and issue a warning otherwise. + if (converged) { + STORM_LOG_INFO("Iterative solver converged after " << currentMaxLocalIterations << " iterations."); + } else { + STORM_LOG_WARN("Iterative solver did not converged after " << currentMaxLocalIterations << " iterations."); + } + + return converged; + } + } + + template + std::vector> + TopologicalCudaMinMaxLinearEquationSolver::getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const { + + (void)matrix; + + std::vector> result; + +#ifdef STORM_HAVE_CUDA + // 95% to have a bit of padding + size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); + size_t lastResultIndex = 0; + + std::vector const& rowGroupIndices = matrix.getRowGroupIndices(); + + size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(matrix.getRowCount()), rowGroupIndices.size(), static_cast(matrix.getEntryCount())); + size_t const gpuSizePerRowGroup = std::max(static_cast(gpuSizeOfCompleteSystem / rowGroupIndices.size()), static_cast(1)); + size_t const maxRowGroupsPerMemory = cudaFreeMemory / gpuSizePerRowGroup; + + size_t currentSize = 0; + size_t neededReserveSize = 0; + size_t startIndex = 0; + for (size_t i = 0; i < topologicalSort.size(); ++i) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[i]]; + size_t const currentSccSize = scc.size(); + + uint_fast64_t rowCount = 0; + uint_fast64_t entryCount = 0; + + for (auto sccIt = scc.cbegin(); sccIt != scc.cend(); ++sccIt) { + rowCount += matrix.getRowGroupSize(*sccIt); + entryCount += matrix.getRowGroupEntryCount(*sccIt); + } + + size_t sccSize = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(rowCount), scc.size(), static_cast(entryCount)); + + if ((currentSize + sccSize) <= cudaFreeMemory) { + // There is enough space left in the current group + neededReserveSize += currentSccSize; + currentSize += sccSize; + } else { + // This would make the last open group to big for the GPU + + if (startIndex < i) { + if ((startIndex + 1) < i) { + // More than one component + std::vector tempGroups; + tempGroups.reserve(neededReserveSize); + + // Copy the first group to make inplace_merge possible + storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; + tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); + + if (((startIndex + 1) + 80) >= i) { + size_t lastSize = 0; + for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + lastSize = tempGroups.size(); + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + std::vector::iterator middleIterator = tempGroups.begin(); + std::advance(middleIterator, lastSize); + std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); + } + } else { + // Use std::sort + for (size_t j = startIndex + 1; j < i; ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + } + std::sort(tempGroups.begin(), tempGroups.end()); + } + result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); + } else { + // Only one group, copy construct. + result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); + } + ++lastResultIndex; + } + + if (sccSize <= cudaFreeMemory) { + currentSize = sccSize; + neededReserveSize = currentSccSize; + startIndex = i; + } else { + // This group is too big to fit into the CUDA Memory by itself + result.push_back(std::make_pair(false, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[i]])))); + ++lastResultIndex; + + currentSize = 0; + neededReserveSize = 0; + startIndex = i + 1; + } + } + } + + size_t const topologicalSortSize = topologicalSort.size(); + if (startIndex < topologicalSortSize) { + if ((startIndex + 1) < topologicalSortSize) { + // More than one component + std::vector tempGroups; + tempGroups.reserve(neededReserveSize); + + // Copy the first group to make inplace_merge possible. + storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; + tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); + + // For set counts <= 80, in-place merge is faster. + if (((startIndex + 1) + 80) >= topologicalSortSize) { + size_t lastSize = 0; + for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + lastSize = tempGroups.size(); + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + std::vector::iterator middleIterator = tempGroups.begin(); + std::advance(middleIterator, lastSize); + std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); + } + } else { + // Use std::sort + for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { + storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; + tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); + } + std::sort(tempGroups.begin(), tempGroups.end()); + } + result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); + } + else { + // Only one group, copy construct. + result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); + } + ++lastResultIndex; + } +#else + for (auto sccIndexIt = topologicalSort.cbegin(); sccIndexIt != topologicalSort.cend(); ++sccIndexIt) { + storm::storage::StateBlock const& scc = sccDecomposition[*sccIndexIt]; + result.push_back(std::make_pair(false, scc)); + } +#endif + return result; + } + + template + TopologicalCudaMinMaxLinearEquationSolverFactory::TopologicalCudaMinMaxLinearEquationSolverFactory(bool trackScheduler) { + // Intentionally left empty. + } + + template + std::unique_ptr> TopologicalCudaMinMaxLinearEquationSolverFactory::create(Environment const& env) const { + STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); + return std::make_unique>(); + } + + // Explicitly instantiate the solver. + template class TopologicalCudaMinMaxLinearEquationSolver; + + template class TopologicalCudaMinMaxLinearEquationSolverFactory; + } // namespace solver +} // namespace storm diff --git a/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h new file mode 100644 index 000000000..7005d9d8f --- /dev/null +++ b/src/storm/solver/TopologicalCudaMinMaxLinearEquationSolver.h @@ -0,0 +1,152 @@ +#ifndef STORM_SOLVER_TOPOLOGICALCUDAMINMAXLINEAREQUATIONSOLVER_H_ +#define STORM_SOLVER_TOPOLOGICALCUDAMINMAXLINEAREQUATIONSOLVER_H_ + +#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" +#include "storm/storage/SparseMatrix.h" +#include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/NotSupportedException.h" + +#include +#include + +#include "storm-config.h" +#ifdef STORM_HAVE_CUDA +#include "cudaForStorm.h" +#endif + +namespace storm { + namespace solver { + + /*! + * A class that uses SCC Decompositions to solve a min/max linear equation system. + */ + template + class TopologicalCudaMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { + public: + TopologicalCudaMinMaxLinearEquationSolver(); + + /*! + * Constructs a min-max linear equation solver with parameters being set according to the settings + * object. + * + * @param A The matrix defining the coefficients of the linear equation system. + */ + TopologicalCudaMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); + + virtual void setMatrix(storm::storage::SparseMatrix const& matrix) override; + virtual void setMatrix(storm::storage::SparseMatrix&& matrix) override; + + virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; + + private: + storm::storage::SparseMatrix const* A; + std::unique_ptr> localA; + + bool enableCuda; + /*! + * Given a topological sort of a SCC Decomposition, this will calculate the optimal grouping of SCCs with respect to the size of the GPU memory. + */ + std::vector> getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const; + }; + + template + bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector& x, std::vector const&, std::vector const&, size_t&) { + // + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); + } + template <> + inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_double_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + template <> + inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_float_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + + template + bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector&, std::vector const&, std::vector const&, size_t&) { + STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); + } + template <> + inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_double_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + template <> + inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + + (void)maxIterationCount; + (void)precision; + (void)relativePrecisionCheck; + (void)matrixRowIndices; + (void)columnIndicesAndValues; + (void)x; + (void)b; + (void)nondeterministicChoiceIndices; + (void)iterationCount; + +#ifdef STORM_HAVE_CUDA + return basicValueIteration_mvReduce_uint64_float_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); +#else + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); +#endif + } + + template + class TopologicalCudaMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { + public: + TopologicalCudaMinMaxLinearEquationSolverFactory(bool trackScheduler = false); + + protected: + virtual std::unique_ptr> create(Environment const& env) const override; + }; + + } // namespace solver +} // namespace storm + +#endif /* STORM_SOLVER_TOPOLOGICALCUDAMINMAXLINEAREQUATIONSOLVER_H_ */ diff --git a/src/storm/solver/TopologicalLinearEquationSolver.cpp b/src/storm/solver/TopologicalLinearEquationSolver.cpp new file mode 100644 index 000000000..877ba76dd --- /dev/null +++ b/src/storm/solver/TopologicalLinearEquationSolver.cpp @@ -0,0 +1,264 @@ +#include "storm/solver/TopologicalLinearEquationSolver.h" + +#include "storm/environment/solver/TopologicalSolverEnvironment.h" + +#include "storm/utility/constants.h" +#include "storm/utility/vector.h" +#include "storm/exceptions/InvalidStateException.h" +#include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace solver { + + template + TopologicalLinearEquationSolver::TopologicalLinearEquationSolver() : localA(nullptr), A(nullptr) { + // Intentionally left empty. + } + + template + TopologicalLinearEquationSolver::TopologicalLinearEquationSolver(storm::storage::SparseMatrix const& A) : localA(nullptr), A(nullptr) { + this->setMatrix(A); + } + + template + TopologicalLinearEquationSolver::TopologicalLinearEquationSolver(storm::storage::SparseMatrix&& A) : localA(nullptr), A(nullptr) { + this->setMatrix(std::move(A)); + } + + template + void TopologicalLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& A) { + localA.reset(); + this->A = &A; + clearCache(); + } + + template + void TopologicalLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& A) { + localA = std::make_unique>(std::move(A)); + this->A = localA.get(); + clearCache(); + } + + template + storm::Environment TopologicalLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const { + storm::Environment subEnv(env); + subEnv.solver().setLinearEquationSolverType(env.solver().topological().getUnderlyingEquationSolverType(), env.solver().topological().isUnderlyingEquationSolverTypeSetFromDefault()); + if (adaptPrecision) { + STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed."); + auto subEnvPrec = subEnv.solver().getPrecisionOfLinearEquationSolver(subEnv.solver().getLinearEquationSolverType()); + subEnv.solver().setLinearEquationSolverPrecision(static_cast(subEnvPrec.first.get() / storm::utility::convertNumber(this->longestSccChainSize.get()))); + } + return subEnv; + } + + template + bool TopologicalLinearEquationSolver::internalSolveEquations(Environment const& env, std::vector& x, std::vector const& b) const { + + // For sound computations we need to increase the precision in each SCC + bool needAdaptPrecision = env.solver().isForceSoundness() && env.solver().getPrecisionOfLinearEquationSolver(env.solver().topological().getUnderlyingEquationSolverType()).first.is_initialized(); + + if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) { + STORM_LOG_TRACE("Creating SCC decomposition."); + createSortedSccDecomposition(needAdaptPrecision); + } + + // We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic) + needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->getMatrixRowCount()); + + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); + + STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << " SCC(s). Average size is " << static_cast(this->getMatrixRowCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); + if (this->longestSccChainSize) { + STORM_LOG_INFO("Longest SCC chain size is " << this->longestSccChainSize.get() << "."); + } + + // Handle the case where there is just one large SCC + bool returnValue = true; + if (this->sortedSccDecomposition->size() == 1) { + returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, x, b); + } else { + storm::storage::BitVector sccAsBitVector(x.size(), false); + for (auto const& scc : *this->sortedSccDecomposition) { + if (scc.isTrivial()) { + returnValue = solveTrivialScc(*scc.begin(), x, b) && returnValue; + } else { + sccAsBitVector.clear(); + for (auto const& state : scc) { + sccAsBitVector.set(state, true); + } + returnValue = solveScc(sccSolverEnvironment, sccAsBitVector, x, b) && returnValue; + } + } + } + + if (!this->isCachingEnabled()) { + clearCache(); + } + + + + + return returnValue; + } + + template + void TopologicalLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { + // Obtain the scc decomposition + this->sortedSccDecomposition = std::make_unique>(*this->A); + if (needLongestChainSize) { + this->longestSccChainSize = 0; + this->sortedSccDecomposition->sortTopologically(*this->A, &(this->longestSccChainSize.get())); + } else { + this->sortedSccDecomposition->sortTopologically(*this->A); + } + } + + template + bool TopologicalLinearEquationSolver::solveTrivialScc(uint64_t const& sccState, std::vector& globalX, std::vector const& globalB) const { + ValueType& xi = globalX[sccState]; + xi = globalB[sccState]; + bool hasDiagonalEntry = false; + ValueType denominator; + for (auto const& entry : this->A->getRow(sccState)) { + if (entry.getColumn() == sccState) { + STORM_LOG_ASSERT(!storm::utility::isOne(entry.getValue()), "Diagonal entry of fix point system has value 1."); + hasDiagonalEntry = true; + denominator = storm::utility::one() - entry.getValue(); + } else { + xi += entry.getValue() * globalX[entry.getColumn()]; + } + } + + if (hasDiagonalEntry) { + xi /= denominator; + } + return true; + } + + template + bool TopologicalLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, std::vector& x, std::vector const& b) const { + if (!this->sccSolver) { + this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + this->sccSolver->setBoundsFromOtherSolver(*this); + if (this->sccSolver->getEquationProblemFormat(sccSolverEnvironment) == LinearEquationSolverProblemFormat::EquationSystem) { + // Convert the matrix to an equation system. Note that we need to insert diagonal entries. + storm::storage::SparseMatrix eqSysA(*this->A, true); + eqSysA.convertToEquationSystem(); + this->sccSolver->setMatrix(std::move(eqSysA)); + } else { + this->sccSolver->setMatrix(*this->A); + } + } + return this->sccSolver->solveEquations(sccSolverEnvironment, x, b); + } + + template + bool TopologicalLinearEquationSolver::solveScc(storm::Environment const& sccSolverEnvironment, storm::storage::BitVector const& scc, std::vector& globalX, std::vector const& globalB) const { + + // Set up the SCC solver + if (!this->sccSolver) { + this->sccSolver = GeneralLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + } + + // Matrix + bool asEquationSystem = this->sccSolver->getEquationProblemFormat(sccSolverEnvironment) == LinearEquationSolverProblemFormat::EquationSystem; + storm::storage::SparseMatrix sccA = this->A->getSubmatrix(true, scc, scc, asEquationSystem); + if (asEquationSystem) { + sccA.convertToEquationSystem(); + } +// std::cout << "Solving SCC " << scc << std::endl; +// std::cout << "Matrix is " << sccA << std::endl; + this->sccSolver->setMatrix(std::move(sccA)); + + // x Vector + auto sccX = storm::utility::vector::filterVector(globalX, scc); + + // b Vector + std::vector sccB; + sccB.reserve(scc.getNumberOfSetBits()); + for (auto const& row : scc) { + ValueType bi = globalB[row]; + for (auto const& entry : this->A->getRow(row)) { + if (!scc.get(entry.getColumn())) { + bi += entry.getValue() * globalX[entry.getColumn()]; + } + } + sccB.push_back(std::move(bi)); + } + + // lower/upper bounds + if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setLowerBound(this->getLowerBound()); + } else if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setLowerBounds(storm::utility::vector::filterVector(this->getLowerBounds(), scc)); + } + if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setUpperBound(this->getUpperBound()); + } else if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), scc)); + } + + //std::cout << "rhs is " << storm::utility::vector::toString(sccB) << std::endl; + //std::cout << "x is " << storm::utility::vector::toString(sccX) << std::endl; + + bool returnvalue = this->sccSolver->solveEquations(sccSolverEnvironment, sccX, sccB); + storm::utility::vector::setVectorValues(globalX, scc, sccX); + return returnvalue; + } + + template + LinearEquationSolverProblemFormat TopologicalLinearEquationSolver::getEquationProblemFormat(Environment const& env) const { + return LinearEquationSolverProblemFormat::FixedPointSystem; + } + + template + LinearEquationSolverRequirements TopologicalLinearEquationSolver::getRequirements(Environment const& env) const { + // Return the requirements of the underlying solver + return GeneralLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env)); + } + + template + void TopologicalLinearEquationSolver::clearCache() const { + sortedSccDecomposition.reset(); + longestSccChainSize = boost::none; + sccSolver.reset(); + LinearEquationSolver::clearCache(); + } + + template + uint64_t TopologicalLinearEquationSolver::getMatrixRowCount() const { + return this->A->getRowCount(); + } + + template + uint64_t TopologicalLinearEquationSolver::getMatrixColumnCount() const { + return this->A->getColumnCount(); + } + + template + std::unique_ptr> TopologicalLinearEquationSolverFactory::create(Environment const& env) const { + return std::make_unique>(); + } + + template + std::unique_ptr> TopologicalLinearEquationSolverFactory::clone() const { + return std::make_unique>(*this); + } + + // Explicitly instantiate the linear equation solver. + template class TopologicalLinearEquationSolver; + template class TopologicalLinearEquationSolverFactory; + +#ifdef STORM_HAVE_CARL + template class TopologicalLinearEquationSolver; + template class TopologicalLinearEquationSolverFactory; + + template class TopologicalLinearEquationSolver; + template class TopologicalLinearEquationSolverFactory; + +#endif + } +} diff --git a/src/storm/solver/TopologicalLinearEquationSolver.h b/src/storm/solver/TopologicalLinearEquationSolver.h new file mode 100644 index 000000000..4c754c44e --- /dev/null +++ b/src/storm/solver/TopologicalLinearEquationSolver.h @@ -0,0 +1,76 @@ +#pragma once + +#include "storm/solver/LinearEquationSolver.h" + +#include "storm/solver/SolverSelectionOptions.h" +#include "storm/solver/NativeMultiplier.h" +#include "storm/storage/StronglyConnectedComponentDecomposition.h" + +namespace storm { + + class Environment; + + namespace solver { + + template + class TopologicalLinearEquationSolver : public LinearEquationSolver { + public: + TopologicalLinearEquationSolver(); + TopologicalLinearEquationSolver(storm::storage::SparseMatrix const& A); + TopologicalLinearEquationSolver(storm::storage::SparseMatrix&& A); + + virtual void setMatrix(storm::storage::SparseMatrix const& A) override; + virtual void setMatrix(storm::storage::SparseMatrix&& A) override; + + virtual LinearEquationSolverProblemFormat getEquationProblemFormat(storm::Environment const& env) const override; + virtual LinearEquationSolverRequirements getRequirements(Environment const& env) const override; + + virtual void clearCache() const override; + + protected: + virtual bool internalSolveEquations(storm::Environment const& env, std::vector& x, std::vector const& b) const override; + + private: + + virtual uint64_t getMatrixRowCount() const override; + virtual uint64_t getMatrixColumnCount() const override; + + storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision = false) const; + + // Creates an SCC decomposition and sorts the SCCs according to a topological sort. + void createSortedSccDecomposition(bool needLongestChainSize) const; + + // Solves the SCC with the given index + // ... for the case that the SCC is trivial + bool solveTrivialScc(uint64_t const& sccState, std::vector& globalX, std::vector const& globalB) const; + // ... for the case that there is just one large SCC + bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, std::vector& x, std::vector const& b) const; + // ... for the remaining cases (1 < scc.size() < x.size()) + bool solveScc(storm::Environment const& sccSolverEnvironment, storm::storage::BitVector const& scc, std::vector& globalX, std::vector const& globalB) const; + + // If the solver takes posession of the matrix, we store the moved matrix in this member, so it gets deleted + // when the solver is destructed. + std::unique_ptr> localA; + + // A pointer to the original sparse matrix given to this solver. If the solver takes posession of the matrix + // the pointer refers to localA. + storm::storage::SparseMatrix const* A; + + // cached auxiliary data + mutable std::unique_ptr> sortedSccDecomposition; + mutable boost::optional longestSccChainSize; + mutable std::unique_ptr> sccSolver; + }; + + template + class TopologicalLinearEquationSolverFactory : public LinearEquationSolverFactory { + public: + using LinearEquationSolverFactory::create; + + virtual std::unique_ptr> create(Environment const& env) const override; + + virtual std::unique_ptr> clone() const override; + + }; + } +} diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp index 9e33a4c9e..d6c1b69e1 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.cpp @@ -1,485 +1,309 @@ #include "storm/solver/TopologicalMinMaxLinearEquationSolver.h" +#include "storm/environment/solver/MinMaxSolverEnvironment.h" +#include "storm/environment/solver/TopologicalSolverEnvironment.h" + +#include "storm/utility/constants.h" #include "storm/utility/vector.h" -#include "storm/utility/graph.h" -#include "storm/storage/StronglyConnectedComponentDecomposition.h" -#include "storm/exceptions/IllegalArgumentException.h" #include "storm/exceptions/InvalidStateException.h" #include "storm/exceptions/InvalidEnvironmentException.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/UncheckedRequirementException.h" -#include "storm/environment/solver/MinMaxSolverEnvironment.h" +namespace storm { + namespace solver { -#include "storm/settings/SettingsManager.h" -#include "storm/settings/modules/CoreSettings.h" + template + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() { + // Intentionally left empty. + } -#include "storm/utility/macros.h" -#include "storm-config.h" -#ifdef STORM_HAVE_CUDA -# include "cudaForStorm.h" -#endif + template + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : StandardMinMaxLinearEquationSolver(A) { + // Intentionally left empty. + } -namespace storm { - namespace solver { + template + TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A) : StandardMinMaxLinearEquationSolver(std::move(A)) { + // Intentionally left empty. + } template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver() { - // Get the settings object to customize solving. - this->enableCuda = storm::settings::getModule().isUseCudaSet(); -#ifdef STORM_HAVE_CUDA - STORM_LOG_INFO_COND(this->enableCuda, "Option CUDA was not set, but the topological value iteration solver will use it anyways."); -#endif + storm::Environment TopologicalMinMaxLinearEquationSolver::getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision) const { + storm::Environment subEnv(env); + subEnv.solver().minMax().setMethod(env.solver().topological().getUnderlyingMinMaxMethod(), env.solver().topological().isUnderlyingMinMaxMethodSetFromDefault()); + if (adaptPrecision) { + STORM_LOG_ASSERT(this->longestSccChainSize, "Did not compute the longest SCC chain size although it is needed."); + storm::RationalNumber subEnvPrec = subEnv.solver().minMax().getPrecision() / storm::utility::convertNumber(this->longestSccChainSize.get()); + subEnv.solver().minMax().setPrecision(subEnvPrec); + } + return subEnv; } template - TopologicalMinMaxLinearEquationSolver::TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A) : TopologicalMinMaxLinearEquationSolver() { - this->setMatrix(A); + bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + STORM_LOG_ASSERT(x.size() == this->A->getRowGroupCount(), "Provided x-vector has invalid size."); + STORM_LOG_ASSERT(b.size() == this->A->getRowCount(), "Provided b-vector has invalid size."); + + // For sound computations we need to increase the precision in each SCC + bool needAdaptPrecision = env.solver().isForceSoundness(); + + if (!this->sortedSccDecomposition || (needAdaptPrecision && !this->longestSccChainSize)) { + STORM_LOG_TRACE("Creating SCC decomposition."); + createSortedSccDecomposition(needAdaptPrecision); + } + + // We do not need to adapt the precision if all SCCs are trivial (i.e., the system is acyclic) + needAdaptPrecision = needAdaptPrecision && (this->sortedSccDecomposition->size() != this->A->getRowGroupCount()); + + storm::Environment sccSolverEnvironment = getEnvironmentForUnderlyingSolver(env, needAdaptPrecision); + + STORM_LOG_INFO("Found " << this->sortedSccDecomposition->size() << " SCC(s). Average size is " << static_cast(this->A->getRowGroupCount()) / static_cast(this->sortedSccDecomposition->size()) << "."); + if (this->longestSccChainSize) { + STORM_LOG_INFO("Longest SCC chain size is " << this->longestSccChainSize.get()); + } + + bool returnValue = true; + if (this->sortedSccDecomposition->size() == 1) { + // Handle the case where there is just one large SCC + returnValue = solveFullyConnectedEquationSystem(sccSolverEnvironment, dir, x, b); + } else { + if (this->isTrackSchedulerSet()) { + if (this->schedulerChoices) { + this->schedulerChoices.get().resize(x.size()); + } else { + this->schedulerChoices = std::vector(x.size()); + } + } + storm::storage::BitVector sccRowGroupsAsBitVector(x.size(), false); + storm::storage::BitVector sccRowsAsBitVector(b.size(), false); + for (auto const& scc : *this->sortedSccDecomposition) { + if (scc.isTrivial()) { + returnValue = solveTrivialScc(*scc.begin(), dir, x, b) && returnValue; + } else { + sccRowGroupsAsBitVector.clear(); + sccRowsAsBitVector.clear(); + for (auto const& group : scc) { + sccRowGroupsAsBitVector.set(group, true); + for (uint64_t row = this->A->getRowGroupIndices()[group]; row < this->A->getRowGroupIndices()[group + 1]; ++row) { + sccRowsAsBitVector.set(row, true); + } + } + returnValue = solveScc(sccSolverEnvironment, dir, sccRowGroupsAsBitVector, sccRowsAsBitVector, x, b) && returnValue; + } + } + + // If requested, we store the scheduler for retrieval. + if (this->isTrackSchedulerSet()) { + if (!auxiliaryRowGroupVector) { + auxiliaryRowGroupVector = std::make_unique>(this->A->getRowGroupCount()); + } + this->schedulerChoices = std::vector(this->A->getRowGroupCount()); + this->A->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *auxiliaryRowGroupVector.get(), &this->schedulerChoices.get()); + } + } + + if (!this->isCachingEnabled()) { + clearCache(); + } + + return returnValue; } template - void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& matrix) { - this->localA = nullptr; - this->A = &matrix; + void TopologicalMinMaxLinearEquationSolver::createSortedSccDecomposition(bool needLongestChainSize) const { + // Obtain the scc decomposition + this->sortedSccDecomposition = std::make_unique>(*this->A); + if (needLongestChainSize) { + this->longestSccChainSize = 0; + this->sortedSccDecomposition->sortTopologically(*this->A, &(this->longestSccChainSize.get())); + } else { + this->sortedSccDecomposition->sortTopologically(*this->A); + } } template - void TopologicalMinMaxLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& matrix) { - this->localA = std::make_unique>(std::move(matrix)); - this->A = this->localA.get(); + bool TopologicalMinMaxLinearEquationSolver::solveTrivialScc(uint64_t const& sccState, OptimizationDirection dir, std::vector& globalX, std::vector const& globalB) const { + ValueType& xi = globalX[sccState]; + bool firstRow = true; + uint64_t bestRow; + + for (uint64_t row = this->A->getRowGroupIndices()[sccState]; row < this->A->getRowGroupIndices()[sccState + 1]; ++row) { + ValueType rowValue = globalB[row]; + bool hasDiagonalEntry = false; + ValueType denominator; + for (auto const& entry : this->A->getRow(row)) { + if (entry.getColumn() == sccState) { + STORM_LOG_ASSERT(!storm::utility::isOne(entry.getValue()), "Diagonal entry of fix point system has value 1."); + hasDiagonalEntry = true; + denominator = storm::utility::one() - entry.getValue(); + } else { + rowValue += entry.getValue() * globalX[entry.getColumn()]; + } + } + if (hasDiagonalEntry) { + rowValue /= denominator; + } + if (firstRow) { + xi = std::move(rowValue); + bestRow = row; + firstRow = false; + } else { + if (minimize(dir)) { + if (rowValue < xi) { + xi = std::move(rowValue); + bestRow = row; + } + } else { + if (rowValue > xi) { + xi = std::move(rowValue); + bestRow = row; + } + } + } + } + if (this->isTrackSchedulerSet()) { + this->schedulerChoices.get()[sccState] = bestRow - this->A->getRowGroupIndices()[sccState]; + } + //std::cout << "Solved trivial scc " << sccState << " with result " << globalX[sccState] << std::endl; + return true; } template - bool TopologicalMinMaxLinearEquationSolver::internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); - - ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); - uint64_t maxIters = env.solver().minMax().getMaximalNumberOfIterations(); - bool relative = env.solver().minMax().getMaximalNumberOfIterations(); - -#ifdef GPU_USE_FLOAT -#define __FORCE_FLOAT_CALCULATION true -#else -#define __FORCE_FLOAT_CALCULATION false -#endif - if (__FORCE_FLOAT_CALCULATION && std::is_same::value) { - // FIXME: This actually allocates quite some storage, because of this conversion, is it really necessary? - storm::storage::SparseMatrix newA = this->A->template toValueType(); - - TopologicalMinMaxLinearEquationSolver newSolver(newA); - - std::vector new_x = storm::utility::vector::toValueType(x); - std::vector const new_b = storm::utility::vector::toValueType(b); - - bool callConverged = newSolver.solveEquations(env, dir, new_x, new_b); - - for (size_t i = 0, size = new_x.size(); i < size; ++i) { - x.at(i) = new_x.at(i); - } - return callConverged; - } - - // For testing only - if (sizeof(ValueType) == sizeof(double)) { - //std::cout << "<<< Using CUDA-DOUBLE Kernels >>>" << std::endl; - STORM_LOG_INFO("<<< Using CUDA-DOUBLE Kernels >>>"); - } else { - //std::cout << "<<< Using CUDA-FLOAT Kernels >>>" << std::endl; - STORM_LOG_INFO("<<< Using CUDA-FLOAT Kernels >>>"); - } - - // Now, we need to determine the SCCs of the MDP and perform a topological sort. - std::vector const& nondeterministicChoiceIndices = this->A->getRowGroupIndices(); - - // Check if the decomposition is necessary -#ifdef STORM_HAVE_CUDA -#define __USE_CUDAFORSTORM_OPT true - size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(A->getRowCount()), nondeterministicChoiceIndices.size(), static_cast(A->getEntryCount())); - size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); -#else -#define __USE_CUDAFORSTORM_OPT false - size_t const gpuSizeOfCompleteSystem = 0; - size_t const cudaFreeMemory = 0; -#endif - std::vector> sccDecomposition; - if (__USE_CUDAFORSTORM_OPT && (gpuSizeOfCompleteSystem < cudaFreeMemory)) { - // Dummy output for SCC Times - //std::cout << "Computing the SCC Decomposition took 0ms" << std::endl; - -#ifdef STORM_HAVE_CUDA - STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA Equation Solver."); - - bool result = false; - size_t globalIterations = 0; - if (dir == OptimizationDirection::Minimize) { - result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); - } else { - result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, A->rowIndications, A->columnsAndValues, x, b, nondeterministicChoiceIndices, globalIterations); - } - STORM_LOG_INFO("Executed " << globalIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); - - bool converged = false; - if (!result) { - converged = false; - STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); - throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; - } else { - converged = true; - } - - // Check if the solver converged and issue a warning otherwise. - if (converged) { - STORM_LOG_INFO("Iterative solver converged after " << globalIterations << " iterations."); - } else { - STORM_LOG_WARN("Iterative solver did not converged after " << globalIterations << " iterations."); - } -#else - STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); - throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; -#endif - } else { - storm::storage::BitVector fullSystem(this->A->getRowGroupCount(), true); - storm::storage::StronglyConnectedComponentDecomposition sccDecomposition(*this->A, fullSystem, false, false); - - STORM_LOG_THROW(sccDecomposition.size() > 0, storm::exceptions::IllegalArgumentException, "Can not solve given equation system as the SCC decomposition returned no SCCs."); - - storm::storage::SparseMatrix stronglyConnectedComponentsDependencyGraph = sccDecomposition.extractPartitionDependencyGraph(*this->A); - std::vector topologicalSort = storm::utility::graph::getTopologicalSort(stronglyConnectedComponentsDependencyGraph); - - // Calculate the optimal distribution of sccs - std::vector> optimalSccs = this->getOptimalGroupingFromTopologicalSccDecomposition(sccDecomposition, topologicalSort, *this->A); - STORM_LOG_INFO("Optimized SCC Decomposition, originally " << topologicalSort.size() << " SCCs, optimized to " << optimalSccs.size() << " SCCs."); - - std::vector* currentX = nullptr; - std::vector* swap = nullptr; - size_t currentMaxLocalIterations = 0; - size_t localIterations = 0; - size_t globalIterations = 0; - bool converged = true; - - // Iterate over all SCCs of the MDP as specified by the topological sort. This guarantees that an SCC is only - // solved after all SCCs it depends on have been solved. - for (auto sccIndexIt = optimalSccs.cbegin(); sccIndexIt != optimalSccs.cend() && converged; ++sccIndexIt) { - bool const useGpu = sccIndexIt->first; - storm::storage::StateBlock const& scc = sccIndexIt->second; - - // Generate a sub matrix - storm::storage::BitVector subMatrixIndices(this->A->getColumnCount(), scc.cbegin(), scc.cend()); - storm::storage::SparseMatrix sccSubmatrix = this->A->getSubmatrix(true, subMatrixIndices, subMatrixIndices); - std::vector sccSubB(sccSubmatrix.getRowCount()); - storm::utility::vector::selectVectorValues(sccSubB, subMatrixIndices, nondeterministicChoiceIndices, b); - std::vector sccSubX(sccSubmatrix.getColumnCount()); - std::vector sccSubXSwap(sccSubmatrix.getColumnCount()); - std::vector sccMultiplyResult(sccSubmatrix.getRowCount()); - - // Prepare the pointers for swapping in the calculation - currentX = &sccSubX; - swap = &sccSubXSwap; - - storm::utility::vector::selectVectorValues(sccSubX, subMatrixIndices, x); // x is getCols() large, where as b and multiplyResult are getRows() (nondet. choices times states) - std::vector sccSubNondeterministicChoiceIndices(sccSubmatrix.getColumnCount() + 1); - sccSubNondeterministicChoiceIndices.at(0) = 0; - - // Pre-process all dependent states - // Remove outgoing transitions and create the ChoiceIndices - uint_fast64_t innerIndex = 0; - uint_fast64_t outerIndex = 0; - for (uint_fast64_t state : scc) { - // Choice Indices - sccSubNondeterministicChoiceIndices.at(outerIndex + 1) = sccSubNondeterministicChoiceIndices.at(outerIndex) + (nondeterministicChoiceIndices[state + 1] - nondeterministicChoiceIndices[state]); - - for (auto rowGroupIt = nondeterministicChoiceIndices[state]; rowGroupIt != nondeterministicChoiceIndices[state + 1]; ++rowGroupIt) { - typename storm::storage::SparseMatrix::const_rows row = this->A->getRow(rowGroupIt); - for (auto rowIt = row.begin(); rowIt != row.end(); ++rowIt) { - if (!subMatrixIndices.get(rowIt->getColumn())) { - // This is an outgoing transition of a state in the SCC to a state not included in the SCC - // Subtracting Pr(tau) * x_other from b fixes that - sccSubB.at(innerIndex) = sccSubB.at(innerIndex) + (rowIt->getValue() * x.at(rowIt->getColumn())); - } - } - ++innerIndex; - } - ++outerIndex; - } - - // For the current SCC, we need to perform value iteration until convergence. - if (useGpu) { -#ifdef STORM_HAVE_CUDA - STORM_LOG_THROW(resetCudaDevice(), storm::exceptions::InvalidStateException, "Could not reset CUDA Device, can not use CUDA-based equation solver."); - - //STORM_LOG_INFO("Device has " << getTotalCudaMemory() << " Bytes of Memory with " << getFreeCudaMemory() << "Bytes free (" << (static_cast(getFreeCudaMemory()) / static_cast(getTotalCudaMemory())) * 100 << "%)."); - //STORM_LOG_INFO("We will allocate " << (sizeof(uint_fast64_t)* sccSubmatrix.rowIndications.size() + sizeof(uint_fast64_t)* sccSubmatrix.columnsAndValues.size() * 2 + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubX.size() + sizeof(double)* sccSubB.size() + sizeof(double)* sccSubB.size() + sizeof(uint_fast64_t)* sccSubNondeterministicChoiceIndices.size()) << " Bytes."); - //STORM_LOG_INFO("The CUDA Runtime Version is " << getRuntimeCudaVersion()); - - bool result = false; - localIterations = 0; - if (dir == OptimizationDirection::Minimum) { - result = __basicValueIteration_mvReduce_minimize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); - } else { - result = __basicValueIteration_mvReduce_maximize(maxIters, precision, relative, sccSubmatrix.rowIndications, sccSubmatrix.columnsAndValues, *currentX, sccSubB, sccSubNondeterministicChoiceIndices, localIterations); - } - STORM_LOG_INFO("Executed " << localIterations << " of max. " << maximalNumberOfIterations << " Iterations on GPU."); - - if (!result) { - converged = false; - STORM_LOG_ERROR("An error occurred in the CUDA Plugin. Can not continue."); - throw storm::exceptions::InvalidStateException() << "An error occurred in the CUDA Plugin. Can not continue."; - } else { - converged = true; - } - - // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep - // track of the maximum. - if (localIterations > currentMaxLocalIterations) { - currentMaxLocalIterations = localIterations; - } - globalIterations += localIterations; -#else - STORM_LOG_ERROR("The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"); - throw storm::exceptions::InvalidStateException() << "The useGpu Flag of a SCC was set, but this version of storm does not support CUDA acceleration. Internal Error!"; -#endif - } else { - //std::cout << "WARNING: Using CPU based TopoSolver! (double)" << std::endl; - STORM_LOG_INFO("Performance Warning: Using CPU based TopoSolver! (double)"); - localIterations = 0; - converged = false; - while (!converged && localIterations < maxIters) { - // Compute x' = A*x + b. - sccSubmatrix.multiplyWithVector(*currentX, sccMultiplyResult); - storm::utility::vector::addVectors(sccMultiplyResult, sccSubB, sccMultiplyResult); - - //A.multiplyWithVector(scc, nondeterministicChoiceIndices, *currentX, multiplyResult); - //storm::utility::addVectors(scc, nondeterministicChoiceIndices, multiplyResult, b); - - /* - Versus: - A.multiplyWithVector(*currentX, *multiplyResult); - storm::utility::vector::addVectorsInPlace(*multiplyResult, b); - */ - - // Reduce the vector x' by applying min/max for all non-deterministic choices. - storm::utility::vector::reduceVectorMinOrMax(dir,sccMultiplyResult, *swap, sccSubNondeterministicChoiceIndices); - - // Determine whether the method converged. - // TODO: It seems that the equalModuloPrecision call that compares all values should have a higher - // running time. In fact, it is faster. This has to be investigated. - // converged = storm::utility::equalModuloPrecision(*currentX, *newX, scc, precision, relative); - converged = storm::utility::vector::equalModuloPrecision(*currentX, *swap, precision, relative); - - // Update environment variables. - std::swap(currentX, swap); - - ++localIterations; - ++globalIterations; - } - STORM_LOG_INFO("Executed " << localIterations << " of max. " << maxIters << " Iterations."); - } - - - // The Result of this SCC has to be taken back into the main result vector - innerIndex = 0; - for (uint_fast64_t state : scc) { - x.at(state) = currentX->at(innerIndex); - ++innerIndex; - } - - // Since the pointers for swapping in the calculation point to temps they should not be valid anymore - currentX = nullptr; - swap = nullptr; - - // As the "number of iterations" of the full method is the maximum of the local iterations, we need to keep - // track of the maximum. - if (localIterations > currentMaxLocalIterations) { - currentMaxLocalIterations = localIterations; - } - } - - //std::cout << "Used a total of " << globalIterations << " iterations with a maximum of " << localIterations << " iterations in a single block." << std::endl; - - // Check if the solver converged and issue a warning otherwise. - if (converged) { - STORM_LOG_INFO("Iterative solver converged after " << currentMaxLocalIterations << " iterations."); - } else { - STORM_LOG_WARN("Iterative solver did not converged after " << currentMaxLocalIterations << " iterations."); - } - - return converged; - } + bool TopologicalMinMaxLinearEquationSolver::solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, std::vector& x, std::vector const& b) const { + if (!this->sccSolver) { + this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + } + this->sccSolver->setMatrix(*this->A); + this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution()); + this->sccSolver->setBoundsFromOtherSolver(*this); + this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet()); + if (this->hasInitialScheduler()) { + auto choices = this->getInitialScheduler(); + this->sccSolver->setInitialScheduler(std::move(choices)); + } + auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); + if (req.upperBounds() && this->hasUpperBound()) { + req.clearUpperBounds(); + } + 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(); + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); + this->sccSolver->setRequirementsChecked(true); + + bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, x, b); + if (this->isTrackSchedulerSet()) { + this->schedulerChoices = this->sccSolver->getSchedulerChoices(); + } + return res; } - - template - std::vector> - TopologicalMinMaxLinearEquationSolver::getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const { - - (void)matrix; - - std::vector> result; - -#ifdef STORM_HAVE_CUDA - // 95% to have a bit of padding - size_t const cudaFreeMemory = static_cast(getFreeCudaMemory() * 0.95); - size_t lastResultIndex = 0; - - std::vector const& rowGroupIndices = matrix.getRowGroupIndices(); - - size_t const gpuSizeOfCompleteSystem = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(matrix.getRowCount()), rowGroupIndices.size(), static_cast(matrix.getEntryCount())); - size_t const gpuSizePerRowGroup = std::max(static_cast(gpuSizeOfCompleteSystem / rowGroupIndices.size()), static_cast(1)); - size_t const maxRowGroupsPerMemory = cudaFreeMemory / gpuSizePerRowGroup; - - size_t currentSize = 0; - size_t neededReserveSize = 0; - size_t startIndex = 0; - for (size_t i = 0; i < topologicalSort.size(); ++i) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[i]]; - size_t const currentSccSize = scc.size(); - - uint_fast64_t rowCount = 0; - uint_fast64_t entryCount = 0; - - for (auto sccIt = scc.cbegin(); sccIt != scc.cend(); ++sccIt) { - rowCount += matrix.getRowGroupSize(*sccIt); - entryCount += matrix.getRowGroupEntryCount(*sccIt); - } - - size_t sccSize = basicValueIteration_mvReduce_uint64_double_calculateMemorySize(static_cast(rowCount), scc.size(), static_cast(entryCount)); - - if ((currentSize + sccSize) <= cudaFreeMemory) { - // There is enough space left in the current group - neededReserveSize += currentSccSize; - currentSize += sccSize; - } else { - // This would make the last open group to big for the GPU - - if (startIndex < i) { - if ((startIndex + 1) < i) { - // More than one component - std::vector tempGroups; - tempGroups.reserve(neededReserveSize); - - // Copy the first group to make inplace_merge possible - storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; - tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); - - if (((startIndex + 1) + 80) >= i) { - size_t lastSize = 0; - for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - lastSize = tempGroups.size(); - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - std::vector::iterator middleIterator = tempGroups.begin(); - std::advance(middleIterator, lastSize); - std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); - } - } else { - // Use std::sort - for (size_t j = startIndex + 1; j < i; ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - } - std::sort(tempGroups.begin(), tempGroups.end()); - } - result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); - } else { - // Only one group, copy construct. - result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); - } - ++lastResultIndex; - } - - if (sccSize <= cudaFreeMemory) { - currentSize = sccSize; - neededReserveSize = currentSccSize; - startIndex = i; - } else { - // This group is too big to fit into the CUDA Memory by itself - result.push_back(std::make_pair(false, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[i]])))); - ++lastResultIndex; - - currentSize = 0; - neededReserveSize = 0; - startIndex = i + 1; - } - } - } - - size_t const topologicalSortSize = topologicalSort.size(); - if (startIndex < topologicalSortSize) { - if ((startIndex + 1) < topologicalSortSize) { - // More than one component - std::vector tempGroups; - tempGroups.reserve(neededReserveSize); - - // Copy the first group to make inplace_merge possible. - storm::storage::StateBlock const& scc_first = sccDecomposition[topologicalSort[startIndex]]; - tempGroups.insert(tempGroups.cend(), scc_first.cbegin(), scc_first.cend()); - - // For set counts <= 80, in-place merge is faster. - if (((startIndex + 1) + 80) >= topologicalSortSize) { - size_t lastSize = 0; - for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - lastSize = tempGroups.size(); - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - std::vector::iterator middleIterator = tempGroups.begin(); - std::advance(middleIterator, lastSize); - std::inplace_merge(tempGroups.begin(), middleIterator, tempGroups.end()); - } - } else { - // Use std::sort - for (size_t j = startIndex + 1; j < topologicalSort.size(); ++j) { - storm::storage::StateBlock const& scc = sccDecomposition[topologicalSort[j]]; - tempGroups.insert(tempGroups.cend(), scc.cbegin(), scc.cend()); - } - std::sort(tempGroups.begin(), tempGroups.end()); - } - result.push_back(std::make_pair(true, storm::storage::StateBlock(tempGroups.cbegin(), tempGroups.cend()))); - } - else { - // Only one group, copy construct. - result.push_back(std::make_pair(true, storm::storage::StateBlock(std::move(sccDecomposition[topologicalSort[startIndex]])))); - } - ++lastResultIndex; - } -#else - for (auto sccIndexIt = topologicalSort.cbegin(); sccIndexIt != topologicalSort.cend(); ++sccIndexIt) { - storm::storage::StateBlock const& scc = sccDecomposition[*sccIndexIt]; - result.push_back(std::make_pair(false, scc)); - } -#endif - return result; - } - + template - void TopologicalMinMaxLinearEquationSolver::repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const { - std::unique_ptr> multiplyResult = std::make_unique>(this->A->getRowCount()); + bool TopologicalMinMaxLinearEquationSolver::solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection dir, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector& globalX, std::vector const& globalB) const { - // Now perform matrix-vector multiplication as long as we meet the bound of the formula. - for (uint_fast64_t i = 0; i < n; ++i) { - this->A->multiplyWithVector(x, *multiplyResult); - - // Add b if it is non-null. - if (b != nullptr) { - storm::utility::vector::addVectors(*multiplyResult, *b, *multiplyResult); + // Set up the SCC solver + if (!this->sccSolver) { + this->sccSolver = GeneralMinMaxLinearEquationSolverFactory().create(sccSolverEnvironment); + this->sccSolver->setCachingEnabled(true); + } + this->sccSolver->setHasUniqueSolution(this->hasUniqueSolution()); + this->sccSolver->setTrackScheduler(this->isTrackSchedulerSet()); + + // SCC Matrix + storm::storage::SparseMatrix sccA = this->A->getSubmatrix(true, sccRowGroups, sccRowGroups); + //std::cout << "Matrix is " << sccA << std::endl; + this->sccSolver->setMatrix(std::move(sccA)); + + // x Vector + auto sccX = storm::utility::vector::filterVector(globalX, sccRowGroups); + + // b Vector + std::vector sccB; + sccB.reserve(sccRows.getNumberOfSetBits()); + for (auto const& row : sccRows) { + ValueType bi = globalB[row]; + for (auto const& entry : this->A->getRow(row)) { + if (!sccRowGroups.get(entry.getColumn())) { + bi += entry.getValue() * globalX[entry.getColumn()]; + } } - - // Reduce the vector x' by applying min/max for all non-deterministic choices as given by the topmost - // element of the min/max operator stack. - storm::utility::vector::reduceVectorMinOrMax(dir, *multiplyResult, x, this->A->getRowGroupIndices()); + sccB.push_back(std::move(bi)); } - } + + // initial scheduler + if (this->hasInitialScheduler()) { + auto sccInitChoices = storm::utility::vector::filterVector(this->getInitialScheduler(), sccRowGroups); + this->sccSolver->setInitialScheduler(std::move(sccInitChoices)); + } + + // lower/upper bounds + if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setLowerBound(this->getLowerBound()); + } else if (this->hasLowerBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setLowerBounds(storm::utility::vector::filterVector(this->getLowerBounds(), sccRowGroups)); + } + if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Global)) { + this->sccSolver->setUpperBound(this->getUpperBound()); + } else if (this->hasUpperBound(storm::solver::AbstractEquationSolver::BoundType::Local)) { + this->sccSolver->setUpperBounds(storm::utility::vector::filterVector(this->getUpperBounds(), sccRowGroups)); + } + + // Requirements + auto req = this->sccSolver->getRequirements(sccSolverEnvironment, dir); + if (req.upperBounds() && this->hasUpperBound()) { + req.clearUpperBounds(); + } + if (req.lowerBounds() && this->hasLowerBound()) { + req.clearLowerBounds(); + } + if (req.validInitialScheduler() && this->hasInitialScheduler()) { + req.clearValidInitialScheduler(); + } + STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked."); + this->sccSolver->setRequirementsChecked(true); + // Invoke scc solver + bool res = this->sccSolver->solveEquations(sccSolverEnvironment, dir, sccX, sccB); + //std::cout << "rhs is " << storm::utility::vector::toString(sccB) << std::endl; + //std::cout << "x is " << storm::utility::vector::toString(sccX) << std::endl; + + // Set Scheduler choices + if (this->isTrackSchedulerSet()) { + storm::utility::vector::setVectorValues(this->schedulerChoices.get(), sccRowGroups, this->sccSolver->getSchedulerChoices()); + } + + // Set solution + storm::utility::vector::setVectorValues(globalX, sccRowGroups, sccX); + + return res; + } + template - TopologicalMinMaxLinearEquationSolverFactory::TopologicalMinMaxLinearEquationSolverFactory(bool trackScheduler) { - // Intentionally left empty. + MinMaxLinearEquationSolverRequirements TopologicalMinMaxLinearEquationSolver::getRequirements(Environment const& env, boost::optional const& direction, bool const& hasInitialScheduler) const { + // Return the requirements of the underlying solver + return GeneralMinMaxLinearEquationSolverFactory().getRequirements(getEnvironmentForUnderlyingSolver(env), this->hasUniqueSolution(), direction, hasInitialScheduler); } template - std::unique_ptr> TopologicalMinMaxLinearEquationSolverFactory::create(Environment const& env) const { - STORM_LOG_THROW(env.solver().minMax().getMethod() == MinMaxMethod::Topological, storm::exceptions::InvalidEnvironmentException, "This min max solver does not support the selected technique."); - return std::make_unique>(); + void TopologicalMinMaxLinearEquationSolver::clearCache() const { + sortedSccDecomposition.reset(); + longestSccChainSize = boost::none; + sccSolver.reset(); + auxiliaryRowGroupVector.reset(); + StandardMinMaxLinearEquationSolver::clearCache(); } - - // Explicitly instantiate the solver. - template class TopologicalMinMaxLinearEquationSolver; - template class TopologicalMinMaxLinearEquationSolverFactory; - } // namespace solver -} // namespace storm + // Explicitly instantiate the min max linear equation solver. + template class TopologicalMinMaxLinearEquationSolver; + +#ifdef STORM_HAVE_CARL + template class TopologicalMinMaxLinearEquationSolver; +#endif + } +} diff --git a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h index 7bf35c2d2..617f9e1b2 100644 --- a/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h +++ b/src/storm/solver/TopologicalMinMaxLinearEquationSolver.h @@ -1,154 +1,53 @@ -#ifndef STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ -#define STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ +#pragma once -#include "storm/solver/MinMaxLinearEquationSolver.h" +#include "storm/solver/StandardMinMaxLinearEquationSolver.h" + +#include "storm/solver/SolverSelectionOptions.h" #include "storm/storage/StronglyConnectedComponentDecomposition.h" -#include "storm/storage/SparseMatrix.h" -#include "storm/exceptions/NotImplementedException.h" -#include "storm/exceptions/NotSupportedException.h" -#include -#include +namespace storm { -#include "storm-config.h" -#ifdef STORM_HAVE_CUDA -#include "cudaForStorm.h" -#endif + class Environment; -namespace storm { namespace solver { - - /*! - * A class that uses SCC Decompositions to solve a min/max linear equation system. - */ - template - class TopologicalMinMaxLinearEquationSolver : public MinMaxLinearEquationSolver { + + template + class TopologicalMinMaxLinearEquationSolver : public StandardMinMaxLinearEquationSolver { public: TopologicalMinMaxLinearEquationSolver(); - - /*! - * Constructs a min-max linear equation solver with parameters being set according to the settings - * object. - * - * @param A The matrix defining the coefficients of the linear equation system. - */ TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A); - - virtual void setMatrix(storm::storage::SparseMatrix const& matrix) override; - virtual void setMatrix(storm::storage::SparseMatrix&& matrix) override; - - virtual bool internalSolveEquations(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const& b) const override; - - virtual void repeatedMultiply(Environment const& env, OptimizationDirection dir, std::vector& x, std::vector const* b, uint_fast64_t n) const override; - - private: - storm::storage::SparseMatrix const* A; - std::unique_ptr> localA; - - bool enableCuda; - /*! - * Given a topological sort of a SCC Decomposition, this will calculate the optimal grouping of SCCs with respect to the size of the GPU memory. - */ - std::vector> getOptimalGroupingFromTopologicalSccDecomposition(storm::storage::StronglyConnectedComponentDecomposition const& sccDecomposition, std::vector const& topologicalSort, storm::storage::SparseMatrix const& matrix) const; - }; - - template - bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector& x, std::vector const&, std::vector const&, size_t&) { - // - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); - } - template <> - inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { - - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; + TopologicalMinMaxLinearEquationSolver(storm::storage::SparseMatrix&& A); -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_double_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - template <> - inline bool __basicValueIteration_mvReduce_minimize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + virtual ~TopologicalMinMaxLinearEquationSolver() { + } - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; + virtual void clearCache() const override; -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_float_minimize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - - template - bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const, double const, bool const, std::vector const&, std::vector> const&, std::vector&, std::vector const&, std::vector const&, size_t&) { - STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Unsupported template arguments."); - } - template <> - inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { + virtual MinMaxLinearEquationSolverRequirements getRequirements(Environment const& env, boost::optional const& direction = boost::none, bool const& hasInitialScheduler = false) const override ; - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; - -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_double_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - template <> - inline bool __basicValueIteration_mvReduce_maximize(uint_fast64_t const maxIterationCount, double const precision, bool const relativePrecisionCheck, std::vector const& matrixRowIndices, std::vector> const& columnIndicesAndValues, std::vector& x, std::vector const& b, std::vector const& nondeterministicChoiceIndices, size_t& iterationCount) { - - (void)maxIterationCount; - (void)precision; - (void)relativePrecisionCheck; - (void)matrixRowIndices; - (void)columnIndicesAndValues; - (void)x; - (void)b; - (void)nondeterministicChoiceIndices; - (void)iterationCount; - -#ifdef STORM_HAVE_CUDA - return basicValueIteration_mvReduce_uint64_float_maximize(maxIterationCount, precision, relativePrecisionCheck, matrixRowIndices, columnIndicesAndValues, x, b, nondeterministicChoiceIndices, iterationCount); -#else - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm is compiled without CUDA support."); -#endif - } - - template - class TopologicalMinMaxLinearEquationSolverFactory : public MinMaxLinearEquationSolverFactory { - public: - TopologicalMinMaxLinearEquationSolverFactory(bool trackScheduler = false); - protected: - virtual std::unique_ptr> create(Environment const& env) const override; - }; - } // namespace solver -} // namespace storm + virtual bool internalSolveEquations(storm::Environment const& env, OptimizationDirection d, std::vector& x, std::vector const& b) const override; -#endif /* STORM_SOLVER_TOPOLOGICALVALUEITERATIONMINMAXLINEAREQUATIONSOLVER_H_ */ + private: + storm::Environment getEnvironmentForUnderlyingSolver(storm::Environment const& env, bool adaptPrecision = false) const; + + // Creates an SCC decomposition and sorts the SCCs according to a topological sort. + void createSortedSccDecomposition(bool needLongestChainSize) const; + + // Solves the SCC with the given index + // ... for the case that the SCC is trivial + bool solveTrivialScc(uint64_t const& sccState, OptimizationDirection d, std::vector& globalX, std::vector const& globalB) const; + // ... for the case that there is just one large SCC + bool solveFullyConnectedEquationSystem(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, std::vector& x, std::vector const& b) const; + // ... for the remaining cases (1 < scc.size() < x.size()) + bool solveScc(storm::Environment const& sccSolverEnvironment, OptimizationDirection d, storm::storage::BitVector const& sccRowGroups, storm::storage::BitVector const& sccRows, std::vector& globalX, std::vector const& globalB) const; + + // cached auxiliary data + mutable std::unique_ptr> sortedSccDecomposition; + mutable boost::optional longestSccChainSize; + mutable std::unique_ptr> sccSolver; + mutable std::unique_ptr> auxiliaryRowGroupVector; // A.rowGroupCount() entries + }; + } +} diff --git a/src/storm/solver/Z3LpSolver.cpp b/src/storm/solver/Z3LpSolver.cpp index 1dcc1a7f0..bd37e1baa 100644 --- a/src/storm/solver/Z3LpSolver.cpp +++ b/src/storm/solver/Z3LpSolver.cpp @@ -26,7 +26,6 @@ namespace storm { template Z3LpSolver::Z3LpSolver(std::string const& name, OptimizationDirection const& optDir) : LpSolver(optDir) { - STORM_LOG_WARN_COND(name == "", "Z3 does not support names for solvers"); z3::config config; config.set("model", true); context = std::unique_ptr(new z3::context(config)); @@ -128,7 +127,7 @@ namespace storm { template storm::expressions::Variable Z3LpSolver::addBinaryVariable(std::string const& name, ValueType objectiveFunctionCoefficient) { storm::expressions::Variable newVariable = this->manager->declareVariable(name, this->manager->getIntegerType()); - solver->add(expressionAdapter->translateExpression((newVariable.getExpression() >= this->manager->rational(storm::utility::one())) && (newVariable.getExpression() <= this->manager->rational(storm::utility::one())))); + solver->add(expressionAdapter->translateExpression((newVariable.getExpression() >= this->manager->rational(storm::utility::zero())) && (newVariable.getExpression() <= this->manager->rational(storm::utility::one())))); optimizationFunction = optimizationFunction + this->manager->rational(objectiveFunctionCoefficient) * newVariable; return newVariable; } @@ -137,7 +136,6 @@ namespace storm { void Z3LpSolver::addConstraint(std::string const& name, storm::expressions::Expression const& constraint) { STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException, "Illegal constraint is not a relational expression."); STORM_LOG_THROW(constraint.getOperator() != storm::expressions::OperatorType::NotEqual, storm::exceptions::InvalidArgumentException, "Illegal constraint uses inequality operator."); - STORM_LOG_WARN_COND(name == "", "Z3 does not support names for constraints"); solver->add(expressionAdapter->translateExpression(constraint)); } diff --git a/src/storm/solver/helper/SoundValueIterationHelper.cpp b/src/storm/solver/helper/SoundValueIterationHelper.cpp new file mode 100644 index 000000000..674ea5160 --- /dev/null +++ b/src/storm/solver/helper/SoundValueIterationHelper.cpp @@ -0,0 +1,450 @@ +#include "storm/solver/helper/SoundValueIterationHelper.h" + +#include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" +#include "storm/utility/vector.h" +#include "storm/utility/macros.h" +#include "storm/utility/NumberTraits.h" + +#include "storm/exceptions/NotSupportedException.h" + + +namespace storm { + namespace solver { + namespace helper { + + template + SoundValueIterationHelper::SoundValueIterationHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), hasLowerBound(false), hasUpperBound(false), hasDecisionValue(false), convergencePhase1(true), decisionValueBlocks(false), firstIndexViolatingConvergence(0), minIndex(0), maxIndex(0), relative(relative), precision(precision), rowGroupIndices(nullptr) { + STORM_LOG_THROW(matrix.getEntryCount() < std::numeric_limits::max(), storm::exceptions::NotSupportedException, "The number of matrix entries is too large for the selected index type."); + if (!matrix.hasTrivialRowGrouping()) { + rowGroupIndices = &matrix.getRowGroupIndices(); + uint64_t sizeOfLargestRowGroup = matrix.getSizeOfLargestRowGroup(); + xTmp.resize(sizeOfLargestRowGroup); + yTmp.resize(sizeOfLargestRowGroup); + } + x.assign(x.size(), storm::utility::zero()); + y.assign(x.size(), storm::utility::one()); + + numRows = matrix.getRowCount(); + matrixValues.clear(); + matrixColumns.clear(); + rowIndications.clear(); + matrixValues.reserve(matrix.getNonzeroEntryCount()); + matrixColumns.reserve(matrix.getColumnCount()); + rowIndications.reserve(numRows + 1); + rowIndications.push_back(0); + for (IndexType r = 0; r < numRows; ++r) { + for (auto const& entry : matrix.getRow(r)) { + matrixValues.push_back(entry.getValue()); + matrixColumns.push_back(entry.getColumn()); + } + rowIndications.push_back(matrixValues.size()); + } + } + + template + SoundValueIterationHelper::SoundValueIterationHelper(SoundValueIterationHelper&& oldHelper, std::vector& x, std::vector& y, bool relative, ValueType const& precision) : x(x), y(y), xTmp(std::move(oldHelper.xTmp)), yTmp(std::move(oldHelper.yTmp)), hasLowerBound(false), hasUpperBound(false), hasDecisionValue(false), convergencePhase1(true), decisionValueBlocks(false), firstIndexViolatingConvergence(0), minIndex(0), maxIndex(0), relative(relative), precision(precision), numRows(std::move(oldHelper.numRows)), matrixValues(std::move(oldHelper.matrixValues)), matrixColumns(std::move(oldHelper.matrixColumns)), rowIndications(std::move(oldHelper.rowIndications)), rowGroupIndices(oldHelper.rowGroupIndices) { + + x.assign(x.size(), storm::utility::zero()); + y.assign(x.size(), storm::utility::one()); + } + + + template + void SoundValueIterationHelper::setLowerBound(ValueType const& value) { + hasLowerBound = true; + lowerBound = value; + } + + template + void SoundValueIterationHelper::setUpperBound(ValueType const& value) { + hasUpperBound = true; + upperBound = value; + } + + template + void SoundValueIterationHelper::multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi) { + assert(rowIndex < numRows); + ValueType xRes = bi; + ValueType yRes = storm::utility::zero(); + + auto entryIt = matrixValues.begin() + rowIndications[rowIndex]; + auto entryItE = matrixValues.begin() + rowIndications[rowIndex + 1]; + auto colIt = matrixColumns.begin() + rowIndications[rowIndex]; + for (; entryIt != entryItE; ++entryIt, ++colIt) { + xRes += *entryIt * x[*colIt]; + yRes += *entryIt * y[*colIt]; + } + xi = std::move(xRes); + yi = std::move(yRes); + } + + template + void SoundValueIterationHelper::performIterationStep(OptimizationDirection const& dir, std::vector const& b) { + if (rowGroupIndices) { + if (minimize(dir)) { + performIterationStep(b); + } else { + performIterationStep(b); + } + } else { + performIterationStep(b); + } + } + + template + void SoundValueIterationHelper::performIterationStep(std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + IndexType row = numRows; + while (row > 0) { + --row; + multiplyRow(row, b[row], *xIt, *yIt); + ++xIt; + ++yIt; + } + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::performIterationStep(std::vector const& b) { + if (!decisionValueBlocks) { + performIterationStepUpdateDecisionValue(b); + } else { + assert(decisionValue == getPrimaryBound()); + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = rowGroupIndices->rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = rowGroupIndices->rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + IndexType row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (currentValue == bestValue && yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + xBest = std::move(xi); + yBest = std::move(yi); + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::performIterationStepUpdateDecisionValue(std::vector const& b) { + auto xIt = x.rbegin(); + auto yIt = y.rbegin(); + auto groupStartIt = rowGroupIndices->rbegin(); + uint64_t groupEnd = *groupStartIt; + ++groupStartIt; + for (auto groupStartIte = rowGroupIndices->rend(); groupStartIt != groupStartIte; groupEnd = *(groupStartIt++), ++xIt, ++yIt) { + // Perform the iteration for the first row in the group + uint64_t row = *groupStartIt; + ValueType xBest, yBest; + multiplyRow(row, b[row], xBest, yBest); + ++row; + // Only do more work if there are still rows in this row group + if (row != groupEnd) { + ValueType xi, yi; + uint64_t xyTmpIndex = 0; + if (hasPrimaryBound()) { + ValueType bestValue = xBest + yBest * getPrimaryBound(); + for (;row < groupEnd; ++row) { + // Get the multiplication results + multiplyRow(row, b[row], xi, yi); + ValueType currentValue = xi + yi * getPrimaryBound(); + // Check if the current row is better then the previously found one + if (better(currentValue, bestValue)) { + if (yBest < yi) { + // We need to store the 'old' best value as it might be relevant for the decision value + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + } + xBest = std::move(xi); + yBest = std::move(yi); + bestValue = std::move(currentValue); + } else if (yBest > yi) { + // If the value for this row is not strictly better, it might still be equal and have a better y value + if (currentValue == bestValue) { + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + } else { + for (;row < groupEnd; ++row) { + multiplyRow(row, b[row], xi, yi); + // Update the best choice + if (yi > yBest || (yi == yBest && better(xi, xBest))) { + xTmp[xyTmpIndex] = std::move(xBest); + yTmp[xyTmpIndex] = std::move(yBest); + ++xyTmpIndex; + xBest = std::move(xi); + yBest = std::move(yi); + } else { + xTmp[xyTmpIndex] = std::move(xi); + yTmp[xyTmpIndex] = std::move(yi); + ++xyTmpIndex; + } + } + } + + // Update the decision value + for (uint64_t i = 0; i < xyTmpIndex; ++i) { + ValueType deltaY = yBest - yTmp[i]; + if (deltaY > storm::utility::zero()) { + ValueType newDecisionValue = (xTmp[i] - xBest) / deltaY; + if (!hasDecisionValue || better(newDecisionValue, decisionValue)) { + decisionValue = std::move(newDecisionValue); + hasDecisionValue = true; + } + } + } + } + *xIt = std::move(xBest); + *yIt = std::move(yBest); + } + } + + template + bool SoundValueIterationHelper::checkConvergenceUpdateBounds(OptimizationDirection const& dir, storm::storage::BitVector const* relevantValues) { + if (rowGroupIndices) { + if (minimize(dir)) { + return checkConvergenceUpdateBounds(relevantValues); + } else { + return checkConvergenceUpdateBounds(relevantValues); + } + } else { + return checkConvergenceUpdateBounds(relevantValues); + } + } + + template + bool SoundValueIterationHelper::checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues) { + return checkConvergenceUpdateBounds(relevantValues); + } + + template + template::InternalOptimizationDirection dir> + bool SoundValueIterationHelper::checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues) { + + if (convergencePhase1) { + if (checkConvergencePhase1()) { + firstIndexViolatingConvergence = 0; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); + } + } else { + return false; + } + } + STORM_LOG_ASSERT(!std::any_of(y.begin(), y.end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point."); + + // Reaching this point means that we are in Phase 2: + // The difference between lower and upper bound has to be < precision at every (relevant) value + + // For efficiency reasons we first check whether it is worth to compute the actual bounds. We do so by considering possibly too tight bounds + ValueType lowerBoundCandidate, upperBoundCandidate; + if (preliminaryConvergenceCheck(lowerBoundCandidate, upperBoundCandidate)) { + updateLowerUpperBound(lowerBoundCandidate, upperBoundCandidate); + if (dir != InternalOptimizationDirection::None) { + checkIfDecisionValueBlocks(); + } + return checkConvergencePhase2(relevantValues); + } + return false; + } + + template + void SoundValueIterationHelper::setSolutionVector() { + // Due to a custom termination criterion it might be the case that one of the bounds was not yet established. + ValueType meanBound; + if (!hasLowerBound) { + STORM_LOG_WARN("No lower result bound was computed during sound value iteration."); + if (hasUpperBound) { + meanBound = upperBound; + } else { + STORM_LOG_WARN("No upper result bound was computed during sound value iteration."); + meanBound = storm::utility::zero(); + } + } else if (!hasUpperBound) { + STORM_LOG_WARN("No upper result bound was computed during sound value iteration."); + meanBound = lowerBound; + } else { + meanBound = (upperBound + lowerBound) / storm::utility::convertNumber(2.0); + } + + storm::utility::vector::applyPointwise(x, y, x, [&meanBound] (ValueType const& xi, ValueType const& yi) -> ValueType { return xi + yi * meanBound; }); + + STORM_LOG_INFO("Sound Value Iteration terminated with lower bound (over all states) " + << (hasLowerBound ? lowerBound : storm::utility::zero()) << (hasLowerBound ? "" : "(none)") + << " and upper bound (over all states) " + << (hasUpperBound ? upperBound : storm::utility::infinity()) << (hasUpperBound ? "" : "(none)") + << ". Decision value is " + << (hasDecisionValue ? decisionValue : -storm::utility::infinity()) << (hasDecisionValue ? "" : "(none)") + << "."); + } + + template + bool SoundValueIterationHelper::checkCustomTerminationCondition(storm::solver::TerminationCondition const& condition) { + if (condition.requiresGuarantee(storm::solver::SolverGuarantee::GreaterOrEqual)) { + if (hasUpperBound && condition.terminateNow( + [&](uint64_t const& i) { + return x[i] + y[i] * upperBound; + }, storm::solver::SolverGuarantee::GreaterOrEqual)) { + return true; + } + } else if (condition.requiresGuarantee(storm::solver::SolverGuarantee::LessOrEqual)) { + if (hasLowerBound && condition.terminateNow( + [&](uint64_t const& i) { + return x[i] + y[i] * lowerBound; + }, storm::solver::SolverGuarantee::LessOrEqual)) { + return true; + } + } + return false; + } + + template + bool SoundValueIterationHelper::checkConvergencePhase1() { + // Return true if y ('the probability to stay within the matrix') is < 1 at every entry + for (; firstIndexViolatingConvergence != y.size(); ++firstIndexViolatingConvergence) { + static_assert(NumberTraits::IsExact || std::is_same::value, "Considered ValueType not handled."); + if (NumberTraits::IsExact) { + if (storm::utility::isOne(y[firstIndexViolatingConvergence])) { + return false; + } + } else { + if (storm::utility::isAlmostOne(storm::utility::convertNumber(y[firstIndexViolatingConvergence]))) { + return false; + } + } + } + convergencePhase1 = false; + return true; + } + + + template + bool SoundValueIterationHelper::isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub) { + return yi * (ub - lb) <= storm::utility::abs((relative ? (precision * xi) : (precision * storm::utility::convertNumber(2.0)))); + } + + template + template::InternalOptimizationDirection dir> + bool SoundValueIterationHelper::preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + lowerBoundCandidate = x[minIndex] / (storm::utility::one() - y[minIndex]); + upperBoundCandidate = x[maxIndex] / (storm::utility::one() - y[maxIndex]); + // Make sure that these candidates are at least as tight as the already known bounds + if (hasLowerBound && lowerBoundCandidate < lowerBound) { + lowerBoundCandidate = lowerBound; + } + if (hasUpperBound && upperBoundCandidate > upperBound) { + upperBoundCandidate = upperBound; + } + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBoundCandidate, upperBoundCandidate)) { + return true; + } + if (dir != InternalOptimizationDirection::None && !decisionValueBlocks) { + return hasDecisionValue && better(decisionValue, getPrimaryBound()); + } + return false; + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate) { + auto xIt = x.begin(); + auto xIte = x.end(); + auto yIt = y.begin(); + for (uint64_t index = 0; xIt != xIte; ++xIt, ++yIt, ++index) { + ValueType currentBound = *xIt / (storm::utility::one() - *yIt); + if (dir != InternalOptimizationDirection::None && decisionValueBlocks) { + if (better(getSecondaryBound(), currentBound)) { + getSecondaryIndex() = index; + getSecondaryBound() = std::move(currentBound); + } + } else { + if (currentBound < lowerBoundCandidate) { + minIndex = index; + lowerBoundCandidate = std::move(currentBound); + } else if (currentBound > upperBoundCandidate) { + maxIndex = index; + upperBoundCandidate = std::move(currentBound); + } + } + } + if ((dir != InternalOptimizationDirection::Minimize || !decisionValueBlocks) && (!hasLowerBound || lowerBoundCandidate > lowerBound)) { + setLowerBound(lowerBoundCandidate); + } + if ((dir != InternalOptimizationDirection::Maximize || !decisionValueBlocks) && (!hasUpperBound || upperBoundCandidate < upperBound)) { + setUpperBound(upperBoundCandidate); + } + } + + template + template::InternalOptimizationDirection dir> + void SoundValueIterationHelper::checkIfDecisionValueBlocks() { + // Check whether the decision value blocks now (i.e. further improvement of the primary bound would lead to a non-optimal scheduler). + if (!decisionValueBlocks && hasDecisionValue && better(decisionValue, getPrimaryBound())) { + getPrimaryBound() = decisionValue; + decisionValueBlocks = true; + } + } + + template + bool SoundValueIterationHelper::checkConvergencePhase2(storm::storage::BitVector const* relevantValues) { + // Check whether the desired precision is reached + if (isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // The current index satisfies the desired bound. We now move to the next index that violates it + while (true) { + ++firstIndexViolatingConvergence; + if (relevantValues != nullptr) { + firstIndexViolatingConvergence = relevantValues->getNextSetIndex(firstIndexViolatingConvergence); + } + if (firstIndexViolatingConvergence == x.size()) { + // Converged! + return true; + } else { + if (!isPreciseEnough(x[firstIndexViolatingConvergence], y[firstIndexViolatingConvergence], lowerBound, upperBound)) { + // not converged yet + return false; + } + } + } + } + return false; + } + + template class SoundValueIterationHelper; + template class SoundValueIterationHelper; + } + + } +} + diff --git a/src/storm/solver/helper/SoundValueIterationHelper.h b/src/storm/solver/helper/SoundValueIterationHelper.h new file mode 100644 index 000000000..54cdc1fb1 --- /dev/null +++ b/src/storm/solver/helper/SoundValueIterationHelper.h @@ -0,0 +1,151 @@ +#pragma once + +#include + +#include "storm/solver/OptimizationDirection.h" +#include "storm/solver/TerminationCondition.h" + +namespace storm { + + namespace storage { + template + class SparseMatrix; + + class BitVector; + } + + namespace solver { + namespace helper { + + + template + class SoundValueIterationHelper { + public: + + typedef uint32_t IndexType; + + /*! + * Creates a new helper from the given data + */ + SoundValueIterationHelper(storm::storage::SparseMatrix const& matrix, std::vector& x, std::vector& y, bool relative, ValueType const& precision); + + /*! + * Creates a helper from the given data, considering the same matrix as the given old helper + */ + SoundValueIterationHelper(SoundValueIterationHelper&& oldHelper, std::vector& x, std::vector& y, bool relative, ValueType const& precision); + + /*! + * Sets the currently known lower / upper bound + */ + void setLowerBound(ValueType const& value); + void setUpperBound(ValueType const& value); + + void setSolutionVector(); + + /*! + * Performs one iteration step with respect to the given optimization direction. + */ + void performIterationStep(OptimizationDirection const& dir, std::vector const& b); + + /*! + * Performs one iteration step, assuming that the row grouping of the initial matrix is trivial. + */ + void performIterationStep(std::vector const& b); + + /*! + * Checks for convergence and updates the known lower/upper bounds. + */ + bool checkConvergenceUpdateBounds(OptimizationDirection const& dir, storm::storage::BitVector const* relevantValues = nullptr); + + /*! + * Checks for convergence and updates the known lower/upper bounds, assuming that the row grouping of the initial matrix is trivial. + */ + bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr); + + /*! + * Checks whether the provided termination condition triggers termination + */ + bool checkCustomTerminationCondition(storm::solver::TerminationCondition const& condition); + + private: + + enum class InternalOptimizationDirection { + None, Minimize, Maximize + }; + + template + void performIterationStep(std::vector const& b); + + template + void performIterationStepUpdateDecisionValue(std::vector const& b); + + void multiplyRow(IndexType const& rowIndex, ValueType const& bi, ValueType& xi, ValueType& yi); + + template + bool checkConvergenceUpdateBounds(storm::storage::BitVector const* relevantValues = nullptr); + + bool checkConvergencePhase1(); + bool checkConvergencePhase2(storm::storage::BitVector const* relevantValues = nullptr); + + bool isPreciseEnough(ValueType const& xi, ValueType const& yi, ValueType const& lb, ValueType const& ub); + + template + bool preliminaryConvergenceCheck(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate); + + template + void updateLowerUpperBound(ValueType& lowerBoundCandidate, ValueType& upperBoundCandidate); + + template + void checkIfDecisionValueBlocks(); + + // Auxiliary helper functions to avoid case distinctions due to different optimization directions + template + inline bool better(ValueType const& val1, ValueType const& val2) { + return (dir == InternalOptimizationDirection::Maximize) ? val1 > val2 : val1 < val2; + } + template + inline ValueType& getPrimaryBound() { + return (dir == InternalOptimizationDirection::Maximize) ? upperBound : lowerBound; + } + template + inline bool& hasPrimaryBound() { + return (dir == InternalOptimizationDirection::Maximize) ? hasUpperBound : hasLowerBound; + } + template + inline ValueType& getSecondaryBound() { + return (dir == InternalOptimizationDirection::Maximize) ? lowerBound : upperBound; + } + template + inline uint64_t& getPrimaryIndex() { + return (dir == InternalOptimizationDirection::Maximize) ? maxIndex : minIndex; + } + template + inline uint64_t& getSecondaryIndex() { + return (dir == InternalOptimizationDirection::Maximize) ? minIndex : maxIndex; + } + + std::vector& x; + std::vector& y; + std::vector xTmp, yTmp; + + ValueType lowerBound, upperBound, decisionValue; + bool hasLowerBound, hasUpperBound, hasDecisionValue; + bool convergencePhase1; + bool decisionValueBlocks; + uint64_t firstIndexViolatingConvergence; + uint64_t minIndex, maxIndex; + + bool relative; + ValueType precision; + + IndexType numRows; + std::vector matrixValues; + std::vector matrixColumns; + std::vector rowIndications; + std::vector const* rowGroupIndices; + }; + + } + } +} + diff --git a/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h b/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h index 0ac38769d..4065ee265 100644 --- a/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h +++ b/src/storm/solver/stateelimination/DynamicStatePriorityQueue.h @@ -17,7 +17,7 @@ namespace storm { namespace stateelimination { struct PriorityComparator { - bool operator()(std::pair const& first, std::pair const& second) { + bool operator()(std::pair const& first, std::pair const& second) const { return (first.second < second.second) || (first.second == second.second && first.first < second.first) ; } }; diff --git a/src/storm/storage/BitVectorHashMap.cpp b/src/storm/storage/BitVectorHashMap.cpp index 7bfe1595e..652d4e99f 100644 --- a/src/storm/storage/BitVectorHashMap.cpp +++ b/src/storm/storage/BitVectorHashMap.cpp @@ -54,13 +54,6 @@ namespace storm { buckets = storm::storage::BitVector(bucketSize * (1ull << currentSize)); occupied = storm::storage::BitVector(1ull << currentSize); values = std::vector(1ull << currentSize); - -#ifndef NDEBUG - numberOfInsertions = 0; - numberOfInsertionProbingSteps = 0; - numberOfFinds = 0; - numberOfFindProbingSteps = 0; -#endif } template @@ -81,11 +74,7 @@ namespace storm { template void BitVectorHashMap::increaseSize() { ++currentSize; -#ifndef NDEBUG - STORM_LOG_TRACE("Increasing size of hash map from " << (1ull << (currentSize - 1)) << " to " << (1ull << currentSize) << ". Stats: " << numberOfFinds << " finds (avg. " << (numberOfFindProbingSteps / static_cast(numberOfFinds)) << " probing steps), " << numberOfInsertions << " insertions (avg. " << (numberOfInsertionProbingSteps / static_cast(numberOfInsertions)) << " probing steps)."); -#else STORM_LOG_TRACE("Increasing size of hash map from " << (1ull << (currentSize - 1)) << " to " << (1ull << currentSize) << "."); -#endif // Create new containers and swap them with the old ones. storm::storage::BitVector oldBuckets(bucketSize * (1ull << currentSize)); @@ -96,10 +85,12 @@ namespace storm { std::swap(oldValues, values); // Now iterate through the elements and reinsert them in the new storage. + uint64_t oldSize = numberOfElements; numberOfElements = 0; for (auto bucketIndex : oldOccupied) { findOrAddAndGetBucket(oldBuckets.get(bucketIndex * bucketSize, bucketSize), oldValues[bucketIndex]); } + STORM_LOG_ASSERT(oldSize == numberOfElements, "Size mismatch in rehashing. Size before was " << oldSize << " and new size is " << numberOfElements << "."); } template @@ -111,7 +102,7 @@ namespace storm { std::pair BitVectorHashMap::findOrAddAndGetBucket(storm::storage::BitVector const& key, ValueType const& value) { checkIncreaseSize(); - std::pair flagAndBucket = this->findBucketToInsert(key); + std::pair flagAndBucket = this->findBucket(key); if (flagAndBucket.first) { return std::make_pair(values[flagAndBucket.second], flagAndBucket.second); } else { @@ -168,38 +159,10 @@ namespace storm { template std::pair BitVectorHashMap::findBucket(storm::storage::BitVector const& key) const { -#ifndef NDEBUG - ++numberOfFinds; -#endif + STORM_LOG_ASSERT(key.size() == bucketSize, "Size of bit vector and size of buckets do not match"); uint64_t bucket = hasher(key) >> this->getCurrentShiftWidth(); while (isBucketOccupied(bucket)) { -#ifndef NDEBUG - ++numberOfFindProbingSteps; -#endif - if (buckets.matches(bucket * bucketSize, key)) { - return std::make_pair(true, bucket); - } - ++bucket; - if (bucket == (1ull << currentSize)) { - bucket = 0; - } - } - - return std::make_pair(false, bucket); - } - - template - std::pair BitVectorHashMap::findBucketToInsert(storm::storage::BitVector const& key) { -#ifndef NDEBUG - ++numberOfInsertions; -#endif - uint64_t bucket = hasher(key) >> this->getCurrentShiftWidth(); - - while (isBucketOccupied(bucket)) { -#ifndef NDEBUG - ++numberOfInsertionProbingSteps; -#endif if (buckets.matches(bucket * bucketSize, key)) { return std::make_pair(true, bucket); } diff --git a/src/storm/storage/BitVectorHashMap.h b/src/storm/storage/BitVectorHashMap.h index 38310aa4f..7484c9445 100644 --- a/src/storm/storage/BitVectorHashMap.h +++ b/src/storm/storage/BitVectorHashMap.h @@ -170,19 +170,6 @@ namespace storm { */ std::pair findBucket(storm::storage::BitVector const& key) const; - /*! - * Searches for the bucket into which the given key can be inserted. If no empty bucket can be found, the - * size of the underlying data structure is increased. - * - * @param key The key to search for. - * @param increaseStorage A flag indicating whether the storage should be increased if no bucket can be found. - * @return A tuple whose first component indicates whether the key is already contained in the map, whose - * second component indicates in which bucket the key is supposed to be stored and whose third component is - * an error flag indicating that the bucket could not be found (e.g. due to the restriction that the storage - * must not be increased). - */ - std::pair findBucketToInsert(storm::storage::BitVector const& key); - /*! * Inserts the given key-value pair without resizing the underlying storage. If that fails, this is * indicated by the return value. @@ -234,13 +221,6 @@ namespace storm { // Functor object that are used to perform the actual hashing. Hash hasher; -#ifndef NDEBUG - // Some performance metrics. - mutable uint64_t numberOfInsertions; - mutable uint64_t numberOfInsertionProbingSteps; - mutable uint64_t numberOfFinds; - mutable uint64_t numberOfFindProbingSteps; -#endif }; } diff --git a/src/storm/storage/MaximalEndComponentDecomposition.cpp b/src/storm/storage/MaximalEndComponentDecomposition.cpp index cd8b637e3..7cbf36fd7 100644 --- a/src/storm/storage/MaximalEndComponentDecomposition.cpp +++ b/src/storm/storage/MaximalEndComponentDecomposition.cpp @@ -80,7 +80,20 @@ namespace storm { endComponentStateSets.emplace_back(states.begin(), states.end(), true); } storm::storage::BitVector statesToCheck(numberOfStates); - + storm::storage::BitVector includedChoices; + if (choices) { + includedChoices = *choices; + } else if (states) { + includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount()); + for (auto state : *states) { + for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + includedChoices.set(choice, true); + } + } + } else { + includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true); + } + for (std::list::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) { StateBlock const& mec = *mecIterator; @@ -88,7 +101,7 @@ namespace storm { bool mecChanged = false; // Get an SCC decomposition of the current MEC candidate. - StronglyConnectedComponentDecomposition sccs(transitionMatrix, mec, true); + StronglyConnectedComponentDecomposition sccs(transitionMatrix, mec, includedChoices, true); // We need to do another iteration in case we have either more than once SCC or the SCC is smaller than // the MEC canditate itself. @@ -105,10 +118,16 @@ namespace storm { bool keepStateInMEC = false; for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) { + // If the choice is not part of our subsystem, skip it. if (choices && !choices->get(choice)) { continue; } + + // If the choice is not included any more, skip it. + if (!includedChoices.get(choice)) { + continue; + } bool choiceContainedInMEC = true; for (auto const& entry : transitionMatrix.getRow(choice)) { @@ -117,6 +136,7 @@ namespace storm { } if (!scc.containsState(entry.getColumn())) { + includedChoices.set(choice, false); choiceContainedInMEC = false; break; } @@ -125,7 +145,6 @@ namespace storm { // If there is at least one choice whose successor states are fully contained in the MEC, we can leave the state in the MEC. if (choiceContainedInMEC) { keepStateInMEC = true; - break; } } @@ -185,15 +204,7 @@ namespace storm { continue; } - bool choiceContained = true; - for (auto const& entry : transitionMatrix.getRow(choice)) { - if (!mecStateSet.containsState(entry.getColumn())) { - choiceContained = false; - break; - } - } - - if (choiceContained) { + if (includedChoices.get(choice)) { containedChoices.insert(choice); } } diff --git a/src/storm/storage/Scheduler.h b/src/storm/storage/Scheduler.h index b51e308b9..f3777cf55 100644 --- a/src/storm/storage/Scheduler.h +++ b/src/storm/storage/Scheduler.h @@ -44,10 +44,10 @@ namespace storm { void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0); /*! - * Sets the choice defined by the scheduler for the given model and memory state. + * Gets the choice defined by the scheduler for the given model and memory state. * - * @param state The state for which to set the choice. - * @param choice The choice to set for the given state. + * @param state The state for which to get the choice. + * @param memoryState the memory state which we consider. */ SchedulerChoice const& getChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0) const; diff --git a/src/storm/storage/SparseMatrix.cpp b/src/storm/storage/SparseMatrix.cpp index 36dd5724e..559902e77 100644 --- a/src/storm/storage/SparseMatrix.cpp +++ b/src/storm/storage/SparseMatrix.cpp @@ -579,6 +579,20 @@ namespace storm { return this->getRowGroupIndices()[group + 1] - this->getRowGroupIndices()[group]; } + template + typename SparseMatrix::index_type SparseMatrix::getSizeOfLargestRowGroup() const { + if (this->hasTrivialRowGrouping()) { + return 1; + } + index_type res = 0; + index_type previousGroupStart = 0; + for (auto const& i : rowGroupIndices.get()) { + res = std::max(res, i - previousGroupStart); + previousGroupStart = i; + } + return res; + } + template std::vector::index_type> const& SparseMatrix::getRowGroupIndices() const { // If there is no current row grouping, we need to create it. @@ -589,6 +603,16 @@ namespace storm { return rowGroupIndices.get(); } + template + std::vector::index_type> SparseMatrix::swapRowGroupIndices(std::vector&& newRowGrouping) { + std::vector result; + if (this->rowGroupIndices) { + result = std::move(rowGroupIndices.get()); + rowGroupIndices = std::move(newRowGrouping); + } + return result; + } + template void SparseMatrix::setRowGroupIndices(std::vector const& newRowGroupIndices) { trivialRowGrouping = false; @@ -946,6 +970,7 @@ namespace storm { // Copy over selected entries. rowGroupCount = 0; index_type rowCount = 0; + subEntries = 0; for (auto index : rowGroupConstraint) { if (!this->hasTrivialRowGrouping()) { matrixBuilder.newRowGroup(rowCount); @@ -961,6 +986,7 @@ namespace storm { matrixBuilder.addNextValue(rowCount, rowGroupCount, storm::utility::zero()); insertedDiagonalElement = true; } + ++subEntries; matrixBuilder.addNextValue(rowCount, columnBitsSetBeforeIndex[it->getColumn()], it->getValue()); } } @@ -1477,7 +1503,7 @@ namespace storm { multiplyWithVectorParallel(vector, tmpVector); result = std::move(tmpVector); } else { - tbb::parallel_for(tbb::blocked_range(0, result.size(), 10), TbbMultAddFunctor(columnsAndValues, rowIndications, vector, result, summand)); + tbb::parallel_for(tbb::blocked_range(0, result.size(), 100), TbbMultAddFunctor(columnsAndValues, rowIndications, vector, result, summand)); } } #endif @@ -1562,6 +1588,17 @@ namespace storm { template void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + if (dir == OptimizationDirection::Minimize) { + multiplyAndReduceForward>(rowGroupIndices, vector, summand, result, choices); + } else { + multiplyAndReduceForward>(rowGroupIndices, vector, summand, result, choices); + } + } + + template + template + void SparseMatrix::multiplyAndReduceForward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + Compare compare; auto elementIt = this->begin(); auto rowGroupIt = rowGroupIndices.begin(); auto rowIt = rowIndications.begin(); @@ -1574,11 +1611,13 @@ namespace storm { choiceIt = choices->begin(); } + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = 0; for (auto resultIt = result.begin(), resultIte = result.end(); resultIt != resultIte; ++resultIt, ++choiceIt, ++rowGroupIt) { ValueType currentValue = storm::utility::zero(); - if (choices) { - *choiceIt = 0; - } // Only multiply and reduce if there is at least one row in the group. if (*rowGroupIt < *(rowGroupIt + 1)) { @@ -1586,38 +1625,51 @@ namespace storm { currentValue = *summandIt; ++summandIt; } - + for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } + if (choices) { + selectedChoice = 0; + if (*choiceIt == 0) { + oldSelectedChoiceValue = currentValue; + } + } + ++rowIt; + ++currentRow; - for (; static_cast(std::distance(rowIndications.begin(), rowIt)) < *(rowGroupIt + 1); ++rowIt) { + for (; currentRow < *(rowGroupIt + 1); ++rowIt, ++currentRow) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = this->begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } + + if (choices && currentRow == *choiceIt + *rowGroupIt) { + oldSelectedChoiceValue = newValue; + } - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *rowGroupIt; + selectedChoice = currentRow - *rowGroupIt; } } if (summand) { ++summandIt; } } - } else if (choices) { - *choiceIt = 0; + + // Finally write value to target vector. + *resultIt = currentValue; + if (choices && compare(currentValue, oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } - - // Finally write value to target vector. - *resultIt = currentValue; } } - + #ifdef STORM_HAVE_CARL template<> void SparseMatrix::multiplyAndReduceForward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const { @@ -1627,6 +1679,17 @@ namespace storm { template void SparseMatrix::multiplyAndReduceBackward(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + if (dir == storm::OptimizationDirection::Minimize) { + multiplyAndReduceBackward>(rowGroupIndices, vector, summand, result, choices); + } else { + multiplyAndReduceBackward>(rowGroupIndices, vector, summand, result, choices); + } + } + + template + template + void SparseMatrix::multiplyAndReduceBackward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { + Compare compare; auto elementIt = this->end() - 1; auto rowGroupIt = rowGroupIndices.end() - 2; auto rowIt = rowIndications.end() - 2; @@ -1639,10 +1702,12 @@ namespace storm { choiceIt = choices->end() - 1; } + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = this->getRowCount() - 1; for (auto resultIt = result.end() - 1, resultIte = result.begin() - 1; resultIt != resultIte; --resultIt, --choiceIt, --rowGroupIt) { - if (choices) { - *choiceIt = 0; - } ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if there is at least one row in the group. @@ -1651,32 +1716,43 @@ namespace storm { currentValue = *summandIt; --summandIt; } - + for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) { currentValue += elementIt->getValue() * vector[elementIt->getColumn()]; } if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *rowGroupIt; + selectedChoice = currentRow - *rowGroupIt; + if (*choiceIt == selectedChoice) { + oldSelectedChoiceValue = currentValue; + } } --rowIt; + --currentRow; - for (uint64_t i = *rowGroupIt + 1, end = *(rowGroupIt + 1); i < end; --rowIt, ++i, --summandIt) { + for (uint64_t i = *rowGroupIt + 1, end = *(rowGroupIt + 1); i < end; --rowIt, --currentRow, ++i, --summandIt) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = this->begin() + *rowIt - 1; elementIt != elementIte; --elementIt) { newValue += elementIt->getValue() * vector[elementIt->getColumn()]; } - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (choices && currentRow == *choiceIt + *rowGroupIt) { + oldSelectedChoiceValue = newValue; + } + + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *rowGroupIt; + selectedChoice = currentRow - *rowGroupIt; } } } + + // Finally write value to target vector. + *resultIt = currentValue; + if (choices && compare(currentValue, oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } - - // Finally write value to target vector. - *resultIt = currentValue; } } @@ -1688,18 +1764,19 @@ namespace storm { #endif #ifdef STORM_HAVE_INTELTBB - template + template class TbbMultAddReduceFunctor { public: typedef typename storm::storage::SparseMatrix::index_type index_type; typedef typename storm::storage::SparseMatrix::value_type value_type; typedef typename storm::storage::SparseMatrix::const_iterator const_iterator; - TbbMultAddReduceFunctor(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector> const& columnsAndEntries, std::vector const& rowIndications, std::vector const& x, std::vector& result, std::vector const* summand, std::vector* choices) : dir(dir), rowGroupIndices(rowGroupIndices), columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand), choices(choices) { + TbbMultAddReduceFunctor(std::vector const& rowGroupIndices, std::vector> const& columnsAndEntries, std::vector const& rowIndications, std::vector const& x, std::vector& result, std::vector const* summand, std::vector* choices) : rowGroupIndices(rowGroupIndices), columnsAndEntries(columnsAndEntries), rowIndications(rowIndications), x(x), result(result), summand(summand), choices(choices) { // Intentionally left empty. } void operator()(tbb::blocked_range const& range) const { + auto groupIt = rowGroupIndices.begin() + range.begin(); auto groupIte = rowGroupIndices.begin() + range.end(); @@ -1716,11 +1793,12 @@ namespace storm { auto resultIt = result.begin() + range.begin(); + // Variables for correctly tracking choices (only update if new choice is strictly better). + ValueType oldSelectedChoiceValue; + uint64_t selectedChoice; + + uint64_t currentRow = *groupIt; for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) { - if (choices) { - *choiceIt = 0; - } - ValueType currentValue = storm::utility::zero(); // Only multiply and reduce if there is at least one row in the group. @@ -1734,30 +1812,45 @@ namespace storm { currentValue += elementIt->getValue() * x[elementIt->getColumn()]; } + if (choices) { + selectedChoice = 0; + if (*choiceIt == 0) { + oldSelectedChoiceValue = currentValue; + } + } + ++rowIt; + ++currentRow; - for (; static_cast(std::distance(rowIndications.begin(), rowIt)) < *(groupIt + 1); ++rowIt, ++summandIt) { + for (; currentRow < *(groupIt + 1); ++rowIt, ++currentRow, ++summandIt) { ValueType newValue = summand ? *summandIt : storm::utility::zero(); for (auto elementIte = columnsAndEntries.begin() + *(rowIt + 1); elementIt != elementIte; ++elementIt) { newValue += elementIt->getValue() * x[elementIt->getColumn()]; } - if ((dir == OptimizationDirection::Minimize && newValue < currentValue) || (dir == OptimizationDirection::Maximize && newValue > currentValue)) { + if (choices && currentRow == *choiceIt + *groupIt) { + oldSelectedChoiceValue = newValue; + } + + if (compare(newValue, currentValue)) { currentValue = newValue; if (choices) { - *choiceIt = std::distance(rowIndications.begin(), rowIt) - *groupIt; + selectedChoice = currentRow - *groupIt; } } } + + // Finally write value to target vector. + *resultIt = currentValue; + if (choices && compare(currentValue, oldSelectedChoiceValue)) { + *choiceIt = selectedChoice; + } } - - // Finally write value to target vector. - *resultIt = currentValue; } } private: - OptimizationDirection dir; + Compare compare; std::vector const& rowGroupIndices; std::vector> const& columnsAndEntries; std::vector const& rowIndications; @@ -1769,7 +1862,11 @@ namespace storm { template void SparseMatrix::multiplyAndReduceParallel(OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const { - tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 10), TbbMultAddReduceFunctor(dir, rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + if (dir == storm::OptimizationDirection::Minimize) { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + } else { + tbb::parallel_for(tbb::blocked_range(0, rowGroupIndices.size() - 1, 100), TbbMultAddReduceFunctor>(rowGroupIndices, columnsAndValues, rowIndications, vector, result, summand, choices)); + } } #ifdef STORM_HAVE_CARL diff --git a/src/storm/storage/SparseMatrix.h b/src/storm/storage/SparseMatrix.h index e07389e5a..f742a7c49 100644 --- a/src/storm/storage/SparseMatrix.h +++ b/src/storm/storage/SparseMatrix.h @@ -27,7 +27,7 @@ namespace storm { } namespace solver { template - class TopologicalValueIterationMinMaxLinearEquationSolver; + class TopologicalCudaValueIterationMinMaxLinearEquationSolver; } } @@ -327,7 +327,7 @@ namespace storm { friend class storm::adapters::GmmxxAdapter; friend class storm::adapters::EigenAdapter; friend class storm::adapters::StormAdapter; - friend class storm::solver::TopologicalValueIterationMinMaxLinearEquationSolver; + friend class storm::solver::TopologicalCudaValueIterationMinMaxLinearEquationSolver; friend class SparseMatrixBuilder; typedef SparseMatrixIndexType index_type; @@ -567,6 +567,11 @@ namespace storm { */ index_type getRowGroupSize(index_type group) const; + /*! + * Returns the size of the largest row group of the matrix + */ + index_type getSizeOfLargestRowGroup() const; + /*! * Returns the grouping of rows of this matrix. * @@ -574,6 +579,13 @@ namespace storm { */ std::vector const& getRowGroupIndices() const; + /*! + * Swaps the grouping of rows of this matrix. + * + * @return The old grouping of rows of this matrix. + */ + std::vector swapRowGroupIndices(std::vector&& newRowGrouping); + /*! * Sets the row grouping to the given one. * @note It is assumed that the new row grouping is non-trivial. @@ -681,7 +693,7 @@ namespace storm { * * @param useGroups If set to true, the constraint for the rows is interpreted as selecting whole row groups. * If it is not set, the row constraint is interpreted over the actual rows. Note that empty row groups will - * be dropped altogether. That is, if no row of a row group is selected *or* the row group is alread empty, + * be dropped altogether. That is, if no row of a row group is selected *or* the row group is already empty, * the submatrix will not have this row group. * @param constraint A bit vector indicating which rows to keep. * @param columnConstraint A bit vector indicating which columns to keep. @@ -744,7 +756,7 @@ namespace storm { /*! * Selects the rows that are given by the sequence of row indices, allowing to select rows arbitrarily often and with an arbitrary order - * The resulting matrix will have a trivial row grouping + * The resulting matrix will have a trivial row grouping. * * @param rowIndexSequence the sequence of row indices which specifies, which rows are contained in the new matrix * @param insertDiagonalEntries If set to true, the resulting matrix will have zero entries in column i for @@ -839,15 +851,24 @@ namespace storm { * @param vector The vector with which to multiply the matrix. * @param summand If given, this summand will be added to the result of the multiplication. * @param result The vector that is supposed to hold the result of the multiplication after the operation. - * @param choices If given, the choices made in the reduction process will be written to this vector. + * @param choices If given, the choices made in the reduction process will be written to this vector. Note + * that if the direction is maximize, the choice for a row group is only updated if the value obtained with + * the 'new' choice has a value strictly better (wrt. to the optimization direction) value. * @return The resulting vector the content of the given result vector. */ void multiplyAndReduce(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const; void multiplyAndReduceForward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; + template + void multiplyAndReduceForward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* summand, std::vector& result, std::vector* choices) const; + void multiplyAndReduceBackward(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; + template + void multiplyAndReduceBackward(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; #ifdef STORM_HAVE_INTELTBB void multiplyAndReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; + template + void multiplyAndReduceParallel(std::vector const& rowGroupIndices, std::vector const& vector, std::vector const* b, std::vector& result, std::vector* choices) const; #endif /*! diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp index af98331a7..6ab3e31f6 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.cpp +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.cpp @@ -2,6 +2,9 @@ #include "storm/models/sparse/Model.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/adapters/RationalFunctionAdapter.h" +#include "storm/utility/macros.h" + +#include "storm/exceptions/UnexpectedException.h" namespace storm { namespace storage { @@ -20,30 +23,40 @@ namespace storm { template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::sparse::Model const& model, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) { storm::storage::BitVector subsystem(model.getNumberOfStates(), block.begin(), block.end()); - performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(model.getTransitionMatrix(), &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } template template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::sparse::Model const& model, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) { - performSccDecomposition(model.getTransitionMatrix(), subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(model.getTransitionMatrix(), &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs, bool onlyBottomSccs) { storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end()); - performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); } + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, storm::storage::BitVector const& choices, bool dropNaiveSccs, bool onlyBottomSccs) { + storm::storage::BitVector subsystem(transitionMatrix.getRowGroupCount(), block.begin(), block.end()); + performSccDecomposition(transitionMatrix, &subsystem, &choices, dropNaiveSccs, onlyBottomSccs); + } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, bool dropNaiveSccs, bool onlyBottomSccs) { - performSccDecomposition(transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(transitionMatrix, nullptr, nullptr, dropNaiveSccs, onlyBottomSccs); } template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) { - performSccDecomposition(transitionMatrix, subsystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(transitionMatrix, &subsystem, nullptr, dropNaiveSccs, onlyBottomSccs); + } + + template + StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& choices, bool dropNaiveSccs, bool onlyBottomSccs) { + performSccDecomposition(transitionMatrix, &subsystem, &choices, dropNaiveSccs, onlyBottomSccs); } template @@ -69,7 +82,10 @@ namespace storm { } template - void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs) { + void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, bool dropNaiveSccs, bool onlyBottomSccs) { + + STORM_LOG_ASSERT(!choices || subsystem, "Expecting subsystem if choices are given."); + uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount(); // Set up the environment of the algorithm. @@ -91,16 +107,30 @@ namespace storm { // Start the search for SCCs from every state in the block. uint_fast64_t currentIndex = 0; - for (auto state : subsystem) { - if (!hasPreorderNumber.get(state)) { - performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount); + if (subsystem) { + for (auto state : *subsystem) { + if (!hasPreorderNumber.get(state)) { + performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, choices, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount); + } + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + if (!hasPreorderNumber.get(state)) { + performSccDecompositionGCM(transitionMatrix, state, statesWithSelfLoop, subsystem, choices, currentIndex, hasPreorderNumber, preorderNumbers, s, p, stateHasScc, stateToSccMapping, sccCount); + } } } // After we obtained the state-to-SCC mapping, we build the actual blocks. this->blocks.resize(sccCount); - for (auto state : subsystem) { - this->blocks[stateToSccMapping[state]].insert(state); + if (subsystem) { + for (auto state : *subsystem) { + this->blocks[stateToSccMapping[state]].insert(state); + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + this->blocks[stateToSccMapping[state]].insert(state); + } } // Now flag all trivial SCCs as such. @@ -129,13 +159,34 @@ namespace storm { // If requested, we need to drop all non-bottom SCCs. if (onlyBottomSccs) { - for (uint_fast64_t state = 0; state < numberOfStates; ++state) { - // If the block of the state is already known to be dropped, we don't need to check the transitions. - if (!blocksToDrop.get(stateToSccMapping[state])) { - for (typename storm::storage::SparseMatrix::const_iterator successorIt = transitionMatrix.getRowGroup(state).begin(), successorIte = transitionMatrix.getRowGroup(state).end(); successorIt != successorIte; ++successorIt) { - if (subsystem.get(successorIt->getColumn()) && stateToSccMapping[state] != stateToSccMapping[successorIt->getColumn()]) { - blocksToDrop.set(stateToSccMapping[state]); - break; + if (subsystem) { + for (uint64_t state : *subsystem) { + // If the block of the state is already known to be dropped, we don't need to check the transitions. + if (!blocksToDrop.get(stateToSccMapping[state])) { + for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row != endRow; ++row) { + if (choices && !choices->get(row)) { + continue; + } + for (auto const& entry : transitionMatrix.getRow(row)) { + if (subsystem->get(entry.getColumn()) && stateToSccMapping[state] != stateToSccMapping[entry.getColumn()]) { + blocksToDrop.set(stateToSccMapping[state]); + break; + } + } + } + } + } + } else { + for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) { + // If the block of the state is already known to be dropped, we don't need to check the transitions. + if (!blocksToDrop.get(stateToSccMapping[state])) { + for (uint64_t row = transitionMatrix.getRowGroupIndices()[state], endRow = transitionMatrix.getRowGroupIndices()[state + 1]; row != endRow; ++row) { + for (auto const& entry : transitionMatrix.getRow(row)) { + if (stateToSccMapping[state] != stateToSccMapping[entry.getColumn()]) { + blocksToDrop.set(stateToSccMapping[state]); + break; + } + } } } } @@ -160,15 +211,11 @@ namespace storm { template template void StronglyConnectedComponentDecomposition::performSccDecomposition(storm::models::sparse::Model const& model, bool dropNaiveSccs, bool onlyBottomSccs) { - // Prepare a block that contains all states for a call to the other overload of this function. - storm::storage::BitVector fullSystem(model.getNumberOfStates(), true); - - // Call the overloaded function. - performSccDecomposition(model.getTransitionMatrix(), fullSystem, dropNaiveSccs, onlyBottomSccs); + performSccDecomposition(model.getTransitionMatrix(), nullptr, nullptr, dropNaiveSccs, onlyBottomSccs); } template - void StronglyConnectedComponentDecomposition::performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount) { + void StronglyConnectedComponentDecomposition::performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount) { // Prepare the stack used for turning the recursive procedure into an iterative one. std::vector recursionStateStack; @@ -187,20 +234,26 @@ namespace storm { s.push_back(currentState); p.push_back(currentState); - for (auto const& successor : transitionMatrix.getRowGroup(currentState)) { - if (subsystem.get(successor.getColumn()) && successor.getValue() != storm::utility::zero()) { - if (currentState == successor.getColumn()) { - statesWithSelfLoop.set(currentState); - } - - if (!hasPreorderNumber.get(successor.getColumn())) { - // In this case, we must recursively visit the successor. We therefore push the state - // onto the recursion stack. - recursionStateStack.push_back(successor.getColumn()); - } else { - if (!stateHasScc.get(successor.getColumn())) { - while (preorderNumbers[p.back()] > preorderNumbers[successor.getColumn()]) { - p.pop_back(); + for (uint64_t row = transitionMatrix.getRowGroupIndices()[currentState], rowEnd = transitionMatrix.getRowGroupIndices()[currentState + 1]; row != rowEnd; ++row) { + if (choices && !choices->get(row)) { + continue; + } + + for (auto const& successor : transitionMatrix.getRow(row)) { + if ((!subsystem || subsystem->get(successor.getColumn())) && successor.getValue() != storm::utility::zero()) { + if (currentState == successor.getColumn()) { + statesWithSelfLoop.set(currentState); + } + + if (!hasPreorderNumber.get(successor.getColumn())) { + // In this case, we must recursively visit the successor. We therefore push the state + // onto the recursion stack. + recursionStateStack.push_back(successor.getColumn()); + } else { + if (!stateHasScc.get(successor.getColumn())) { + while (preorderNumbers[p.back()] > preorderNumbers[successor.getColumn()]) { + p.pop_back(); + } } } } @@ -226,6 +279,91 @@ namespace storm { } } + template + void StronglyConnectedComponentDecomposition::sortTopologically(storm::storage::SparseMatrix const& transitions, uint64_t* longestChainSize) { + + // Get a mapping from state to the corresponding scc + STORM_LOG_THROW(this->size() < std::numeric_limits::max(), storm::exceptions::UnexpectedException, "The number of SCCs is too large."); + std::vector sccIndices(transitions.getRowGroupCount(), std::numeric_limits::max()); + uint32_t sccIndex = 0; + for (auto const& scc : *this) { + for (auto const& state : scc) { + sccIndices[state] = sccIndex; + } + ++sccIndex; + } + + // Prepare the resulting set of sorted sccs + std::vector sortedSCCs; + sortedSCCs.reserve(this->size()); + + // Find a topological sort via DFS. + storm::storage::BitVector unsortedSCCs(this->size(), true); + std::vector sccStack, chainSizes; + if (longestChainSize != nullptr) { + chainSizes.resize(this->size(), 1u); + *longestChainSize = 0; + } + uint32_t const token = std::numeric_limits::max(); + std::set successorSCCs; + + for (uint32_t firstUnsortedScc = 0; firstUnsortedScc < unsortedSCCs.size(); firstUnsortedScc = unsortedSCCs.getNextSetIndex(firstUnsortedScc + 1)) { + + sccStack.push_back(firstUnsortedScc); + while (!sccStack.empty()) { + uint32_t currentSccIndex = sccStack.back(); + if (currentSccIndex != token) { + // Check whether the SCC is still unprocessed + if (unsortedSCCs.get(currentSccIndex)) { + // Explore the successors of the scc. + storm::storage::StronglyConnectedComponent const& currentScc = this->getBlock(currentSccIndex); + // We first push a token on the stack in order to recognize later when all successors of this SCC have been explored already. + sccStack.push_back(token); + // Now add all successors that are not already sorted. + // Successors should only be added once, so we first prepare a set of them and add them afterwards. + successorSCCs.clear(); + for (auto const& state : currentScc) { + for (auto const& entry : transitions.getRowGroup(state)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex && unsortedSCCs.get(successorSCC)) { + successorSCCs.insert(successorSCC); + } + } + } + sccStack.insert(sccStack.end(), successorSCCs.begin(), successorSCCs.end()); + + } + } else { + // all successors of the current scc have already been explored. + sccStack.pop_back(); // pop the token + + currentSccIndex = sccStack.back(); + storm::storage::StronglyConnectedComponent& scc = this->getBlock(currentSccIndex); + + // Compute the longest chain size for this scc + if (longestChainSize != nullptr) { + uint32_t& currentChainSize = chainSizes[currentSccIndex]; + for (auto const& state : scc) { + for (auto const& entry : transitions.getRowGroup(state)) { + auto const& successorSCC = sccIndices[entry.getColumn()]; + if (successorSCC != currentSccIndex) { + currentChainSize = std::max(currentChainSize, chainSizes[successorSCC] + 1); + } + } + } + *longestChainSize = std::max(*longestChainSize, currentChainSize); + } + + unsortedSCCs.set(currentSccIndex, false); + sccStack.pop_back(); // pop the current scc index + sortedSCCs.push_back(std::move(scc)); + } + } + } + this->blocks = std::move(sortedSCCs); + } + + // Explicitly instantiate the SCC decomposition. template class StronglyConnectedComponentDecomposition; template StronglyConnectedComponentDecomposition::StronglyConnectedComponentDecomposition(storm::models::sparse::Model const& model, bool dropNaiveSccs, bool onlyBottomSccs); diff --git a/src/storm/storage/StronglyConnectedComponentDecomposition.h b/src/storm/storage/StronglyConnectedComponentDecomposition.h index 20552a87b..7d244b914 100644 --- a/src/storm/storage/StronglyConnectedComponentDecomposition.h +++ b/src/storm/storage/StronglyConnectedComponentDecomposition.h @@ -78,7 +78,21 @@ namespace storm { * leaving the SCC), are kept. */ StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, bool dropNaiveSccs = false, bool onlyBottomSccs = false); - + + /* + * Creates an SCC decomposition of the given subsystem in the given system (whose transition relation is + * given by a sparse matrix). + * + * @param transitionMatrix The transition matrix of the system to decompose. + * @param block The block to decompose into SCCs. + * @param choices A bit vector indicating which choices of the states are contained in the subsystem. + * @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state + * without a self-loop) are to be kept in the decomposition. + * @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of + * leaving the SCC), are kept. + */ + StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, StateBlock const& block, storm::storage::BitVector const& choices, bool dropNaiveSccs = false, bool onlyBottomSccs = false); + /* * Creates an SCC decomposition of the given system (whose transition relation is given by a sparse matrix). * @@ -103,6 +117,20 @@ namespace storm { */ StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs = false, bool onlyBottomSccs = false); + /* + * Creates an SCC decomposition of the given subsystem in the given system (whose transition relation is + * given by a sparse matrix). + * + * @param transitionMatrix The transition matrix of the system to decompose. + * @param subsystem A bit vector indicating which subsystem to consider for the decomposition into SCCs. + * @param choices A bit vector indicating which choices of the states are contained in the subsystem. + * @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state + * without a self-loop) are to be kept in the decomposition. + * @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of + * leaving the SCC), are kept. + */ + StronglyConnectedComponentDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, storm::storage::BitVector const& choices, bool dropNaiveSccs = false, bool onlyBottomSccs = false); + /*! * Creates an SCC decomposition by copying the given SCC decomposition. * @@ -131,6 +159,14 @@ namespace storm { */ StronglyConnectedComponentDecomposition& operator=(StronglyConnectedComponentDecomposition&& other); + + /*! + * Sorts the SCCs topologically: The ith block can only reach states in block j const& transitions, uint64_t* longestChainSize = nullptr); + private: /*! * Performs the SCC decomposition of the given model. As a side-effect this fills the vector of @@ -150,13 +186,14 @@ namespace storm { * the vector of blocks of the decomposition. * * @param transitionMatrix The transition matrix of the system to decompose. - * @param subsystem A bit vector indicating which subsystem to consider for the decomposition into SCCs. + * @param subsystem An optional bit vector indicating which subsystem to consider. + * @param choices An optional bit vector indicating which choices belong to the subsystem. * @param dropNaiveSccs A flag that indicates whether trivial SCCs (i.e. SCCs consisting of just one state * without a self-loop) are to be kept in the decomposition. * @param onlyBottomSccs If set to true, only bottom SCCs, i.e. SCCs in which all states have no way of * leaving the SCC), are kept. */ - void performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& subsystem, bool dropNaiveSccs, bool onlyBottomSccs); + void performSccDecomposition(storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, bool dropNaiveSccs, bool onlyBottomSccs); /*! * Uses the algorithm by Gabow/Cheriyan/Mehlhorn ("Path-based strongly connected component algorithm") to @@ -167,7 +204,8 @@ namespace storm { * @param startState The starting state for the search of Tarjan's algorithm. * @param statesWithSelfLoop A bit vector that is to be filled with all states that have a self-loop. This * is later needed for identification of the naive SCCs. - * @param subsystem The subsystem to search. + * @param subsystem An optional bit vector indicating which subsystem to consider. + * @param choices An optional bit vector indicating which choices belong to the subsystem. * @param currentIndex The next free index that can be assigned to states. * @param hasPreorderNumber A bit that is used to keep track of the states that already have a preorder number. * @param preorderNumbers A vector storing the preorder number for each state. @@ -179,7 +217,7 @@ namespace storm { * @param sccCount The number of SCCs that have been computed. As a side effect of this function, this count * is increased. */ - void performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const& subsystem, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount); + void performSccDecompositionGCM(storm::storage::SparseMatrix const& transitionMatrix, uint_fast64_t startState, storm::storage::BitVector& statesWithSelfLoop, storm::storage::BitVector const* subsystem, storm::storage::BitVector const* choices, uint_fast64_t& currentIndex, storm::storage::BitVector& hasPreorderNumber, std::vector& preorderNumbers, std::vector& s, std::vector& p, storm::storage::BitVector& stateHasScc, std::vector& stateToSccMapping, uint_fast64_t& sccCount); }; } } diff --git a/src/storm/storage/SymbolicModelDescription.cpp b/src/storm/storage/SymbolicModelDescription.cpp index b08166125..9a7bc1388 100644 --- a/src/storm/storage/SymbolicModelDescription.cpp +++ b/src/storm/storage/SymbolicModelDescription.cpp @@ -5,6 +5,7 @@ #include "storm/utility/jani.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" #include "storm/storage/jani/Automaton.h" @@ -124,19 +125,19 @@ namespace storm { return *this; } if (this->isPrismProgram()) { - return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal)); + return SymbolicModelDescription(this->asPrismProgram().toJani(makeVariablesGlobal, "")); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format."); } } - std::pair> SymbolicModelDescription::toJaniWithLabelRenaming(bool makeVariablesGlobal) const { + std::pair> SymbolicModelDescription::toJani(std::vector const& properties, bool makeVariablesGlobal) const { if (this->isJaniModel()) { - return std::make_pair(*this, std::map()); + return std::make_pair(*this, std::vector()); } if (this->isPrismProgram()) { - auto modelAndRenaming = this->asPrismProgram().toJaniWithLabelRenaming(makeVariablesGlobal); - return std::make_pair(SymbolicModelDescription(modelAndRenaming.first), modelAndRenaming.second); + auto modelProperties = this->asPrismProgram().toJani(properties, makeVariablesGlobal, ""); + return std::make_pair(SymbolicModelDescription(modelProperties.first), modelProperties.second); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Cannot transform model description to the JANI format."); } @@ -144,21 +145,15 @@ namespace storm { SymbolicModelDescription SymbolicModelDescription::preprocess(std::string const& constantDefinitionString) const { std::map substitution = parseConstantDefinitions(constantDefinitionString); - if (this->isJaniModel()) { - storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(substitution).substituteConstants(); - return SymbolicModelDescription(preparedModel); - } else if (this->isPrismProgram()) { - return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(substitution).substituteConstants()); - } - return *this; + return preprocess(substitution); } SymbolicModelDescription SymbolicModelDescription::preprocess(std::map const& constantDefinitions) const { if (this->isJaniModel()) { - storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(constantDefinitions).substituteConstants(); + storm::jani::Model preparedModel = this->asJaniModel().defineUndefinedConstants(constantDefinitions).substituteConstantsFunctions(); return SymbolicModelDescription(preparedModel); } else if (this->isPrismProgram()) { - return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(constantDefinitions).substituteConstants()); + return SymbolicModelDescription(this->asPrismProgram().defineUndefinedConstants(constantDefinitions).substituteConstantsFormulas()); } return *this; } @@ -179,6 +174,30 @@ namespace storm { } } + bool SymbolicModelDescription::hasUndefinedConstants() const { + if (this->isPrismProgram()) { + return this->asPrismProgram().hasUndefinedConstants(); + } else { + return this->asJaniModel().hasUndefinedConstants(); + } + } + + std::vector SymbolicModelDescription::getUndefinedConstants() const { + std::vector result; + if (this->isPrismProgram()) { + std::vector> constants = this->asPrismProgram().getUndefinedConstants(); + for (auto const& constant : constants) { + result.emplace_back(constant.get().getExpressionVariable()); + } + } else { + std::vector> constants = this->asJaniModel().getUndefinedConstants(); + for (auto const& constant : constants) { + result.emplace_back(constant.get().getExpressionVariable()); + } + } + return result; + } + std::ostream& operator<<(std::ostream& out, SymbolicModelDescription const& model) { if (model.isPrismProgram()) { out << model.asPrismProgram(); diff --git a/src/storm/storage/SymbolicModelDescription.h b/src/storm/storage/SymbolicModelDescription.h index 137f1a7d4..a22e3afd6 100644 --- a/src/storm/storage/SymbolicModelDescription.h +++ b/src/storm/storage/SymbolicModelDescription.h @@ -39,7 +39,16 @@ namespace storm { std::vector getParameterNames() const; SymbolicModelDescription toJani(bool makeVariablesGlobal = true) const; - std::pair> toJaniWithLabelRenaming(bool makeVariablesGlobal = true) const; + + /*! + * Ensures that this model is a JANI model by, e.g., converting prism to jani. + * If labels or reward models had to be converted during conversion, the renamings are applied to the given properties + * + * @return The jani model of this and either the new set of properties or an empty vector if no renamings were necessary + * + * @note The returned property vector might be empty in case no renaming is necessary. + */ + std::pair> toJani(std::vector const& properties, bool makeVariablesGlobal) const; SymbolicModelDescription preprocess(std::string const& constantDefinitionString = "") const; SymbolicModelDescription preprocess(std::map const& constantDefinitions) const; @@ -47,6 +56,8 @@ namespace storm { std::map parseConstantDefinitions(std::string const& constantDefinitionString) const; void requireNoUndefinedConstants() const; + bool hasUndefinedConstants() const; + std::vector getUndefinedConstants() const; private: boost::optional> modelDescription; diff --git a/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp b/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp index 2a73744cf..6cbd57f09 100644 --- a/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp +++ b/src/storm/storage/bisimulation/DeterministicModelBisimulationDecomposition.cpp @@ -419,7 +419,7 @@ namespace storm { // the sorting is over. Otherwise, this interferes with the data used in the sorting process. storm::storage::sparse::state_type originalBlockIndex = block.getBeginIndex(); auto split = this->partition.splitBlock(block, - [&weakStateLabels,&block,originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { + [&weakStateLabels,originalBlockIndex,this] (storm::storage::sparse::state_type state1, storm::storage::sparse::state_type state2) { return weakStateLabels[this->partition.getPosition(state1) - originalBlockIndex] < weakStateLabels[this->partition.getPosition(state2) - originalBlockIndex]; }, [this, &splitterQueue, &block] (bisimulation::Block& newBlock) { diff --git a/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp b/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp index 473ae556a..019ec40c2 100644 --- a/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp +++ b/src/storm/storage/bisimulation/NondeterministicModelBisimulationDecomposition.cpp @@ -367,7 +367,7 @@ namespace storm { bool result = quotientDistributionsLess(state1, state2); return result; }, - [this, &block, &splitterQueue, &newBlocks] (Block& newBlock) { + [&newBlocks] (Block& newBlock) { newBlocks.push_back(&newBlock); }); diff --git a/src/storm/storage/dd/Add.cpp b/src/storm/storage/dd/Add.cpp index 9e91b2123..7f1cb1517 100644 --- a/src/storm/storage/dd/Add.cpp +++ b/src/storm/storage/dd/Add.cpp @@ -9,6 +9,7 @@ #include "storm/storage/dd/Odd.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" @@ -703,15 +704,18 @@ namespace storm { } // Create the canonical row group sizes and build the matrix. - return toMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd); + return toLabeledMatrix(rowMetaVariables, columnMetaVariables, groupMetaVariables, rowOdd, columnOdd).matrix; } template - storm::storage::SparseMatrix Add::toMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { + typename Add::MatrixAndLabeling Add::toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, std::vector> const& labelMetaVariables) const { std::vector ddRowVariableIndices; std::vector ddColumnVariableIndices; std::vector ddGroupVariableIndices; + std::vector ddLabelVariableIndicesVector; std::set rowAndColumnMetaVariables; + bool buildLabeling = !labelMetaVariables.empty(); + MatrixAndLabeling result; for (auto const& variable : rowMetaVariables) { DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); @@ -736,7 +740,27 @@ namespace storm { } } std::sort(ddGroupVariableIndices.begin(), ddGroupVariableIndices.end()); - + if (buildLabeling) { + for (auto const& labelMetaVariableSet : labelMetaVariables) { + std::set ddLabelVariableIndicesSet; + for (auto const& variable : labelMetaVariableSet) { + DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); + for (auto const& ddVariable : metaVariable.getDdVariables()) { + ddLabelVariableIndicesSet.insert(ddVariable.getIndex()); + } + } + + ddLabelVariableIndicesVector.emplace_back(ddGroupVariableIndices.size()); + uint64_t position = 0; + for (auto const& index : ddGroupVariableIndices) { + if (ddLabelVariableIndicesSet.find(index) != ddLabelVariableIndicesSet.end()) { + ddLabelVariableIndicesVector.back().set(position); + } + ++position; + } + } + } + Bdd columnVariableCube = Bdd::getCube(this->getDdManager(), columnMetaVariables); // Start by computing the offsets (in terms of rows) for each row group. @@ -760,12 +784,27 @@ namespace storm { groups.push_back(Add(this->getDdManager(), internalAdd, rowAndColumnMetaVariables)); } + // Create the group labelings if requested. + std::vector> groupLabelings; + if (buildLabeling) { + for (auto const& ddLabelVariableIndices : ddLabelVariableIndicesVector) { + groupLabelings.emplace_back(internalAdd.decodeGroupLabels(ddGroupVariableIndices, ddLabelVariableIndices)); + STORM_LOG_ASSERT(groupLabelings.back().size() == groups.size(), "Mismatching label sizes."); + } + } + // Create the actual storage for the non-zero entries. std::vector> columnsAndValues(this->getNonZeroCount()); // Now compute the indices at which the individual rows start. std::vector rowIndications(rowGroupIndices.back() + 1); + if (buildLabeling) { + for (uint64_t i = 0; i < labelMetaVariables.size(); ++i) { + result.labelings.emplace_back(rowGroupIndices.back()); + } + } + std::vector> statesWithGroupEnabled(groups.size()); InternalAdd stateToRowGroupCount = this->getDdManager().template getAddZero(); for (uint_fast64_t i = 0; i < groups.size(); ++i) { @@ -778,6 +817,12 @@ namespace storm { } statesWithGroupEnabled[i] = groupNotZero.existsAbstract(columnMetaVariables).template toAdd(); + if (buildLabeling) { + for (uint64_t j = 0; j < labelMetaVariables.size(); ++j) { + uint64_t currentLabel = groupLabelings[j][i]; + statesWithGroupEnabled[i].forEach(rowOdd, ddRowVariableIndices, [currentLabel, &rowGroupIndices, &result, j] (uint64_t const& offset, uint_fast64_t const& value) { result.labelings[j][rowGroupIndices[offset]] = currentLabel; }); + } + } statesWithGroupEnabled[i].composeWithExplicitVector(rowOdd, ddRowVariableIndices, rowGroupIndices, std::plus()); } @@ -811,10 +856,12 @@ namespace storm { rowIndications[i] = rowIndications[i - 1]; } rowIndications[0] = 0; - - return storm::storage::SparseMatrix(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); - } + // Move-construct matrix and return. + result.matrix = storm::storage::SparseMatrix(columnOdd.getTotalOffset(), std::move(rowIndications), std::move(columnsAndValues), std::move(rowGroupIndices)); + return result; + } + template std::pair, std::vector> Add::toMatrixVector(storm::dd::Add const& vector, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const { std::set rowMetaVariables; diff --git a/src/storm/storage/dd/Add.h b/src/storm/storage/dd/Add.h index 1a4a811d5..94a512482 100644 --- a/src/storm/storage/dd/Add.h +++ b/src/storm/storage/dd/Add.h @@ -640,6 +640,38 @@ namespace storm { */ storm::storage::SparseMatrix toMatrix(std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; + /*! + * Converts the ADD to a row-grouped (sparse) matrix. The given offset-labeled DDs are used to determine the + * correct row and column, respectively, for each entry. If requested, it builds a labeling of the rows + * that is derived from the group variable encodings. Note: this function assumes that the meta variables + * used to distinguish different row groups are at the very top of the ADD. + * + * @param rowMetaVariables The meta variables that encode the rows of the matrix. + * @param columnMetaVariables The meta variables that encode the columns of the matrix. + * @param groupMetaVariables The meta variables that are used to distinguish different row groups. + * @param rowOdd The ODD used for determining the correct row. + * @param columnOdd The ODD used for determining the correct column. + * @param buildLabeling If false, no labeling vector is built. + * @return The matrix that is represented by this ADD and a vector corresponding to row labeling + * (if requested). + */ + struct MatrixAndLabeling { + MatrixAndLabeling() = default; + + MatrixAndLabeling(storm::storage::SparseMatrix const& matrix) : matrix(matrix) { + // Intentionally left empty. + } + + MatrixAndLabeling(storm::storage::SparseMatrix&& matrix) : matrix(std::move(matrix)) { + // Intentionally left empty. + } + + storm::storage::SparseMatrix matrix; + std::vector> labelings; + }; + + MatrixAndLabeling toLabeledMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd, std::vector> const& labelMetaVariables = std::vector>()) const; + /*! * Converts the ADD to a row-grouped (sparse) matrix and the given vector to a row-grouped vector. * The given offset-labeled DDs are used to determine the correct row and column, respectively, for each @@ -721,22 +753,6 @@ namespace storm { */ operator InternalAdd() const; - /*! - * Converts the ADD to a row-grouped (sparse) double matrix. If the optional vector is given, it is also - * translated to an explicit row-grouped vector with the same row-grouping. The given offset-labeled DDs - * are used to determine the correct row and column, respectively, for each entry. Note: this function - * assumes that the meta variables used to distinguish different row groups are at the very top of the ADD. - * - * @param rowMetaVariables The meta variables that encode the rows of the matrix. - * @param columnMetaVariables The meta variables that encode the columns of the matrix. - * @param groupMetaVariables The meta variables that are used to distinguish different row groups. - * @param rowOdd The ODD used for determining the correct row. - * @param columnOdd The ODD used for determining the correct column. - * @return The matrix that is represented by this ADD and and a vector corresponding to the symbolic vector - * (if it was given). - */ - storm::storage::SparseMatrix toMatrix(std::set const& rowMetaVariables, std::set const& columnMetaVariables, std::set const& groupMetaVariables, storm::dd::Odd const& rowOdd, storm::dd::Odd const& columnOdd) const; - /*! * Converts the ADD to a row-grouped (sparse) double matrix and the given vector to an equally row-grouped * explicit vector. The given offset-labeled DDs are used to determine the correct row and column, diff --git a/src/storm/storage/dd/Bdd.cpp b/src/storm/storage/dd/Bdd.cpp index d17bbd3d4..62aa7ccb1 100644 --- a/src/storm/storage/dd/Bdd.cpp +++ b/src/storm/storage/dd/Bdd.cpp @@ -63,6 +63,11 @@ namespace storm { return Bdd(ddManager, InternalBdd::fromVector(&ddManager.getInternalDdManager(), odd, ddManager.getSortedVariableIndices(metaVariables), [&truthValues] (uint64_t offset) { return truthValues[offset]; } ), metaVariables); } + template + Bdd Bdd::getEncoding(DdManager const& ddManager, uint64_t targetOffset, storm::dd::Odd const& odd, std::set const& metaVariables) { + return Bdd(ddManager, InternalBdd::fromVector(&ddManager.getInternalDdManager(), odd, ddManager.getSortedVariableIndices(metaVariables), [targetOffset] (uint64_t offset) { return offset == targetOffset; }), metaVariables); + } + template bool Bdd::operator==(Bdd const& other) const { return internalBdd == other.internalBdd; @@ -359,12 +364,75 @@ namespace storm { } } + template + Bdd Bdd::renameVariablesConcretize(std::set const& from, std::set const& to) const { + std::vector> fromBdds; + std::vector> toBdds; + + for (auto const& metaVariable : from) { + STORM_LOG_THROW(this->containsMetaVariable(metaVariable), storm::exceptions::InvalidOperationException, "Cannot rename variable '" << metaVariable.getName() << "' that is not present."); + DdMetaVariable const& ddMetaVariable = this->getDdManager().getMetaVariable(metaVariable); + for (auto const& ddVariable : ddMetaVariable.getDdVariables()) { + fromBdds.push_back(ddVariable.getInternalBdd()); + } + } + std::sort(fromBdds.begin(), fromBdds.end(), [] (InternalBdd const& a, InternalBdd const& b) { return a.getLevel() < b.getLevel(); } ); + for (auto const& metaVariable : to) { + STORM_LOG_THROW(!this->containsMetaVariable(metaVariable), storm::exceptions::InvalidOperationException, "Cannot rename to variable '" << metaVariable.getName() << "' that is already present."); + DdMetaVariable const& ddMetaVariable = this->getDdManager().getMetaVariable(metaVariable); + for (auto const& ddVariable : ddMetaVariable.getDdVariables()) { + toBdds.push_back(ddVariable.getInternalBdd()); + } + } + std::sort(toBdds.begin(), toBdds.end(), [] (InternalBdd const& a, InternalBdd const& b) { return a.getLevel() < b.getLevel(); } ); + + std::set newContainedMetaVariables = to; + std::set_difference(this->getContainedMetaVariables().begin(), this->getContainedMetaVariables().end(), from.begin(), from.end(), std::inserter(newContainedMetaVariables, newContainedMetaVariables.begin())); + + STORM_LOG_ASSERT(toBdds.size() >= fromBdds.size(), "Unable to perform rename-concretize with mismatching sizes."); + + if (fromBdds.size() == toBdds.size()) { + return Bdd(this->getDdManager(), internalBdd.swapVariables(fromBdds, toBdds), newContainedMetaVariables); + } else { + InternalBdd negatedCube = this->getDdManager().getBddOne().getInternalBdd(); + for (uint64_t index = fromBdds.size(); index < toBdds.size(); ++index) { + negatedCube &= !toBdds[index]; + } + toBdds.resize(fromBdds.size()); + + return Bdd(this->getDdManager(), (internalBdd && negatedCube).swapVariables(fromBdds, toBdds), newContainedMetaVariables); + } + } + template template Add Bdd::toAdd() const { return Add(this->getDdManager(), internalBdd.template toAdd(), this->getContainedMetaVariables()); } + template + std::vector> Bdd::split(std::set const& variables) const { + std::set remainingMetaVariables; + std::set_difference(this->getContainedMetaVariables().begin(), this->getContainedMetaVariables().end(), variables.begin(), variables.end(), std::inserter(remainingMetaVariables, remainingMetaVariables.begin())); + + std::vector ddGroupVariableIndices; + for (auto const& variable : variables) { + DdMetaVariable const& metaVariable = this->getDdManager().getMetaVariable(variable); + for (auto const& ddVariable : metaVariable.getDdVariables()) { + ddGroupVariableIndices.push_back(ddVariable.getIndex()); + } + } + std::sort(ddGroupVariableIndices.begin(), ddGroupVariableIndices.end()); + + std::vector> internalBddGroups = this->internalBdd.splitIntoGroups(ddGroupVariableIndices); + std::vector> groups; + for (auto const& internalBdd : internalBddGroups) { + groups.emplace_back(Bdd(this->getDdManager(), internalBdd, remainingMetaVariables)); + } + + return groups; + } + template storm::storage::BitVector Bdd::toVector(storm::dd::Odd const& rowOdd) const { return internalBdd.toVector(rowOdd, this->getSortedVariableIndices()); diff --git a/src/storm/storage/dd/Bdd.h b/src/storm/storage/dd/Bdd.h index c80e6a43b..acb7e9122 100644 --- a/src/storm/storage/dd/Bdd.h +++ b/src/storm/storage/dd/Bdd.h @@ -45,6 +45,16 @@ namespace storm { Bdd(Bdd&& other) = default; Bdd& operator=(Bdd&& other) = default; + /*! + * Constructs the BDD representation of the encoding with the given offset. + * + * @param ddManager The DD manager responsible for the resulting BDD. + * @param targetOffset The offset to encode (interpreted within the ODD). + * @param odd The ODD used for the translation from the explicit representation to a symbolic one. + * @param metaVariables The meta variables to use for the symbolic encoding. + */ + static Bdd getEncoding(DdManager const& ddManager, uint64_t targetOffset, storm::dd::Odd const& odd, std::set const& metaVariables); + /*! * Constructs a BDD representation of all encodings whose value is true in the given list of truth values. * @@ -298,6 +308,19 @@ namespace storm { */ Bdd renameVariablesAbstract(std::set const& from, std::set const& to) const; + /*! + * Renames the given meta variables in the BDD. The number of the underlying DD variables of the from meta + * variable set needs to be at most as large as the to meta variable set. If the amount of variables coincide, + * this operation coincides with renameVariables. Otherwise, it first adds a unique encoding in terms of the + * superfluous variables and then performs the renaming. + * + * @param from The meta variables to be renamed. The current ADD needs to contain all these meta variables. + * @param to The meta variables that are the target of the renaming process. The current ADD must not contain + * any of these meta variables. + * @return The resulting ADD. + */ + Bdd renameVariablesConcretize(std::set const& from, std::set const& to) const; + /*! * Retrieves whether this DD represents the constant one function. * @@ -320,6 +343,11 @@ namespace storm { template Add toAdd() const; + /*! + * Splits the BDD along the given variables (must be at the top). + */ + std::vector> split(std::set const& variables) const; + /*! * Converts the BDD to a bit vector. The given offset-labeled DD is used to determine the correct row of * each entry. diff --git a/src/storm/storage/dd/BisimulationDecomposition.cpp b/src/storm/storage/dd/BisimulationDecomposition.cpp index 682f5602d..d43dd9c65 100644 --- a/src/storm/storage/dd/BisimulationDecomposition.cpp +++ b/src/storm/storage/dd/BisimulationDecomposition.cpp @@ -31,31 +31,31 @@ namespace storm { } } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { this->initialize(); } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, Partition::create(model, bisimulationType, preservationInformation))) { this->initialize(); } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model, formulas), refiner(createRefiner(model, Partition::create(model, bisimulationType, formulas))) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, std::vector> const& formulas, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model, formulas), refiner(createRefiner(model, Partition::create(model, bisimulationType, formulas))) { this->initialize(); } - template - BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, Partition const& initialPartition, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, initialPartition)) { + template + BisimulationDecomposition::BisimulationDecomposition(storm::models::symbolic::Model const& model, Partition const& initialPartition, bisimulation::PreservationInformation const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, initialPartition)) { this->initialize(); } - template - BisimulationDecomposition::~BisimulationDecomposition() = default; + template + BisimulationDecomposition::~BisimulationDecomposition() = default; - template - void BisimulationDecomposition::initialize() { + template + void BisimulationDecomposition::initialize() { auto const& generalSettings = storm::settings::getModule(); verboseProgress = generalSettings.isVerboseSet(); showProgressDelay = generalSettings.getShowProgressDelay(); @@ -69,8 +69,8 @@ namespace storm { STORM_LOG_TRACE("Initial partition has " << refiner->getStatePartition().getNodeCount() << " nodes."); } - template - void BisimulationDecomposition::compute(bisimulation::SignatureMode const& mode) { + template + void BisimulationDecomposition::compute(bisimulation::SignatureMode const& mode) { STORM_LOG_ASSERT(refiner, "No suitable refiner."); STORM_LOG_ASSERT(this->refiner->getStatus() != Status::FixedPoint, "Can only proceed if no fixpoint has been reached yet."); @@ -96,8 +96,8 @@ namespace storm { STORM_LOG_INFO("Partition refinement completed in " << std::chrono::duration_cast(end - start).count() << "ms (" << iterations << " iterations, signature: " << std::chrono::duration_cast(refiner->getTotalSignatureTime()).count() << "ms, refinement: " << std::chrono::duration_cast(refiner->getTotalRefinementTime()).count() << "ms)."); } - template - bool BisimulationDecomposition::compute(uint64_t steps, bisimulation::SignatureMode const& mode) { + template + bool BisimulationDecomposition::compute(uint64_t steps, bisimulation::SignatureMode const& mode) { STORM_LOG_ASSERT(refiner, "No suitable refiner."); STORM_LOG_ASSERT(this->refiner->getStatus() != Status::FixedPoint, "Can only proceed if no fixpoint has been reached yet."); STORM_LOG_ASSERT(steps > 0, "Can only perform positive number of steps."); @@ -123,24 +123,24 @@ namespace storm { return !refined; } - template - bool BisimulationDecomposition::getReachedFixedPoint() const { + template + bool BisimulationDecomposition::getReachedFixedPoint() const { return this->refiner->getStatus() == Status::FixedPoint; } - template - std::shared_ptr> BisimulationDecomposition::getQuotient() const { - std::shared_ptr> quotient; + template + std::shared_ptr> BisimulationDecomposition::getQuotient() const { + std::shared_ptr> quotient; if (this->refiner->getStatus() == Status::FixedPoint) { STORM_LOG_INFO("Starting full quotient extraction."); - QuotientExtractor extractor; + QuotientExtractor extractor; quotient = extractor.extract(model, refiner->getStatePartition(), preservationInformation); } else { STORM_LOG_THROW(model.getType() == storm::models::ModelType::Dtmc || model.getType() == storm::models::ModelType::Mdp, storm::exceptions::InvalidOperationException, "Can only extract partial quotient for discrete-time models."); STORM_LOG_INFO("Starting partial quotient extraction."); if (!partialQuotientExtractor) { - partialQuotientExtractor = std::make_unique>(model); + partialQuotientExtractor = std::make_unique>(model); } quotient = partialQuotientExtractor->extract(refiner->getStatePartition(), preservationInformation); @@ -150,8 +150,8 @@ namespace storm { return quotient; } - template - void BisimulationDecomposition::refineWrtRewardModels() { + template + void BisimulationDecomposition::refineWrtRewardModels() { for (auto const& rewardModelName : this->preservationInformation.getRewardModelNames()) { auto const& rewardModel = this->model.getRewardModel(rewardModelName); refiner->refineWrtRewardModel(rewardModel); @@ -162,6 +162,7 @@ namespace storm { template class BisimulationDecomposition; template class BisimulationDecomposition; + template class BisimulationDecomposition; template class BisimulationDecomposition; } diff --git a/src/storm/storage/dd/BisimulationDecomposition.h b/src/storm/storage/dd/BisimulationDecomposition.h index b5a088ca2..1a552c497 100644 --- a/src/storm/storage/dd/BisimulationDecomposition.h +++ b/src/storm/storage/dd/BisimulationDecomposition.h @@ -29,11 +29,11 @@ namespace storm { template class PartitionRefiner; - template + template class PartialQuotientExtractor; } - template + template class BisimulationDecomposition { public: BisimulationDecomposition(storm::models::symbolic::Model const& model, storm::storage::BisimulationType const& bisimulationType); @@ -64,7 +64,7 @@ namespace storm { /*! * Retrieves the quotient model after the bisimulation decomposition was computed. */ - std::shared_ptr> getQuotient() const; + std::shared_ptr> getQuotient() const; private: void initialize(); @@ -80,7 +80,7 @@ namespace storm { std::unique_ptr> refiner; // A quotient extractor that is used when the fixpoint has not been reached yet. - mutable std::unique_ptr> partialQuotientExtractor; + mutable std::unique_ptr> partialQuotientExtractor; // A flag indicating whether progress is reported. bool verboseProgress; diff --git a/src/storm/storage/dd/Odd.cpp b/src/storm/storage/dd/Odd.cpp index b94295f0e..ff3a1a3ef 100644 --- a/src/storm/storage/dd/Odd.cpp +++ b/src/storm/storage/dd/Odd.cpp @@ -4,6 +4,8 @@ #include #include +#include "storm/storage/BitVector.h" + #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/utility/file.h" @@ -88,6 +90,33 @@ namespace storm { expandValuesToVectorRec(oldOffset + oldOdd.getElseOffset(), oldOdd.getThenSuccessor(), oldValues, newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), newValues); } } + + void Odd::oldToNewIndex(storm::dd::Odd const& newOdd, std::function const& callback) const { + STORM_LOG_ASSERT(this->getHeight() < newOdd.getHeight(), "Expected increase in height."); + oldToNewIndexRec(0, *this, 0, newOdd, callback); + } + + void Odd::oldToNewIndexRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::function const& callback) { + if (oldOdd.getTotalOffset() == 0 || newOdd.getTotalOffset() == 0) { + return; + } + + if (oldOdd.isTerminalNode()) { + if (oldOdd.getThenOffset() != 0) { + if (newOdd.isTerminalNode()) { + if (newOdd.getThenOffset() != 0) { + callback(oldOffset, newOffset); + } + } else { + oldToNewIndexRec(oldOffset, oldOdd, newOffset, newOdd.getElseSuccessor(), callback); + oldToNewIndexRec(oldOffset, oldOdd, newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), callback); + } + } + } else { + oldToNewIndexRec(oldOffset, oldOdd.getElseSuccessor(), newOffset, newOdd.getElseSuccessor(), callback); + oldToNewIndexRec(oldOffset + oldOdd.getElseOffset(), oldOdd.getThenSuccessor(), newOffset + newOdd.getElseOffset(), newOdd.getThenSuccessor(), callback); + } + } void Odd::exportToDot(std::string const& filename) const { std::ofstream dotFile; @@ -130,6 +159,26 @@ namespace storm { storm::utility::closeFile(dotFile); } + void getEncodingRec(Odd const& odd, uint64_t index, uint64_t offset, storm::storage::BitVector& result) { + if (odd.isTerminalNode()) { + return; + } + + bool thenPath = false; + if (odd.getElseOffset() <= offset) { + thenPath = true; + offset -= odd.getElseOffset(); + result.set(index); + } + getEncodingRec(thenPath ? odd.getThenSuccessor() : odd.getElseSuccessor(), index + 1, offset, result); + } + + storm::storage::BitVector Odd::getEncoding(uint64_t offset, uint64_t variableCount) const { + storm::storage::BitVector result(variableCount > 0 ? variableCount : this->getHeight()); + getEncodingRec(*this, 0, offset, result); + return result; + } + void Odd::addToLevelToOddNodesMap(std::map>& levelToOddNodesMap, uint_fast64_t level) const { levelToOddNodesMap[level].emplace(this); if (!this->isTerminalNode()) { diff --git a/src/storm/storage/dd/Odd.h b/src/storm/storage/dd/Odd.h index 0cb4a307c..ac23142f4 100644 --- a/src/storm/storage/dd/Odd.h +++ b/src/storm/storage/dd/Odd.h @@ -5,8 +5,13 @@ #include #include #include +#include namespace storm { + namespace storage { + class BitVector; + } + namespace dd { class Odd { public: @@ -112,6 +117,16 @@ namespace storm { template void expandExplicitVector(storm::dd::Odd const& newOdd, std::vector const& oldValues, std::vector& newValues) const; + /*! + * Translates the indices of the old ODD to that of the new ODD by calling the callback for each old-new + * offset pair. Note that for each old offset, there may be multiple new offsets. The new ODD is expected + * to extend the old ODD by adding layers *at the bottom*. + * + * @param newOdd The new ODD to use. + * @param callback The callback function. + */ + void oldToNewIndex(storm::dd::Odd const& newOdd, std::function const& callback) const; + /*! * Exports the ODD in the dot format to the given file. * @@ -119,6 +134,15 @@ namespace storm { */ void exportToDot(std::string const& filename) const; + /*! + * Retrieves the encoding for the given offset. + * + * @param offset The target offset. + * @param variableCount If not null, this indicates how many variables are contained in the encoding. If 0, + * this number is automatically determined. + */ + storm::storage::BitVector getEncoding(uint64_t offset, uint64_t variableCount = 0) const; + private: /*! * Adds all nodes below the current one to the given mapping. @@ -142,6 +166,8 @@ namespace storm { template static void expandValuesToVectorRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, std::vector const& oldValues, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::vector& newValues); + static void oldToNewIndexRec(uint_fast64_t oldOffset, storm::dd::Odd const& oldOdd, uint_fast64_t newOffset, storm::dd::Odd const& newOdd, std::function const& callback); + // The then- and else-nodes. std::shared_ptr elseNode; std::shared_ptr thenNode; diff --git a/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp b/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp index 07c46fc3c..ce14cd837 100644 --- a/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp +++ b/src/storm/storage/dd/bisimulation/InternalSylvanSignatureRefiner.cpp @@ -11,13 +11,15 @@ namespace storm { namespace dd { namespace bisimulation { + static const uint64_t NO_ELEMENT_MARKER = -1ull; + InternalSylvanSignatureRefinerBase::InternalSylvanSignatureRefinerBase(storm::dd::DdManager const& manager, storm::expressions::Variable const& blockVariable, std::set const& stateVariables, storm::dd::Bdd const& nondeterminismVariables, storm::dd::Bdd const& nonBlockVariables, InternalSignatureRefinerOptions const& options) : manager(manager), blockVariable(blockVariable), stateVariables(stateVariables), nondeterminismVariables(nondeterminismVariables), nonBlockVariables(nonBlockVariables), options(options), numberOfBlockVariables(manager.getMetaVariable(blockVariable).getNumberOfDdVariables()), blockCube(manager.getMetaVariable(blockVariable).getCube()), nextFreeBlockIndex(0), numberOfRefinements(0), currentCapacity(1ull << 20), resizeFlag(0) { // Perform garbage collection to clean up stuff not needed anymore. LACE_ME; sylvan_gc(); - table.resize(3 * currentCapacity); + table.resize(3 * currentCapacity, NO_ELEMENT_MARKER); } template @@ -30,13 +32,14 @@ namespace storm { Partition InternalSignatureRefiner::refine(Partition const& oldPartition, Signature const& signature) { std::pair, boost::optional>> newPartitionDds = refine(oldPartition, signature.getSignatureAdd()); ++numberOfRefinements; + return oldPartition.replacePartition(newPartitionDds.first, nextFreeBlockIndex, nextFreeBlockIndex, newPartitionDds.second); } template void InternalSignatureRefiner::clearCaches() { for (auto& e : this->table) { - e = 0ull; + e = NO_ELEMENT_MARKER; } for (auto& e : this->signatures) { e = 0ull; @@ -142,7 +145,7 @@ namespace storm { uint64_t oldCapacity = refiner->currentCapacity; refiner->currentCapacity <<= 1; - refiner->table = std::vector(3 * refiner->currentCapacity); + refiner->table = std::vector(3 * refiner->currentCapacity, NO_ELEMENT_MARKER); CALL(sylvan_rehash, 0, oldCapacity, refiner); @@ -173,13 +176,13 @@ namespace storm { ptr = refiner->table.data() + pos*3; a = *ptr; if (a == sig) { - while ((b=ptr[1]) == 0) continue; + while ((b=ptr[1]) == NO_ELEMENT_MARKER) continue; if (b == previous_block) { - while ((c=ptr[2]) == 0) continue; + while ((c=ptr[2]) == NO_ELEMENT_MARKER) continue; return c; } - } else if (a == 0) { - if (cas(ptr, 0, sig)) { + } else if (a == NO_ELEMENT_MARKER) { + if (cas(ptr, NO_ELEMENT_MARKER, sig)) { c = ptr[2] = __sync_fetch_and_add(&refiner->nextFreeBlockIndex, 1); ptr[1] = previous_block; return c; @@ -189,7 +192,7 @@ namespace storm { } pos++; if (pos >= refiner->currentCapacity) pos = 0; - if (++count >= 128) return 0; + if (++count >= 128) return NO_ELEMENT_MARKER; } } @@ -219,11 +222,11 @@ namespace storm { } return sylvan_cube(vars, e.data()); } - + TASK_3(BDD, sylvan_assign_block, BDD, sig, BDD, previous_block, InternalSylvanSignatureRefinerBase*, refiner) { assert(previous_block != mtbdd_false); // if so, incorrect call! - + // maybe do garbage collection sylvan_gc_test(); @@ -232,21 +235,25 @@ namespace storm { sig = (uint64_t)-1; } - // try to claim previous block number - assert(previous_block != sylvan_false); - const uint64_t p_b = CALL(sylvan_decode_block, previous_block); - assert(p_b < refiner->signatures.size()); - - for (;;) { - BDD cur = *(volatile BDD*)&refiner->signatures[p_b]; - if (cur == sig) return previous_block; - if (cur != 0) break; - if (cas(&refiner->signatures[p_b], 0, sig)) return previous_block; + if (refiner->options.reuseBlockNumbers) { + // try to claim previous block number + assert(previous_block != sylvan_false); + const uint64_t p_b = CALL(sylvan_decode_block, previous_block); + assert(p_b < refiner->signatures.size()); + + for (;;) { + BDD cur = *(volatile BDD*)&refiner->signatures[p_b]; + if (cur == sig) return previous_block; + if (cur != 0) break; + if (cas(&refiner->signatures[p_b], 0, sig)) return previous_block; + } } // no previous block number, search or insert uint64_t c; - while ((c = sylvan_search_or_insert(sig, previous_block, refiner)) == 0) CALL(sylvan_grow, refiner); + while ((c = sylvan_search_or_insert(sig, previous_block, refiner)) == NO_ELEMENT_MARKER) { + CALL(sylvan_grow, refiner); + } return CALL(sylvan_encode_block, refiner->blockCube.getInternalBdd().getSylvanBdd().GetBDD(), refiner->numberOfBlockVariables, c); } diff --git a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp index 129c426c7..d047acfde 100644 --- a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp +++ b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.cpp @@ -73,6 +73,18 @@ namespace storm { return choicePartition; } + template + bool NondeterministicModelPartitionRefiner::refineWrtStateRewards(storm::dd::Add const& stateRewards) { + STORM_LOG_TRACE("Refining with respect to state rewards."); + Partition newStatePartition = this->stateSignatureRefiner.refine(this->statePartition, Signature(stateRewards)); + if (newStatePartition == this->statePartition) { + return false; + } else { + this->statePartition = newStatePartition; + return true; + } + } + template bool NondeterministicModelPartitionRefiner::refineWrtStateActionRewards(storm::dd::Add const& stateActionRewards) { STORM_LOG_TRACE("Refining with respect to state-action rewards."); diff --git a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h index bf2717998..0dae7f90e 100644 --- a/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h +++ b/src/storm/storage/dd/bisimulation/NondeterministicModelPartitionRefiner.h @@ -34,6 +34,8 @@ namespace storm { private: virtual bool refineWrtStateActionRewards(storm::dd::Add const& stateActionRewards) override; + virtual bool refineWrtStateRewards(storm::dd::Add const& stateRewards) override; + // The model to refine. storm::models::symbolic::NondeterministicModel const& model; diff --git a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp index 9e5e34b54..fea92c755 100644 --- a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.cpp @@ -15,18 +15,18 @@ namespace storm { namespace dd { namespace bisimulation { - template - PartialQuotientExtractor::PartialQuotientExtractor(storm::models::symbolic::Model const& model) : model(model) { + template + PartialQuotientExtractor::PartialQuotientExtractor(storm::models::symbolic::Model const& model) : model(model) { auto const& settings = storm::settings::getModule(); this->quotientFormat = settings.getQuotientFormat(); STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); } - template - std::shared_ptr> PartialQuotientExtractor::extract(Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> PartialQuotientExtractor::extract(Partition const& partition, PreservationInformation const& preservationInformation) { auto start = std::chrono::high_resolution_clock::now(); - std::shared_ptr> result; + std::shared_ptr> result; STORM_LOG_THROW(this->quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Dd, storm::exceptions::NotSupportedException, "Only DD-based partial quotient extraction is currently supported."); result = extractDdQuotient(partition, preservationInformation); @@ -38,8 +38,8 @@ namespace storm { return result; } - template - std::shared_ptr> PartialQuotientExtractor::extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> PartialQuotientExtractor::extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Mdp) { @@ -122,16 +122,19 @@ namespace storm { end = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); + std::shared_ptr> result; if (modelType == storm::models::ModelType::Dtmc) { - return std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), preservedLabelBdds, quotientRewardModels); + result = std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), preservedLabelBdds, quotientRewardModels); } else if (modelType == storm::models::ModelType::Mdp) { std::set allNondeterminismVariables; std::set_union(model.getRowVariables().begin(), model.getRowVariables().end(), model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end(), std::inserter(allNondeterminismVariables, allNondeterminismVariables.begin())); - return std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), model.getNondeterminismVariables(), allNondeterminismVariables, preservedLabelBdds, quotientRewardModels); + result = std::make_shared>(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getRowVariables(), model.getNondeterminismVariables(), allNondeterminismVariables, preservedLabelBdds, quotientRewardModels); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported quotient type."); } + + return result->template toValueType(); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract partial quotient for this model type."); } @@ -142,6 +145,7 @@ namespace storm { #ifdef STORM_HAVE_CARL template class PartialQuotientExtractor; + template class PartialQuotientExtractor; template class PartialQuotientExtractor; #endif diff --git a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h index 26ae033e6..d5c638c2a 100644 --- a/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h +++ b/src/storm/storage/dd/bisimulation/PartialQuotientExtractor.h @@ -16,15 +16,15 @@ namespace storm { namespace dd { namespace bisimulation { - template + template class PartialQuotientExtractor { public: PartialQuotientExtractor(storm::models::symbolic::Model const& model); - std::shared_ptr> extract(Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extract(Partition const& partition, PreservationInformation const& preservationInformation); private: - std::shared_ptr> extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractDdQuotient(Partition const& partition, PreservationInformation const& preservationInformation); // The model for which to compute the partial quotient. storm::models::symbolic::Model const& model; diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp index 593f1491a..1ba224331 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.cpp @@ -222,10 +222,10 @@ namespace storm { spp::sparse_hash_map visitedNodes; }; - template + template class InternalSparseQuotientExtractor; - template + template class InternalSparseQuotientExtractorBase { public: InternalSparseQuotientExtractorBase(storm::models::symbolic::Model const& model, storm::dd::Bdd const& partitionBdd, storm::expressions::Variable const& blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd const& representatives) : model(model), manager(model.getManager()), isNondeterministic(false), partitionBdd(partitionBdd), numberOfBlocks(numberOfBlocks), blockVariable(blockVariable), representatives(representatives), matrixEntriesCreated(false) { @@ -259,23 +259,23 @@ namespace storm { virtual ~InternalSparseQuotientExtractorBase() = default; - storm::storage::SparseMatrix extractTransitionMatrix(storm::dd::Add const& transitionMatrix) { + storm::storage::SparseMatrix extractTransitionMatrix(storm::dd::Add const& transitionMatrix) { return extractMatrixInternal(transitionMatrix); } - std::vector extractStateVector(storm::dd::Add const& vector) { + std::vector extractStateVector(storm::dd::Add const& vector) { return extractVectorInternal(vector, this->rowVariablesCube, this->odd); } - std::vector extractStateActionVector(storm::dd::Add const& vector) { + std::vector extractStateActionVector(storm::dd::Add const& vector) { if (!this->isNondeterministic) { return extractStateVector(vector); } else { STORM_LOG_ASSERT(!this->rowPermutation.empty(), "Expected proper row permutation."); - std::vector valueVector = extractVectorInternal(vector, this->allSourceVariablesCube, this->nondeterminismOdd); + std::vector valueVector = extractVectorInternal(vector, this->allSourceVariablesCube, this->nondeterminismOdd); // Reorder the values according to the known row permutation. - std::vector reorderedValues(valueVector.size()); + std::vector reorderedValues(valueVector.size()); for (uint64_t pos = 0; pos < valueVector.size(); ++pos) { reorderedValues[pos] = valueVector[rowPermutation[pos]]; } @@ -292,14 +292,14 @@ namespace storm { } protected: - virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) = 0; + virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) = 0; - virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) = 0; + virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) = 0; - storm::storage::SparseMatrix createMatrixFromEntries() { + storm::storage::SparseMatrix createMatrixFromEntries() { for (auto& row : matrixEntries) { std::sort(row.begin(), row.end(), - [] (storm::storage::MatrixEntry const& a, storm::storage::MatrixEntry const& b) { + [] (storm::storage::MatrixEntry const& a, storm::storage::MatrixEntry const& b) { return a.getColumn() < b.getColumn(); }); } @@ -312,7 +312,7 @@ namespace storm { uint64_t rowCounter = 0; uint64_t lastState = this->isNondeterministic ? rowToState[rowPermutation.front()] : 0; - storm::storage::SparseMatrixBuilder builder(matrixEntries.size(), this->numberOfBlocks, 0, true, this->isNondeterministic); + storm::storage::SparseMatrixBuilder builder(matrixEntries.size(), this->numberOfBlocks, 0, true, this->isNondeterministic); if (this->isNondeterministic) { builder.newRowGroup(0); } @@ -343,7 +343,7 @@ namespace storm { return builder.build(); } - void addMatrixEntry(uint64_t row, uint64_t column, ValueType const& value) { + void addMatrixEntry(uint64_t row, uint64_t column, ExportValueType const& value) { this->matrixEntries[row].emplace_back(column, value); } @@ -390,7 +390,7 @@ namespace storm { bool matrixEntriesCreated; // The entries of the quotient matrix that is built. - std::vector>> matrixEntries; + std::vector>> matrixEntries; // A vector storing for each row which state it belongs to. std::vector rowToState; @@ -621,33 +621,33 @@ namespace storm { spp::sparse_hash_map blockToOffset; }; - template - class InternalSparseQuotientExtractor : public InternalSparseQuotientExtractorBase { + template + class InternalSparseQuotientExtractor : public InternalSparseQuotientExtractorBase { public: - InternalSparseQuotientExtractor(storm::models::symbolic::Model const& model, storm::dd::Bdd const& partitionBdd, storm::expressions::Variable const& blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd const& representatives) : InternalSparseQuotientExtractorBase(model, partitionBdd, blockVariable, numberOfBlocks, representatives) { + InternalSparseQuotientExtractor(storm::models::symbolic::Model const& model, storm::dd::Bdd const& partitionBdd, storm::expressions::Variable const& blockVariable, uint64_t numberOfBlocks, storm::dd::Bdd const& representatives) : InternalSparseQuotientExtractorBase(model, partitionBdd, blockVariable, numberOfBlocks, representatives) { this->createBlockToOffsetMapping(); } private: - virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) override { + virtual storm::storage::SparseMatrix extractMatrixInternal(storm::dd::Add const& matrix) override { this->createMatrixEntryStorage(); extractTransitionMatrixRec(matrix.getInternalAdd().getSylvanMtbdd().GetMTBDD(), this->isNondeterministic ? this->nondeterminismOdd : this->odd, 0, this->partitionBdd.getInternalBdd().getSylvanBdd().GetBDD(), this->representatives.getInternalBdd().getSylvanBdd().GetBDD(), this->allSourceVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(), this->nondeterminismVariablesCube.getInternalBdd().getSylvanBdd().GetBDD(), this->isNondeterministic ? &this->odd : nullptr, 0); return this->createMatrixFromEntries(); } - virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) override { - std::vector result(odd.getTotalOffset()); + virtual std::vector extractVectorInternal(storm::dd::Add const& vector, storm::dd::Bdd const& variablesCube, storm::dd::Odd const& odd) override { + std::vector result(odd.getTotalOffset()); extractVectorRec(vector.getInternalAdd().getSylvanMtbdd().GetMTBDD(), this->representatives.getInternalBdd().getSylvanBdd().GetBDD(), variablesCube.getInternalBdd().getSylvanBdd().GetBDD(), odd, 0, result); return result; } - void extractVectorRec(MTBDD vector, BDD representativesNode, BDD variables, storm::dd::Odd const& odd, uint64_t offset, std::vector& result) { + void extractVectorRec(MTBDD vector, BDD representativesNode, BDD variables, storm::dd::Odd const& odd, uint64_t offset, std::vector& result) { if (representativesNode == sylvan_false || mtbdd_iszero(vector)) { return; } if (sylvan_isconst(variables)) { - result[offset] = storm::dd::InternalAdd::getValue(vector); + result[offset] = storm::utility::convertNumber(storm::dd::InternalAdd::getValue(vector)); } else { MTBDD vectorT; MTBDD vectorE; @@ -723,7 +723,7 @@ namespace storm { // If we have moved through all source variables, we must have arrived at a target block encoding. if (sylvan_isconst(variables)) { STORM_LOG_ASSERT(mtbdd_isleaf(transitionMatrixNode), "Expected constant node."); - this->addMatrixEntry(sourceOffset, blockToOffset.at(targetPartitionNode), storm::dd::InternalAdd::getValue(transitionMatrixNode)); + this->addMatrixEntry(sourceOffset, blockToOffset.at(targetPartitionNode), storm::utility::convertNumber(storm::dd::InternalAdd::getValue(transitionMatrixNode))); if (stateOdd) { this->assignRowToState(sourceOffset, stateOffset); } @@ -817,18 +817,18 @@ namespace storm { spp::sparse_hash_map blockToOffset; }; - template - QuotientExtractor::QuotientExtractor() : useRepresentatives(false) { + template + QuotientExtractor::QuotientExtractor() : useRepresentatives(false) { auto const& settings = storm::settings::getModule(); this->useRepresentatives = settings.isUseRepresentativesSet(); this->useOriginalVariables = settings.isUseOriginalVariablesSet(); this->quotientFormat = settings.getQuotientFormat(); } - template - std::shared_ptr> QuotientExtractor::extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto start = std::chrono::high_resolution_clock::now(); - std::shared_ptr> result; + std::shared_ptr> result; if (quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Sparse) { result = extractSparseQuotient(model, partition, preservationInformation); } else { @@ -842,8 +842,8 @@ namespace storm { return result; } - template - std::shared_ptr> QuotientExtractor::extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto states = partition.getStates().swapVariables(model.getRowColumnMetaVariablePairs()); storm::dd::Bdd partitionAsBdd = partition.storedAsAdd() ? partition.asAdd().toBdd() : partition.asBdd(); @@ -853,8 +853,8 @@ namespace storm { auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); STORM_LOG_ASSERT(representatives.getNonZeroCount() == partition.getNumberOfBlocks(), "Representatives size does not match that of the partition: " << representatives.getNonZeroCount() << " vs. " << partition.getNumberOfBlocks() << "."); STORM_LOG_ASSERT((representatives && partitionAsBdd).existsAbstract(model.getRowVariables()) == partitionAsBdd.existsAbstract(model.getRowVariables()), "Representatives do not cover all blocks."); - InternalSparseQuotientExtractor sparseExtractor(model, partitionAsBdd, partition.getBlockVariable(), partition.getNumberOfBlocks(), representatives); - storm::storage::SparseMatrix quotientTransitionMatrix = sparseExtractor.extractTransitionMatrix(model.getTransitionMatrix()); + InternalSparseQuotientExtractor sparseExtractor(model, partitionAsBdd, partition.getBlockVariable(), partition.getNumberOfBlocks(), representatives); + storm::storage::SparseMatrix quotientTransitionMatrix = sparseExtractor.extractTransitionMatrix(model.getTransitionMatrix()); auto end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); @@ -881,47 +881,47 @@ namespace storm { STORM_LOG_INFO("Quotient labels extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); start = std::chrono::high_resolution_clock::now(); - std::unordered_map> quotientRewardModels; + std::unordered_map> quotientRewardModels; for (auto const& rewardModelName : preservationInformation.getRewardModelNames()) { auto const& rewardModel = model.getRewardModel(rewardModelName); - boost::optional> quotientStateRewards; + boost::optional> quotientStateRewards; if (rewardModel.hasStateRewards()) { quotientStateRewards = sparseExtractor.extractStateVector(rewardModel.getStateRewardVector()); } - boost::optional> quotientStateActionRewards; + boost::optional> quotientStateActionRewards; if (rewardModel.hasStateActionRewards()) { quotientStateActionRewards = sparseExtractor.extractStateActionVector(rewardModel.getStateActionRewardVector()); } - quotientRewardModels.emplace(rewardModelName, storm::models::sparse::StandardRewardModel(std::move(quotientStateRewards), std::move(quotientStateActionRewards), boost::none)); + quotientRewardModels.emplace(rewardModelName, storm::models::sparse::StandardRewardModel(std::move(quotientStateRewards), std::move(quotientStateActionRewards), boost::none)); } end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); - std::shared_ptr> result; + std::shared_ptr> result; if (model.getType() == storm::models::ModelType::Dtmc) { - result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); + result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); } else if (model.getType() == storm::models::ModelType::Ctmc) { - result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); + result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); } else if (model.getType() == storm::models::ModelType::Mdp) { - result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); + result = std::make_shared>(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels)); } else if (model.getType() == storm::models::ModelType::MarkovAutomaton) { storm::models::symbolic::MarkovAutomaton const& markovAutomaton = *model.template as>(); boost::optional markovianStates = sparseExtractor.extractSetExists(markovAutomaton.getMarkovianStates()); - storm::storage::sparse::ModelComponents modelComponents(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels), false, std::move(markovianStates)); + storm::storage::sparse::ModelComponents modelComponents(std::move(quotientTransitionMatrix), std::move(quotientStateLabeling), std::move(quotientRewardModels), false, std::move(markovianStates)); modelComponents.exitRates = sparseExtractor.extractStateVector(markovAutomaton.getExitRateVector()); - - result = std::make_shared>(std::move(modelComponents)); + + result = std::make_shared>(std::move(modelComponents)); } return result; } - template - std::shared_ptr> QuotientExtractor::extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { if (this->useOriginalVariables) { return extractQuotientUsingOriginalVariables(model, partition, preservationInformation); @@ -930,16 +930,12 @@ namespace storm { } } - template - std::shared_ptr> QuotientExtractor::extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); bool useRepresentativesForThisExtraction = this->useRepresentatives; if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::MarkovAutomaton) { - if (modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::MarkovAutomaton) { - STORM_LOG_WARN_COND(!useRepresentativesForThisExtraction, "Using representatives is unsupported for MDPs, falling back to regular extraction."); - useRepresentativesForThisExtraction = false; - } // Sanity checks. STORM_LOG_ASSERT(partition.getNumberOfStates() == model.getNumberOfStates(), "Mismatching partition size."); @@ -948,16 +944,20 @@ namespace storm { std::set blockVariableSet = {partition.getBlockVariable()}; std::set blockPrimeVariableSet = {partition.getPrimedBlockVariable()}; std::vector> blockMetaVariablePairs = {std::make_pair(partition.getBlockVariable(), partition.getPrimedBlockVariable())}; + + auto start = std::chrono::high_resolution_clock::now(); + // Compute representatives. storm::dd::Bdd partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero(); + partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); + auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); + if (useRepresentativesForThisExtraction) { - storm::dd::Bdd partitionAsBddOverPrimedBlockVariable = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet); - storm::dd::Bdd representativePartition = partitionAsBddOverPrimedBlockVariable.existsAbstractRepresentative(model.getColumnVariables()).renameVariables(model.getColumnVariables(), blockVariableSet); - partitionAsBdd = (representativePartition && partitionAsBddOverPrimedBlockVariable).existsAbstract(blockPrimeVariableSet); + storm::dd::Bdd partitionAsBddOverPrimedBlockVariables = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet); + storm::dd::Bdd tmp = (representatives && partitionAsBddOverPrimedBlockVariables).renameVariablesConcretize(model.getRowVariables(), blockVariableSet); + partitionAsBdd = (tmp && partitionAsBddOverPrimedBlockVariables).existsAbstract(blockPrimeVariableSet); } - auto start = std::chrono::high_resolution_clock::now(); - partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); storm::dd::Bdd reachableStates = partitionAsBdd.existsAbstract(model.getRowVariables()); storm::dd::Bdd initialStates = (model.getInitialStates() && partitionAsBdd).existsAbstract(model.getRowVariables()); @@ -989,7 +989,6 @@ namespace storm { storm::dd::Add quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsAdd.renameVariables(blockAndRowVariables, blockPrimeAndColumnVariables), model.getColumnVariables()); // Pick a representative from each block. - auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); partitionAsBdd &= representatives; partitionAsAdd *= partitionAsBdd.template toAdd(); @@ -1007,7 +1006,10 @@ namespace storm { STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); storm::dd::Bdd quotientTransitionMatrixBdd = quotientTransitionMatrix.notZero(); - storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(blockPrimeVariableSet) && reachableStates; + + std::set blockPrimeAndNondeterminismVariables = model.getNondeterminismVariables(); + blockPrimeAndNondeterminismVariables.insert(blockPrimeVariableSet.begin(), blockPrimeVariableSet.end()); + storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(blockPrimeAndNondeterminismVariables) && reachableStates; start = std::chrono::high_resolution_clock::now(); std::unordered_map> quotientRewardModels; @@ -1029,24 +1031,28 @@ namespace storm { end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); + std::shared_ptr> result; if (modelType == storm::models::ModelType::Dtmc) { - return std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Ctmc) { - return std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Mdp) { - return std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } else { - return std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, blockVariableSet, blockPrimeVariableSet, blockMetaVariablePairs, model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } + + return result->template toValueType(); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract quotient for this model type."); } } - template - std::shared_ptr> QuotientExtractor::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { + template + std::shared_ptr> QuotientExtractor::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation) { auto modelType = model.getType(); + bool useRepresentativesForThisExtraction = this->useRepresentatives; if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc || modelType == storm::models::ModelType::Mdp || modelType == storm::models::ModelType::MarkovAutomaton) { STORM_LOG_WARN_COND(!this->useRepresentatives, "Using representatives is unsupported for this extraction, falling back to regular extraction."); @@ -1058,10 +1064,19 @@ namespace storm { std::set blockPrimeVariableSet = {partition.getPrimedBlockVariable()}; std::vector> blockMetaVariablePairs = {std::make_pair(partition.getBlockVariable(), partition.getPrimedBlockVariable())}; - storm::dd::Bdd partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero(); - auto start = std::chrono::high_resolution_clock::now(); + + // Compute representatives. + storm::dd::Bdd partitionAsBdd = partition.storedAsBdd() ? partition.asBdd() : partition.asAdd().notZero(); partitionAsBdd = partitionAsBdd.renameVariables(model.getColumnVariables(), model.getRowVariables()); + auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); + + if (useRepresentativesForThisExtraction) { + storm::dd::Bdd partitionAsBddOverPrimedBlockVariables = partitionAsBdd.renameVariables(blockVariableSet, blockPrimeVariableSet); + storm::dd::Bdd tmp = (representatives && partitionAsBddOverPrimedBlockVariables).renameVariablesConcretize(model.getRowVariables(), blockVariableSet); + partitionAsBdd = (tmp && partitionAsBddOverPrimedBlockVariables).existsAbstract(blockPrimeVariableSet); + } + storm::dd::Bdd reachableStates = partitionAsBdd.existsAbstract(model.getRowVariables()).renameVariablesAbstract(blockVariableSet, model.getRowVariables()); storm::dd::Bdd initialStates = (model.getInitialStates() && partitionAsBdd).existsAbstract(model.getRowVariables()).renameVariablesAbstract(blockVariableSet, model.getRowVariables()); @@ -1093,7 +1108,6 @@ namespace storm { storm::dd::Add quotientTransitionMatrix = model.getTransitionMatrix().multiplyMatrix(partitionAsAdd.renameVariables(model.getRowVariables(), model.getColumnVariables()), model.getColumnVariables()).renameVariablesAbstract(blockVariableSet, model.getColumnVariables()); // Pick a representative from each block. - auto representatives = InternalRepresentativeComputer(partitionAsBdd, model.getRowVariables()).getRepresentatives(); partitionAsBdd &= representatives; partitionAsAdd = partitionAsBdd.template toAdd(); @@ -1116,7 +1130,10 @@ namespace storm { STORM_LOG_INFO("Quotient transition matrix extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); storm::dd::Bdd quotientTransitionMatrixBdd = quotientTransitionMatrix.notZero(); - storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(model.getColumnVariables()) && reachableStates; + + std::set columnAndNondeterminismVariables = model.getColumnVariables(); + columnAndNondeterminismVariables.insert(model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end()); + storm::dd::Bdd deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(columnAndNondeterminismVariables) && reachableStates; start = std::chrono::high_resolution_clock::now(); std::unordered_map> quotientRewardModels; @@ -1138,15 +1155,18 @@ namespace storm { end = std::chrono::high_resolution_clock::now(); STORM_LOG_INFO("Reward models extracted in " << std::chrono::duration_cast(end - start).count() << "ms."); + std::shared_ptr> result; if (modelType == storm::models::ModelType::Dtmc) { - return std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Dtmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Ctmc) { - return std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Ctmc(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), preservedLabelBdds, quotientRewardModels)); } else if (modelType == storm::models::ModelType::Mdp) { - return std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::Mdp(model.getManager().asSharedPointer(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } else { - return std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); + result = std::shared_ptr>(new storm::models::symbolic::MarkovAutomaton(model.getManager().asSharedPointer(), model. template as>()->getMarkovianMarker(), reachableStates, initialStates, deadlockStates, quotientTransitionMatrix, model.getRowVariables(), model.getColumnVariables(), model.getRowColumnMetaVariablePairs(), model.getNondeterminismVariables(), preservedLabelBdds, quotientRewardModels)); } + + return result->template toValueType(); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Cannot extract quotient for this model type."); } @@ -1156,6 +1176,7 @@ namespace storm { template class QuotientExtractor; template class QuotientExtractor; + template class QuotientExtractor; template class QuotientExtractor; } diff --git a/src/storm/storage/dd/bisimulation/QuotientExtractor.h b/src/storm/storage/dd/bisimulation/QuotientExtractor.h index b75b27b08..422453bf7 100644 --- a/src/storm/storage/dd/bisimulation/QuotientExtractor.h +++ b/src/storm/storage/dd/bisimulation/QuotientExtractor.h @@ -16,19 +16,19 @@ namespace storm { namespace dd { namespace bisimulation { - template + template class QuotientExtractor { public: QuotientExtractor(); - std::shared_ptr> extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extract(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); private: - std::shared_ptr> extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractSparseQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); - std::shared_ptr> extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); - std::shared_ptr> extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); - std::shared_ptr> extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractDdQuotient(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractQuotientUsingBlockVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); + std::shared_ptr> extractQuotientUsingOriginalVariables(storm::models::symbolic::Model const& model, Partition const& partition, PreservationInformation const& preservationInformation); bool useRepresentatives; bool useOriginalVariables; diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp index 11c6b12ca..9ed21a92a 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.cpp @@ -6,6 +6,7 @@ #include "storm/storage/dd/Odd.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" @@ -493,16 +494,24 @@ namespace storm { template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(this->getCuddDdNode(), nullptr, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getCuddDdNode(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector] (uint64_t const& offset, ValueType const& value) { targetVector[offset] = function(targetVector[offset], value); }); + } + + template + void InternalAdd::forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { + forEachRec(this->getCuddDdNode(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, function); } template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(this->getCuddDdNode(), &offsets, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getCuddDdNode(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector, &offsets] (uint64_t const& offset, ValueType const& value) { + ValueType& targetValue = targetVector[offsets[offset]]; + targetValue = function(targetValue, value); + }); } template - void InternalAdd::composeWithExplicitVectorRec(DdNode const* dd, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { + void InternalAdd::forEachRec(DdNode const* dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { // For the empty DD, we do not need to add any entries. if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { return; @@ -510,17 +519,51 @@ namespace storm { // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentLevel == maxLevel) { - ValueType& targetValue = targetVector[offsets != nullptr ? (*offsets)[currentOffset] : currentOffset]; - targetValue = function(targetValue, storm::utility::convertNumber(Cudd_V(dd))); + function(currentOffset, storm::utility::convertNumber(Cudd_V(dd))); } else if (ddVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set // and for the one in which it is not set. - composeWithExplicitVectorRec(dd, offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(dd, offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } else { // Otherwise, we simply recursively call the function for both (different) cases. - composeWithExplicitVectorRec(Cudd_E_const(dd), offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(Cudd_T_const(dd), offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(Cudd_E_const(dd), currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(Cudd_T_const(dd), currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); + } + } + + template + std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const { + std::vector result; + decodeGroupLabelsRec(this->getCuddDdNode(), result, ddGroupVariableIndices, ddLabelVariableIndices, 0, ddGroupVariableIndices.size(), 0); + return result; + } + + template + void InternalAdd::decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { + // For the empty DD, we do not need to create a group. + if (dd == Cudd_ReadZero(ddManager->getCuddManager().getManager())) { + return; + } + + if (currentLevel == maxLevel) { + labels.push_back(label); + } else { + uint64_t elseLabel = label; + uint64_t thenLabel = label; + + if (ddLabelVariableIndices.get(currentLevel)) { + elseLabel <<= 1; + thenLabel = (thenLabel << 1) | 1; + } + + if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } else { + decodeGroupLabelsRec(Cudd_E(dd), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(Cudd_T(dd), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } } } diff --git a/src/storm/storage/dd/cudd/InternalCuddAdd.h b/src/storm/storage/dd/cudd/InternalCuddAdd.h index 2262d5da0..e5af927e8 100644 --- a/src/storm/storage/dd/cudd/InternalCuddAdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddAdd.h @@ -549,6 +549,18 @@ namespace storm { */ void composeWithExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + /*! + * Composes the ADD with an explicit vector by performing a specified function between the entries of this + * ADD and the explicit vector. + * + * @param odd The ODD to use for the translation from symbolic to explicit positions. + * @param ddVariableIndices The indices of the DD variables present in this ADD. + * @param targetVector The explicit vector that is to be composed with the ADD. The results are written to + * this vector again. + * @param function The function to perform in the composition. + */ + void forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; + /*! * Composes the (row-grouped) ADD with an explicit vector by performing a specified function between the * entries of this ADD and the explicit vector. @@ -570,6 +582,16 @@ namespace storm { */ std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + /*! + * Splits the ADD into several ADDs that differ in the encoding of the given group variables (given via indices). + * The labeling is then made by interpreting the group encodings as binary encodings. + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @param ddLabelVariableIndices The indices of variables that are considered as labels. + * @return A vector of ADDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const; + /*! * Simultaneously splits the ADD and the given vector ADD into several ADDs that differ in the encoding of * the given group variables (given via indices). @@ -636,18 +658,18 @@ namespace storm { private: /*! - * Performs a recursive step to perform the given function between the given DD-based vector and the given - * explicit vector. + * Performs a recursive step for forEach. * - * @param dd The DD to add to the explicit vector. + * @param dd The DD to traverse. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. * @param currentOffset The current offset. * @param odd The ODD used for the translation. * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. - * @param targetVector The vector to which the translated DD-based vector is to be added. + * @param function The callback invoked for every element. The first argument is the offset and the second + * is the value. */ - void composeWithExplicitVectorRec(DdNode const* dd, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + void forEachRec(DdNode const* dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; /*! * Splits the given matrix DD into the groups using the given group variables. @@ -661,6 +683,20 @@ namespace storm { */ void splitIntoGroupsRec(DdNode* dd, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + /*! + * Splits the given matrix DD into the labelings of the gropus using the given group variables. + * + * @param dd The DD to split. + * @param labels A vector that is to be filled with the labels of the individual groups. + * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param ddLabelVariableIndices A bit vector indicating which variables are considered label variables. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. + * @param label The currently followed label. + */ + void decodeGroupLabelsRec(DdNode* dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; + /*! * Splits the given DDs into the groups using the given group variables. * diff --git a/src/storm/storage/dd/cudd/InternalCuddBdd.cpp b/src/storm/storage/dd/cudd/InternalCuddBdd.cpp index 5fc12e567..41aee2517 100644 --- a/src/storm/storage/dd/cudd/InternalCuddBdd.cpp +++ b/src/storm/storage/dd/cudd/InternalCuddBdd.cpp @@ -294,7 +294,7 @@ namespace storm { } else if (dd == Cudd_ReadOne(manager.getManager()) && complement) { return; } - + // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentRowLevel == maxLevel) { result.set(currentRowOffset, true); @@ -412,6 +412,32 @@ namespace storm { } } + std::vector> InternalBdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { + std::vector> result; + splitIntoGroupsRec(Cudd_Regular(this->getCuddDdNode()), Cudd_IsComplement(this->getCuddDdNode()), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); + return result; + } + + void InternalBdd::splitIntoGroupsRec(DdNode* dd, bool negated, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { + // For the empty DD, we do not need to create a group. + if (negated && dd == Cudd_ReadOne(ddManager->getCuddManager().getManager())) { + return; + } + + if (currentLevel == maxLevel) { + groups.push_back(InternalBdd(ddManager, cudd::BDD(ddManager->getCuddManager(), negated ? Cudd_Complement(dd) : dd))); + } else if (ddGroupVariableIndices[currentLevel] < Cudd_NodeReadIndex(dd)) { + splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(dd, negated, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } else { + DdNode* elseNode = Cudd_E(dd); + DdNode* thenNode = Cudd_T(dd); + + splitIntoGroupsRec(elseNode, negated ^ Cudd_IsComplement(elseNode), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(thenNode, negated ^ Cudd_IsComplement(thenNode), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } + } + void InternalBdd::filterExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const { uint_fast64_t currentIndex = 0; filterExplicitVectorRec(Cudd_Regular(this->getCuddDdNode()), ddManager->getCuddManager(), 0, Cudd_IsComplement(this->getCuddDdNode()), ddVariableIndices.size(), ddVariableIndices, 0, odd, targetValues, currentIndex, sourceValues); diff --git a/src/storm/storage/dd/cudd/InternalCuddBdd.h b/src/storm/storage/dd/cudd/InternalCuddBdd.h index 93c54c0c8..2a8d8dd52 100644 --- a/src/storm/storage/dd/cudd/InternalCuddBdd.h +++ b/src/storm/storage/dd/cudd/InternalCuddBdd.h @@ -385,6 +385,14 @@ namespace storm { */ void filterExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const; + /*! + * Splits the BDD into several BDDs that differ in the encoding of the given group variables (given via indices). + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of BDDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + friend struct std::hash>; /*! @@ -504,6 +512,8 @@ namespace storm { */ static storm::expressions::Variable toExpressionRec(DdNode const* dd, cudd::Cudd const& ddManager, storm::expressions::ExpressionManager& manager, std::vector& expressions, std::unordered_map& indexToVariableMap, std::unordered_map, storm::expressions::Variable>& countIndexToVariablePair, std::unordered_map& nodeToCounterMap, std::vector& nextCounterForIndex); + void splitIntoGroupsRec(DdNode* dd, bool negated, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; + InternalDdManager const* ddManager; cudd::BDD cuddBdd; diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp index 0173f6aac..fc0829f22 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp @@ -5,6 +5,7 @@ #include "storm/storage/dd/DdManager.h" #include "storm/storage/SparseMatrix.h" +#include "storm/storage/BitVector.h" #include "storm/utility/macros.h" #include "storm/utility/constants.h" @@ -883,16 +884,24 @@ namespace storm { template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), nullptr, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector] (uint64_t const& offset, ValueType const& value) { targetVector[offset] = function(targetVector[offset], value); }); } template void InternalAdd::composeWithExplicitVector(storm::dd::Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const { - composeWithExplicitVectorRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), mtbdd_hascomp(this->getSylvanMtbdd().GetMTBDD()), &offsets, 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, targetVector, function); + forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, [&function, &targetVector, &offsets] (uint64_t const& offset, ValueType const& value) { + ValueType& targetValue = targetVector[offsets[offset]]; + targetValue = function(targetValue, value); + }); } template - void InternalAdd::composeWithExplicitVectorRec(MTBDD dd, bool negated, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const { + void InternalAdd::forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { + forEachRec(this->getSylvanMtbdd().GetMTBDD(), 0, ddVariableIndices.size(), 0, odd, ddVariableIndices, function); + } + + template + void InternalAdd::forEachRec(MTBDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const { // For the empty DD, we do not need to add any entries. if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { return; @@ -900,24 +909,58 @@ namespace storm { // If we are at the maximal level, the value to be set is stored as a constant in the DD. if (currentLevel == maxLevel) { - ValueType& targetValue = targetVector[offsets != nullptr ? (*offsets)[currentOffset] : currentOffset]; - targetValue = function(targetValue, getValue(dd)); + function(currentOffset, getValue(dd)); } else if (mtbdd_isleaf(dd) || ddVariableIndices[currentLevel] < mtbdd_getvar(dd)) { // If we skipped a level, we need to enumerate the explicit entries for the case in which the bit is set // and for the one in which it is not set. - composeWithExplicitVectorRec(dd, negated, offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(dd, negated, offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(dd, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); } else { // Otherwise, we simply recursively call the function for both (different) cases. MTBDD thenNode = mtbdd_gethigh(dd); MTBDD elseNode = mtbdd_getlow(dd); - // Determine whether we have to evaluate the successors as if they were complemented. - bool elseComplemented = mtbdd_hascomp(elseNode) ^ negated; - bool thenComplemented = mtbdd_hascomp(thenNode) ^ negated; + forEachRec(elseNode, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, function); + forEachRec(thenNode, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, function); + } + } + + template + std::vector InternalAdd::decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const { + std::vector result; + decodeGroupLabelsRec(mtbdd_regular(this->getSylvanMtbdd().GetMTBDD()), result, ddGroupVariableIndices, ddLabelVariableIndices, 0, ddGroupVariableIndices.size(), 0); + return result; + } + + template + void InternalAdd::decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const { + // For the empty DD, we do not need to create a group. + if (mtbdd_isleaf(dd) && mtbdd_iszero(dd)) { + return; + } + + if (currentLevel == maxLevel) { + labels.push_back(label); + } else { + uint64_t elseLabel = label; + uint64_t thenLabel = label; - composeWithExplicitVectorRec(mtbdd_regular(elseNode), elseComplemented, offsets, currentLevel + 1, maxLevel, currentOffset, odd.getElseSuccessor(), ddVariableIndices, targetVector, function); - composeWithExplicitVectorRec(mtbdd_regular(thenNode), thenComplemented, offsets, currentLevel + 1, maxLevel, currentOffset + odd.getElseOffset(), odd.getThenSuccessor(), ddVariableIndices, targetVector, function); + if (ddLabelVariableIndices.get(currentLevel)) { + elseLabel <<= 1; + thenLabel = (thenLabel << 1) | 1; + } + + if (mtbdd_isleaf(dd) || ddGroupVariableIndices[currentLevel] < mtbdd_getvar(dd)) { + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(dd, labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + MTBDD thenDdNode = mtbdd_gethigh(dd); + MTBDD elseDdNode = mtbdd_getlow(dd); + + decodeGroupLabelsRec(mtbdd_regular(elseDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, elseLabel); + decodeGroupLabelsRec(mtbdd_regular(thenDdNode), labels, ddGroupVariableIndices, ddLabelVariableIndices, currentLevel + 1, maxLevel, thenLabel); + } } } diff --git a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h index 5137caf15..ccdc61414 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanAdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanAdd.h @@ -553,6 +553,18 @@ namespace storm { */ void composeWithExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, std::vector const& offsets, std::vector& targetVector, std::function const& function) const; + /*! + * Composes the ADD with an explicit vector by performing a specified function between the entries of this + * ADD and the explicit vector. + * + * @param odd The ODD to use for the translation from symbolic to explicit positions. + * @param ddVariableIndices The indices of the DD variables present in this ADD. + * @param targetVector The explicit vector that is to be composed with the ADD. The results are written to + * this vector again. + * @param function The function to perform in the composition. + */ + void forEach(Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; + /*! * Splits the ADD into several ADDs that differ in the encoding of the given group variables (given via indices). * @@ -561,6 +573,16 @@ namespace storm { */ std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + /*! + * Splits the ADD into several ADDs that differ in the encoding of the given group variables (given via indices). + * The labeling is then made by interpreting the group encodings as binary encodings. + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @param ddLabelVariableIndices The indices of variables that are considered as labels. + * @return A vector of ADDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector decodeGroupLabels(std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices) const; + /*! * Simultaneously splits the ADD and the given vector ADD into several ADDs that differ in the encoding of * the given group variables (given via indices). @@ -637,19 +659,32 @@ namespace storm { static std::shared_ptr createOddRec(BDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, std::vector const& ddVariableIndices, std::vector>>& uniqueTableForLevels); /*! - * Performs a recursive step to perform the given function between the given DD-based vector and the given - * explicit vector. + * Performs a recursive step for forEach. * - * @param dd The DD to add to the explicit vector. - * @param negated A flag indicating whether the DD node is to be interpreted as being negated. + * @param dd The DD to traverse. * @param currentLevel The currently considered level in the DD. * @param maxLevel The number of levels that need to be considered. * @param currentOffset The current offset. * @param odd The ODD used for the translation. * @param ddVariableIndices The (sorted) indices of all DD variables that need to be considered. - * @param targetVector The vector to which the translated DD-based vector is to be added. + * @param function The callback invoked for every element. The first argument is the offset and the second + * is the value. + */ + void forEachRec(MTBDD dd, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::function const& function) const; + + /*! + * Splits the given matrix DD into the labelings of the gropus using the given group variables. + * + * @param dd The DD to split. + * @param labels A vector that is to be filled with the labels of the individual groups. + * @param ddGroupVariableIndices The (sorted) indices of all DD group variables that need to be considered. + * @param ddLabelVariableIndices A bit vector indicating which variables are considered label variables. + * @param currentLevel The currently considered level in the DD. + * @param maxLevel The number of levels that need to be considered. + * @param remainingMetaVariables The meta variables that remain in the DDs after the groups have been split. + * @param label The currently followed label. */ - void composeWithExplicitVectorRec(MTBDD dd, bool negated, std::vector const* offsets, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint_fast64_t currentOffset, Odd const& odd, std::vector const& ddVariableIndices, std::vector& targetVector, std::function const& function) const; + void decodeGroupLabelsRec(MTBDD dd, std::vector& labels, std::vector const& ddGroupVariableIndices, storm::storage::BitVector const& ddLabelVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel, uint64_t label) const; /*! * Splits the given matrix DD into the groups using the given group variables. diff --git a/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp b/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp index 97252476a..2ca68d944 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanBdd.cpp @@ -443,6 +443,33 @@ namespace storm { } } + std::vector> InternalBdd::splitIntoGroups(std::vector const& ddGroupVariableIndices) const { + std::vector> result; + splitIntoGroupsRec(this->getSylvanBdd().GetBDD(), result, ddGroupVariableIndices, 0, ddGroupVariableIndices.size()); + return result; + } + + void InternalBdd::splitIntoGroupsRec(BDD dd, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const { + // For the empty DD, we do not need to create a group. + if (dd == sylvan_false) { + return; + } + + if (currentLevel == maxLevel) { + groups.push_back(InternalBdd(ddManager, sylvan::Bdd(dd))); + } else if (bdd_isterminal(dd) || ddGroupVariableIndices[currentLevel] < sylvan_var(dd)) { + splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } else { + // Otherwise, we compute the ODDs for both the then- and else successors. + BDD thenDdNode = sylvan_high(dd); + BDD elseDdNode = sylvan_low(dd); + + splitIntoGroupsRec(elseDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + splitIntoGroupsRec(thenDdNode, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel); + } + } + std::pair, std::unordered_map> InternalBdd::toExpression(storm::expressions::ExpressionManager& manager) const { std::pair, std::unordered_map> result; diff --git a/src/storm/storage/dd/sylvan/InternalSylvanBdd.h b/src/storm/storage/dd/sylvan/InternalSylvanBdd.h index a1160654c..e5c5a3df2 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanBdd.h +++ b/src/storm/storage/dd/sylvan/InternalSylvanBdd.h @@ -374,6 +374,14 @@ namespace storm { */ void filterExplicitVector(Odd const& odd, std::vector const& ddVariableIndices, storm::storage::BitVector const& sourceValues, storm::storage::BitVector& targetValues) const; + /*! + * Splits the BDD into several BDDs that differ in the encoding of the given group variables (given via indices). + * + * @param ddGroupVariableIndices The indices of the variables that are used to distinguish the groups. + * @return A vector of BDDs that are the separate groups (wrt. to the encoding of the given variables). + */ + std::vector> splitIntoGroups(std::vector const& ddGroupVariableIndices) const; + friend struct std::hash>; /*! @@ -488,6 +496,7 @@ namespace storm { */ static storm::expressions::Variable toExpressionRec(BDD dd, storm::expressions::ExpressionManager& manager, std::vector& expressions, std::unordered_map& indexToVariableMap, std::unordered_map, storm::expressions::Variable>& countIndexToVariablePair, std::unordered_map& nodeToCounterMap, std::vector& nextCounterForIndex); + void splitIntoGroupsRec(BDD dd, std::vector>& groups, std::vector const& ddGroupVariableIndices, uint_fast64_t currentLevel, uint_fast64_t maxLevel) const; // The internal manager responsible for this BDD. InternalDdManager const* ddManager; diff --git a/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp b/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp index a2ded9452..eaab6e2c2 100644 --- a/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp +++ b/src/storm/storage/dd/sylvan/InternalSylvanDdManager.cpp @@ -64,25 +64,39 @@ namespace storm { } lace_startup(0, 0, 0); - // Each node takes 24 bytes and the maximal memory is specified in megabytes. - uint_fast64_t totalNodesToStore = storm::settings::getModule().getMaximalMemory() * 1024 * 1024 / 24; + // Table/cache size computation taken from newer version of sylvan. + uint64_t memorycap = storm::settings::getModule().getMaximalMemory() * 1024 * 1024; - // Compute the power of two that still fits within the total numbers to store. - uint_fast64_t powerOfTwo = findLargestPowerOfTwoFitting(totalNodesToStore); + uint64_t table_ratio = 0; + uint64_t initial_ratio = 0; - STORM_LOG_THROW(powerOfTwo >= 16, storm::exceptions::InvalidSettingsException, "Too little memory assigned to sylvan."); + uint64_t max_t = 1; + uint64_t max_c = 1; + if (table_ratio > 0) { + max_t <<= table_ratio; + } else { + max_c <<= -table_ratio; + } - uint64_t maxTableSize = 1ull << powerOfTwo; - uint64_t maxCacheSize = 1ull << (powerOfTwo - 1); - if (maxTableSize + maxCacheSize > totalNodesToStore) { - maxTableSize >>= 1; + uint64_t cur = max_t * 24 + max_c * 36; + STORM_LOG_THROW(cur <= memorycap, storm::exceptions::InvalidSettingsException, "Memory cap incompatible with default table ratio."); + + while (2*cur < memorycap && max_t < 0x0000040000000000) { + max_t *= 2; + max_c *= 2; + cur *= 2; } - uint64_t initialTableSize = 1ull << std::max(powerOfTwo - 4, static_cast(16)); - uint64_t initialCacheSize = initialTableSize; + uint64_t min_t = max_t, min_c = max_c; + while (initial_ratio > 0 && min_t > 0x1000 && min_c > 0x1000) { + min_t >>= 1; + min_c >>= 1; + initial_ratio--; + } + // End of copied code. - STORM_LOG_DEBUG("Initializing sylvan. Initial/max table size: " << initialTableSize << "/" << maxTableSize << ", initial/max cache size: " << initialCacheSize << "/" << maxCacheSize << "."); - sylvan::Sylvan::initPackage(initialTableSize, maxTableSize, initialCacheSize, maxCacheSize); + STORM_LOG_DEBUG("Initializing sylvan library. Initial/max table size: " << min_t << "/" << max_t << ", initial/max cache size: " << min_c << "/" << max_c << "."); + sylvan::Sylvan::initPackage(min_t, max_t, min_c, max_c); sylvan::Sylvan::initBdd(); sylvan::Sylvan::initMtbdd(); diff --git a/src/storm/storage/expressions/BaseExpression.cpp b/src/storm/storage/expressions/BaseExpression.cpp index 4e07fd089..b6f652e3f 100644 --- a/src/storm/storage/expressions/BaseExpression.cpp +++ b/src/storm/storage/expressions/BaseExpression.cpp @@ -6,6 +6,7 @@ #include "storm/storage/expressions/Expressions.h" #include "storm/storage/expressions/ToRationalNumberVisitor.h" +#include "storm/storage/expressions/ReduceNestingVisitor.h" namespace storm { namespace expressions { @@ -63,7 +64,7 @@ namespace storm { } std::shared_ptr BaseExpression::getOperand(uint_fast64_t operandIndex) const { - STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression of arity 0."); + STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operand " << operandIndex << " in expression '" << *this << "' of arity 0."); } std::string const& BaseExpression::getIdentifier() const { @@ -74,6 +75,11 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to access operator of non-function application expression."); } + std::shared_ptr BaseExpression::reduceNesting() const { + ReduceNestingVisitor v; + return v.reduceNesting(this->toExpression()).getBaseExpressionPointer(); + } + bool BaseExpression::containsVariables() const { return false; } diff --git a/src/storm/storage/expressions/BaseExpression.h b/src/storm/storage/expressions/BaseExpression.h index 93091e536..666c4d40b 100644 --- a/src/storm/storage/expressions/BaseExpression.h +++ b/src/storm/storage/expressions/BaseExpression.h @@ -185,6 +185,13 @@ namespace storm { */ virtual std::shared_ptr simplify() const = 0; + /*! + * Tries to flatten the syntax tree of the expression, e.g., 1 + (2 + (3 + 4)) becomes (1 + 2) + (3 + 4) + * + * @return A semantically equivalent expression with reduced nesting + */ + std::shared_ptr reduceNesting() const; + /*! * Accepts the given visitor by calling its visit method. * diff --git a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp index 2cd3c2f61..92ed03c5c 100644 --- a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp +++ b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.cpp @@ -6,11 +6,13 @@ #include "storm/storage/expressions/IntegerLiteralExpression.h" #include "storm/storage/expressions/RationalLiteralExpression.h" #include "storm/storage/expressions/ExpressionVisitor.h" + #include "storm/utility/macros.h" +#include "storm/utility/constants.h" +#include "storm/utility/NumberTraits.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/InvalidStateException.h" - namespace storm { namespace expressions { BinaryNumericalFunctionExpression::BinaryNumericalFunctionExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& firstOperand, std::shared_ptr const& secondOperand, OperatorType operatorType) : BinaryExpression(manager, type, firstOperand, secondOperand), operatorType(operatorType) { @@ -31,6 +33,7 @@ namespace storm { case OperatorType::Min: result = storm::expressions::OperatorType::Min; break; case OperatorType::Max: result = storm::expressions::OperatorType::Max; break; case OperatorType::Power: result = storm::expressions::OperatorType::Power; break; + case OperatorType::Modulo: result = storm::expressions::OperatorType::Modulo; break; } return result; } @@ -49,6 +52,7 @@ namespace storm { case OperatorType::Min: result = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: result = std::max(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Power: result = static_cast(std::pow(firstOperandEvaluation, secondOperandEvaluation)); break; + case OperatorType::Modulo: result = firstOperandEvaluation % secondOperandEvaluation; break; } return result; } @@ -67,6 +71,7 @@ namespace storm { case OperatorType::Min: result = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: result = std::max(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Power: result = std::pow(firstOperandEvaluation, secondOperandEvaluation); break; + case OperatorType::Modulo: result = std::fmod(firstOperandEvaluation, secondOperandEvaluation); break; } return result; } @@ -79,7 +84,7 @@ namespace storm { if (this->hasIntegerType()) { int_fast64_t firstOperandEvaluation = firstOperandSimplified->evaluateAsInt(); int_fast64_t secondOperandEvaluation = secondOperandSimplified->evaluateAsInt(); - int_fast64_t newValue = 0; + boost::optional newValue; switch (this->getOperatorType()) { case OperatorType::Plus: newValue = firstOperandEvaluation + secondOperandEvaluation; break; case OperatorType::Minus: newValue = firstOperandEvaluation - secondOperandEvaluation; break; @@ -87,28 +92,40 @@ namespace storm { case OperatorType::Min: newValue = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: newValue = std::max(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Power: newValue = static_cast(std::pow(firstOperandEvaluation, secondOperandEvaluation)); break; - case OperatorType::Divide: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Unable to simplify division."); break; + case OperatorType::Modulo: newValue = firstOperandEvaluation % secondOperandEvaluation; break; + case OperatorType::Divide: break; // do not simplify division. + } + if (newValue) { + return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), newValue.get())); } - return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), newValue)); } else if (this->hasRationalType()) { storm::RationalNumber firstOperandEvaluation = firstOperandSimplified->evaluateAsRational(); storm::RationalNumber secondOperandEvaluation = secondOperandSimplified->evaluateAsRational(); - storm::RationalNumber newValue = 0; + boost::optional newValue; switch (this->getOperatorType()) { case OperatorType::Plus: newValue = firstOperandEvaluation + secondOperandEvaluation; break; case OperatorType::Minus: newValue = firstOperandEvaluation - secondOperandEvaluation; break; case OperatorType::Times: newValue = firstOperandEvaluation * secondOperandEvaluation; break; case OperatorType::Min: newValue = std::min(firstOperandEvaluation, secondOperandEvaluation); break; case OperatorType::Max: newValue = std::max(firstOperandEvaluation, secondOperandEvaluation); break; + case OperatorType::Divide: newValue = firstOperandEvaluation / secondOperandEvaluation; break; case OperatorType::Power: { - STORM_LOG_THROW(carl::isInteger(secondOperandEvaluation), storm::exceptions::InvalidStateException, "Can not simplify pow() with fractional exponent."); - std::size_t exponent = carl::toInt(secondOperandEvaluation); - newValue = carl::pow(firstOperandEvaluation, exponent); + if (carl::isInteger(secondOperandEvaluation)) { + std::size_t exponent = carl::toInt(secondOperandEvaluation); + newValue = carl::pow(firstOperandEvaluation, exponent); + } break; } - case OperatorType::Divide: STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Unable to simplify division."); break; + case OperatorType::Modulo: { + if (carl::isInteger(firstOperandEvaluation) && carl::isInteger(secondOperandEvaluation)) { + newValue = storm::utility::mod(storm::utility::numerator(firstOperandEvaluation), storm::utility::numerator(secondOperandEvaluation)); + } + break; + } + } + if (newValue) { + return std::shared_ptr(new RationalLiteralExpression(this->getManager(), newValue.get())); } - return std::shared_ptr(new RationalLiteralExpression(this->getManager(), newValue)); } } @@ -137,6 +154,7 @@ namespace storm { case OperatorType::Min: stream << "min(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")"; break; case OperatorType::Max: stream << "max(" << *this->getFirstOperand() << ", " << *this->getSecondOperand() << ")"; break; case OperatorType::Power: stream << *this->getFirstOperand() << " ^ " << *this->getSecondOperand(); break; + case OperatorType::Modulo: stream << *this->getFirstOperand() << " % " << *this->getSecondOperand(); break; } stream << ")"; } diff --git a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h index 1e9adb028..1879b141d 100644 --- a/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h +++ b/src/storm/storage/expressions/BinaryNumericalFunctionExpression.h @@ -11,7 +11,7 @@ namespace storm { /*! * An enum type specifying the different operators applicable. */ - enum class OperatorType {Plus, Minus, Times, Divide, Min, Max, Power}; + enum class OperatorType {Plus, Minus, Times, Divide, Min, Max, Power, Modulo}; /*! * Constructs a binary numerical function expression with the given return type, operands and operator. diff --git a/src/storm/storage/expressions/CheckIfThenElseGuardVisitor.cpp b/src/storm/storage/expressions/CheckIfThenElseGuardVisitor.cpp index 0bbb32fba..49a1e658c 100644 --- a/src/storm/storage/expressions/CheckIfThenElseGuardVisitor.cpp +++ b/src/storm/storage/expressions/CheckIfThenElseGuardVisitor.cpp @@ -43,7 +43,7 @@ namespace storm { boost::any_cast(expression.getSecondOperand()->accept(*this, data)); } - boost::any CheckIfThenElseGuardVisitor::visit(VariableExpression const& expression, boost::any const&) { + boost::any CheckIfThenElseGuardVisitor::visit(VariableExpression const&, boost::any const&) { return false; } @@ -55,15 +55,15 @@ namespace storm { return expression.getOperand()->accept(*this, data); } - boost::any CheckIfThenElseGuardVisitor::visit(BooleanLiteralExpression const& expression, boost::any const&) { + boost::any CheckIfThenElseGuardVisitor::visit(BooleanLiteralExpression const&, boost::any const&) { return false; } - boost::any CheckIfThenElseGuardVisitor::visit(IntegerLiteralExpression const& expression, boost::any const&) { + boost::any CheckIfThenElseGuardVisitor::visit(IntegerLiteralExpression const&, boost::any const&) { return false; } - boost::any CheckIfThenElseGuardVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { + boost::any CheckIfThenElseGuardVisitor::visit(RationalLiteralExpression const&, boost::any const&) { return false; } diff --git a/src/storm/storage/expressions/EquivalenceChecker.cpp b/src/storm/storage/expressions/EquivalenceChecker.cpp index b8d538656..ba286dd63 100644 --- a/src/storm/storage/expressions/EquivalenceChecker.cpp +++ b/src/storm/storage/expressions/EquivalenceChecker.cpp @@ -13,10 +13,33 @@ namespace storm { } } + void EquivalenceChecker::addConstraints(std::vector const& constraints) { + for (auto const& constraint : constraints) { + this->smtSolver->add(constraint); + } + } + bool EquivalenceChecker::areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second) { this->smtSolver->push(); - this->smtSolver->add((first && !second) || (!first && second)); + this->smtSolver->add(!storm::expressions::iff(first, second)); + bool equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; + this->smtSolver->pop(); + return equivalent; + } + + bool EquivalenceChecker::areEquivalentModuloNegation(storm::expressions::Expression const& first, storm::expressions::Expression const& second) { + this->smtSolver->push(); + this->smtSolver->add(!storm::expressions::iff(first, second)); bool equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; + if (equivalent) { + this->smtSolver->pop(); + return true; + } + this->smtSolver->pop(); + this->smtSolver->push(); + this->smtSolver->add(!storm::expressions::iff(first, !second)); + equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat; + this->smtSolver->pop(); return equivalent; } diff --git a/src/storm/storage/expressions/EquivalenceChecker.h b/src/storm/storage/expressions/EquivalenceChecker.h index 2ec39ba8a..5d60eb50b 100644 --- a/src/storm/storage/expressions/EquivalenceChecker.h +++ b/src/storm/storage/expressions/EquivalenceChecker.h @@ -20,7 +20,10 @@ namespace storm { */ EquivalenceChecker(std::unique_ptr&& smtSolver, boost::optional const& constraint = boost::none); + void addConstraints(std::vector const& constraints); + bool areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second); + bool areEquivalentModuloNegation(storm::expressions::Expression const& first, storm::expressions::Expression const& second); private: std::unique_ptr smtSolver; diff --git a/src/storm/storage/expressions/Expression.cpp b/src/storm/storage/expressions/Expression.cpp index 1537e633e..f6459ba85 100644 --- a/src/storm/storage/expressions/Expression.cpp +++ b/src/storm/storage/expressions/Expression.cpp @@ -73,6 +73,10 @@ namespace storm { return Expression(this->getBaseExpression().simplify()); } + Expression Expression::reduceNesting() const { + return Expression(this->getBaseExpression().reduceNesting()); + } + OperatorType Expression::getOperator() const { return this->getBaseExpression().getOperator(); } @@ -123,6 +127,10 @@ namespace storm { return result; } + void Expression::gatherVariables(std::set& variables) const { + this->getBaseExpression().gatherVariables(variables); + } + bool Expression::containsVariable(std::set const& variables) const { std::set appearingVariables = this->getVariables(); std::set intersection; @@ -277,6 +285,11 @@ namespace storm { return Expression(std::shared_ptr(new BinaryNumericalFunctionExpression(first.getBaseExpression().getManager(), first.getType().power(second.getType()), first.getBaseExpressionPointer(), second.getBaseExpressionPointer(), BinaryNumericalFunctionExpression::OperatorType::Power))); } + Expression operator%(Expression const& first, Expression const& second) { + assertSameManager(first.getBaseExpression(), second.getBaseExpression()); + return Expression(std::shared_ptr(new BinaryNumericalFunctionExpression(first.getBaseExpression().getManager(), first.getType().power(second.getType()), first.getBaseExpressionPointer(), second.getBaseExpressionPointer(), BinaryNumericalFunctionExpression::OperatorType::Modulo))); + } + Expression operator&&(Expression const& first, Expression const& second) { if (!first.isInitialized()) { return second; @@ -442,8 +455,5 @@ namespace storm { return result; } - - - } } diff --git a/src/storm/storage/expressions/Expression.h b/src/storm/storage/expressions/Expression.h index 98a2e6417..262e09208 100644 --- a/src/storm/storage/expressions/Expression.h +++ b/src/storm/storage/expressions/Expression.h @@ -33,6 +33,7 @@ namespace storm { friend Expression operator*(Expression const& first, Expression const& second); friend Expression operator/(Expression const& first, Expression const& second); friend Expression operator^(Expression const& first, Expression const& second); + friend Expression operator%(Expression const& first, Expression const& second); friend Expression operator&&(Expression const& first, Expression const& second); friend Expression operator||(Expression const& first, Expression const& second); friend Expression operator!(Expression const& first); @@ -151,6 +152,13 @@ namespace storm { */ Expression simplify() const; + /*! + * Tries to flatten the syntax tree of the expression, e.g., 1 + (2 + (3 + 4)) becomes (1 + 2) + (3 + 4) + * + * @return A semantically equivalent expression with reduced nesting + */ + Expression reduceNesting() const; + /*! * Retrieves the operator of a function application. This is only legal to call if the expression is * function application. @@ -254,6 +262,14 @@ namespace storm { */ std::set getVariables() const; + /*! + * Retrieves the set of all variables that appear in the expression. These variables are added to the given + * set. + * + * @param variables The set to which to add the variables. + */ + void gatherVariables(std::set& variables) const; + /*! * Retrieves whether the expression contains any of the given variables. * diff --git a/src/storm/storage/expressions/ExpressionEvaluator.cpp b/src/storm/storage/expressions/ExpressionEvaluator.cpp index b167c6034..0436a8ef2 100644 --- a/src/storm/storage/expressions/ExpressionEvaluator.cpp +++ b/src/storm/storage/expressions/ExpressionEvaluator.cpp @@ -53,6 +53,11 @@ namespace storm { rationalNumberVisitor.setMapping(variable, storm::utility::convertNumber(value)); } + void ExpressionEvaluator::setRationalValue(storm::expressions::Variable const& variable, RationalNumber const& value) { + ExprtkExpressionEvaluatorBase::setRationalValue(variable, storm::utility::convertNumber(value)); + rationalNumberVisitor.setMapping(variable, value); + } + RationalNumber ExpressionEvaluator::asRational(Expression const& expression) const { RationalNumber result = this->rationalNumberVisitor.toRationalNumber(expression); return result; @@ -78,6 +83,12 @@ namespace storm { rationalFunctionVisitor.setMapping(variable, storm::utility::convertNumber(value)); } + void ExpressionEvaluator::setRationalValue(storm::expressions::Variable const& variable, RationalFunction const& value) { + STORM_LOG_ASSERT(storm::utility::isConstant(value), "Value for rational variable is not a constant."); + ExprtkExpressionEvaluatorBase::setRationalValue(variable, storm::utility::convertNumber(value)); + rationalFunctionVisitor.setMapping(variable, value); + } + RationalFunction ExpressionEvaluator::asRational(Expression const& expression) const { return this->rationalFunctionVisitor.toRationalFunction(expression); } diff --git a/src/storm/storage/expressions/ExpressionEvaluator.h b/src/storm/storage/expressions/ExpressionEvaluator.h index 5d867e8be..5461f9c4f 100644 --- a/src/storm/storage/expressions/ExpressionEvaluator.h +++ b/src/storm/storage/expressions/ExpressionEvaluator.h @@ -45,6 +45,11 @@ namespace storm { void setIntegerValue(storm::expressions::Variable const& variable, int_fast64_t value) override; void setRationalValue(storm::expressions::Variable const& variable, double value) override; + // Sets a rational value from a RationalNumber. + // Note: If an expression contains the given variable and is evaluated to int or bool, the value is internally considered as a double. + void setRationalValue(storm::expressions::Variable const& variable, storm::RationalNumber const& value); + + RationalNumber asRational(Expression const& expression) const override; private: @@ -60,6 +65,10 @@ namespace storm { void setBooleanValue(storm::expressions::Variable const& variable, bool value) override; void setIntegerValue(storm::expressions::Variable const& variable, int_fast64_t value) override; void setRationalValue(storm::expressions::Variable const& variable, double value) override; + + // Sets a rational value from a RationalFunction. The function needs to be constant. + // Note: If an expression contains the given variable and is evaluated to int or bool, the value is internally considered as a double. + void setRationalValue(storm::expressions::Variable const& variable, storm::RationalFunction const& value); RationalFunction asRational(Expression const& expression) const override; diff --git a/src/storm/storage/expressions/ExpressionManager.cpp b/src/storm/storage/expressions/ExpressionManager.cpp index d1b3d15cd..5cc3ffcd5 100644 --- a/src/storm/storage/expressions/ExpressionManager.cpp +++ b/src/storm/storage/expressions/ExpressionManager.cpp @@ -52,7 +52,7 @@ namespace storm { } } - ExpressionManager::ExpressionManager() : nameToIndexMapping(), indexToNameMapping(), indexToTypeMapping(), numberOfBooleanVariables(0), numberOfIntegerVariables(0), numberOfBitVectorVariables(0), numberOfRationalVariables(0), numberOfAuxiliaryVariables(0), numberOfAuxiliaryBooleanVariables(0), numberOfAuxiliaryIntegerVariables(0), numberOfAuxiliaryBitVectorVariables(0), numberOfAuxiliaryRationalVariables(0), freshVariableCounter(0) { + ExpressionManager::ExpressionManager() : nameToIndexMapping(), indexToNameMapping(), indexToTypeMapping(), numberOfBooleanVariables(0), numberOfIntegerVariables(0), numberOfBitVectorVariables(0), numberOfRationalVariables(0), numberOfArrayVariables(0), numberOfAuxiliaryVariables(0), numberOfAuxiliaryBooleanVariables(0), numberOfAuxiliaryIntegerVariables(0), numberOfAuxiliaryBitVectorVariables(0), numberOfAuxiliaryRationalVariables(0), numberOfAuxiliaryArrayVariables(0), freshVariableCounter(0) { // Intentionally left empty. } @@ -115,6 +115,11 @@ namespace storm { return rationalType.get(); } + Type const& ExpressionManager::getArrayType(Type elementType) const { + Type type(this->getSharedPointer(), std::shared_ptr(new ArrayType(elementType))); + return *arrayTypes.insert(type).first; + } + bool ExpressionManager::isValidVariableName(std::string const& name) { return name.size() < 2 || name.at(0) != '_' || name.at(1) != '_'; } @@ -149,6 +154,10 @@ namespace storm { Variable ExpressionManager::declareRationalVariable(std::string const& name, bool auxiliary) { return this->declareVariable(name, this->getRationalType(), auxiliary); } + + Variable ExpressionManager::declareArrayVariable(std::string const& name, Type const& elementType, bool auxiliary) { + return this->declareVariable(name, this->getArrayType(elementType), auxiliary); + } Variable ExpressionManager::declareOrGetVariable(std::string const& name, storm::expressions::Type const& variableType, bool auxiliary) { return declareOrGetVariable(name, variableType, auxiliary, true); @@ -168,8 +177,12 @@ namespace storm { offset = numberOfIntegerVariables++ + numberOfBitVectorVariables; } else if (variableType.isBitVectorType()) { offset = numberOfBitVectorVariables++ + numberOfIntegerVariables; - } else { + } else if (variableType.isRationalType()) { offset = numberOfRationalVariables++; + } else if (variableType.isArrayType()) { + offset = numberOfArrayVariables++; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Trying to declare a variable of unsupported type: '" << variableType.getStringRepresentation() << "'."); } } else { if (variableType.isBooleanType()) { @@ -178,8 +191,12 @@ namespace storm { offset = numberOfIntegerVariables++ + numberOfBitVectorVariables; } else if (variableType.isBitVectorType()) { offset = numberOfBitVectorVariables++ + numberOfIntegerVariables; - } else { + } else if (variableType.isRationalType()) { offset = numberOfRationalVariables++; + } else if (variableType.isArrayType()) { + offset = numberOfArrayVariables++; + } else { + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Trying to declare a variable of unsupported type: '" << variableType.getStringRepresentation() << "'."); } } @@ -240,12 +257,14 @@ namespace storm { return numberOfBitVectorVariables; } else if (variableType.isRationalType()) { return numberOfRationalVariables; + } else if (variableType.isArrayType()) { + return numberOfArrayVariables; } return 0; } uint_fast64_t ExpressionManager::getNumberOfVariables() const { - return numberOfBooleanVariables + numberOfIntegerVariables + numberOfBitVectorVariables + numberOfRationalVariables; + return numberOfBooleanVariables + numberOfIntegerVariables + numberOfBitVectorVariables + numberOfRationalVariables + numberOfArrayVariables; } uint_fast64_t ExpressionManager::getNumberOfBooleanVariables() const { @@ -264,6 +283,10 @@ namespace storm { return numberOfRationalVariables; } + uint_fast64_t ExpressionManager::getNumberOfArrayVariables() const { + return numberOfRationalVariables; + } + std::string const& ExpressionManager::getVariableName(uint_fast64_t index) const { auto indexTypeNamePair = indexToNameMapping.find(index); STORM_LOG_THROW(indexTypeNamePair != indexToNameMapping.end(), storm::exceptions::InvalidArgumentException, "Unknown variable index '" << index << "'."); @@ -300,7 +323,7 @@ namespace storm { out << "manager {" << std::endl; for (auto const& variableTypePair : manager) { - std::cout << "\t" << variableTypePair.second << " " << variableTypePair.first.getName() << " [offset " << variableTypePair.first.getOffset() << "]" << std::endl; + out << "\t" << variableTypePair.second << " " << variableTypePair.first.getName() << " [offset " << variableTypePair.first.getOffset() << "]" << std::endl; } out << "}" << std::endl; diff --git a/src/storm/storage/expressions/ExpressionManager.h b/src/storm/storage/expressions/ExpressionManager.h index 3a80261b3..cf56d5670 100644 --- a/src/storm/storage/expressions/ExpressionManager.h +++ b/src/storm/storage/expressions/ExpressionManager.h @@ -149,6 +149,11 @@ namespace storm { * @return The rational type. */ Type const& getRationalType() const; + + /*! + * Retrieves the array type with the given element type + */ + Type const& getArrayType(Type elementType) const; /*! * Declares a variable that is a copy of the provided variable (i.e. has the same type). @@ -211,6 +216,11 @@ namespace storm { */ Variable declareRationalVariable(std::string const& name, bool auxiliary = false); + /*! + * Declares a new array variable with the given name and the given element type. + */ + Variable declareArrayVariable(std::string const& name, Type const& elementType, bool auxiliary = false); + /*! * Declares a variable with the given name if it does not yet exist. * @@ -321,6 +331,11 @@ namespace storm { */ uint_fast64_t getNumberOfRationalVariables() const; + /*! + * Retrieves the number of array variables. + */ + uint_fast64_t getNumberOfArrayVariables() const; + /*! * Retrieves the name of the variable with the given index. * @@ -443,6 +458,7 @@ namespace storm { uint_fast64_t numberOfIntegerVariables; uint_fast64_t numberOfBitVectorVariables; uint_fast64_t numberOfRationalVariables; + uint_fast64_t numberOfArrayVariables; // The number of declared auxiliary variables. uint_fast64_t numberOfAuxiliaryVariables; @@ -452,6 +468,7 @@ namespace storm { uint_fast64_t numberOfAuxiliaryIntegerVariables; uint_fast64_t numberOfAuxiliaryBitVectorVariables; uint_fast64_t numberOfAuxiliaryRationalVariables; + uint_fast64_t numberOfAuxiliaryArrayVariables; // A counter used to create fresh variables. uint_fast64_t freshVariableCounter; @@ -461,6 +478,7 @@ namespace storm { mutable boost::optional integerType; mutable std::unordered_set bitvectorTypes; mutable boost::optional rationalType; + mutable std::unordered_set arrayTypes; // A mask that can be used to query whether a variable is an auxiliary variable. static const uint64_t auxiliaryMask = (1ull << 50); diff --git a/src/storm/storage/expressions/LinearityCheckVisitor.cpp b/src/storm/storage/expressions/LinearityCheckVisitor.cpp index 9eeb3ea56..86650acea 100644 --- a/src/storm/storage/expressions/LinearityCheckVisitor.cpp +++ b/src/storm/storage/expressions/LinearityCheckVisitor.cpp @@ -77,6 +77,7 @@ namespace storm { case BinaryNumericalFunctionExpression::OperatorType::Min: return LinearityStatus::NonLinear; break; case BinaryNumericalFunctionExpression::OperatorType::Max: return LinearityStatus::NonLinear; break; case BinaryNumericalFunctionExpression::OperatorType::Power: return LinearityStatus::NonLinear; break; + case BinaryNumericalFunctionExpression::OperatorType::Modulo: return LinearityStatus::NonLinear; break; } STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Illegal binary numerical expression operator."); } diff --git a/src/storm/storage/expressions/OperatorType.cpp b/src/storm/storage/expressions/OperatorType.cpp index 1036869bc..bba61a653 100644 --- a/src/storm/storage/expressions/OperatorType.cpp +++ b/src/storm/storage/expressions/OperatorType.cpp @@ -16,6 +16,7 @@ namespace storm { case OperatorType::Min: stream << "min"; break; case OperatorType::Max: stream << "max"; break; case OperatorType::Power: stream << "^"; break; + case OperatorType::Modulo: stream << "%"; break; case OperatorType::Equal: stream << "="; break; case OperatorType::NotEqual: stream << "!="; break; case OperatorType::Less: stream << "<"; break; diff --git a/src/storm/storage/expressions/OperatorType.h b/src/storm/storage/expressions/OperatorType.h index f056f494a..e334b8104 100644 --- a/src/storm/storage/expressions/OperatorType.h +++ b/src/storm/storage/expressions/OperatorType.h @@ -19,6 +19,7 @@ namespace storm { Min, Max, Power, + Modulo, Equal, NotEqual, Less, diff --git a/src/storm/storage/expressions/ReduceNestingVisitor.cpp b/src/storm/storage/expressions/ReduceNestingVisitor.cpp new file mode 100644 index 000000000..5f77ca10c --- /dev/null +++ b/src/storm/storage/expressions/ReduceNestingVisitor.cpp @@ -0,0 +1,180 @@ +#include + +#include "storm/storage/expressions/ReduceNestingVisitor.h" +#include "storm/storage/expressions/Expressions.h" + +namespace storm { + namespace expressions { + + ReduceNestingVisitor::ReduceNestingVisitor() { + // Intentionally left empty. + } + + Expression ReduceNestingVisitor::reduceNesting(Expression const& expression) { + return Expression(boost::any_cast>(expression.getBaseExpression().accept(*this, boost::none))); + } + + boost::any ReduceNestingVisitor::visit(IfThenElseExpression const& expression, boost::any const& data) { + std::shared_ptr conditionExpression = boost::any_cast>(expression.getCondition()->accept(*this, data)); + std::shared_ptr thenExpression = boost::any_cast>(expression.getThenExpression()->accept(*this, data)); + std::shared_ptr elseExpression = boost::any_cast>(expression.getElseExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new IfThenElseExpression(expression.getManager(), expression.getType(), conditionExpression, thenExpression, elseExpression))); + } + } + + template + std::vector> getAllOperands(BinaryFunc const& binaryExpression) { + auto opType = binaryExpression.getOperatorType(); + std::vector> stack = {binaryExpression.getSharedPointer()}; + std::vector> res; + while (!stack.empty()) { + auto f = std::move(stack.back()); + stack.pop_back(); + + for (uint64_t opIndex = 0; opIndex < 2; ++opIndex) { + BinaryFunc const* subexp = dynamic_cast(f->getOperand(opIndex).get()); + if (subexp != nullptr && subexp->getOperatorType() == opType) { + stack.push_back(f->getOperand(opIndex)); + } else { + res.push_back(f->getOperand(opIndex)); + } + } + } + return res; + } + + boost::any ReduceNestingVisitor::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) { + + // Check if the operator is commutative and associative + if (expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::Or || expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::And || expression.getOperatorType() == BinaryBooleanFunctionExpression::OperatorType::Iff) { + + std::vector> operands = getAllOperands(expression); + + // Balance the syntax tree if there are enough operands + if (operands.size() >= 4) { + + for (auto& operand : operands) { + operand = boost::any_cast>(operand->accept(*this, data)); + } + + auto opIt = operands.begin(); + while (operands.size() > 1) { + if (opIt == operands.end() || opIt == operands.end() - 1) { + opIt = operands.begin(); + } + *opIt = std::const_pointer_cast(std::shared_ptr(new BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), *opIt, operands.back(), expression.getOperatorType()))); + operands.pop_back(); + ++opIt; + } + return operands.front(); + } + } + + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) { + // Check if the operator is commutative and associative + if (expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Plus || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Times || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Max || expression.getOperatorType() == BinaryNumericalFunctionExpression::OperatorType::Min) { + + std::vector> operands = getAllOperands(expression); + + // Balance the syntax tree if there are enough operands + if (operands.size() >= 4) { + + for (auto& operand : operands) { + operand = boost::any_cast>(operand->accept(*this, data)); + } + + auto opIt = operands.begin(); + while (operands.size() > 1) { + if (opIt == operands.end() || opIt == operands.end() - 1) { + opIt = operands.begin(); + } + *opIt = std::const_pointer_cast(std::shared_ptr(new BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), *opIt, operands.back(), expression.getOperatorType()))); + operands.pop_back(); + ++opIt; + } + return operands.front(); + } + } + + + + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(BinaryRelationExpression const& expression, boost::any const& data) { + + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new BinaryRelationExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getRelationType()))); + } + } + + boost::any ReduceNestingVisitor::visit(VariableExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + boost::any ReduceNestingVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr operandExpression = boost::any_cast>(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { + std::shared_ptr operandExpression = boost::any_cast>(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + boost::any ReduceNestingVisitor::visit(BooleanLiteralExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + boost::any ReduceNestingVisitor::visit(IntegerLiteralExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + boost::any ReduceNestingVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { + return expression.getSharedPointer(); + } + + } +} diff --git a/src/storm/storage/expressions/ReduceNestingVisitor.h b/src/storm/storage/expressions/ReduceNestingVisitor.h new file mode 100644 index 000000000..f7c9c1566 --- /dev/null +++ b/src/storm/storage/expressions/ReduceNestingVisitor.h @@ -0,0 +1,36 @@ +#pragma once + +#include "storm/storage/expressions/Expression.h" +#include "storm/storage/expressions/ExpressionVisitor.h" + +namespace storm { + namespace expressions { + class ReduceNestingVisitor : public ExpressionVisitor { + public: + /*! + * Creates a new reduce nesting visitor. + */ + ReduceNestingVisitor(); + + /*! + * Reduces the nesting in the given expression + * + * @return A semantically equivalent expression with reduced nesting + */ + Expression reduceNesting(Expression const& expression); + + virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override; + virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override; + virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; + virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; + + private: + }; + } +} diff --git a/src/storm/storage/expressions/SubstitutionVisitor.h b/src/storm/storage/expressions/SubstitutionVisitor.h index c0885c0fe..99f0c2c18 100644 --- a/src/storm/storage/expressions/SubstitutionVisitor.h +++ b/src/storm/storage/expressions/SubstitutionVisitor.h @@ -39,7 +39,7 @@ namespace storm { virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override; virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override; - private: + protected: // A mapping of variables to expressions with which they shall be replaced. MapType const& variableToExpressionMapping; }; diff --git a/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp b/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp index 7f45240d7..d49b864dd 100644 --- a/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp +++ b/src/storm/storage/expressions/SyntacticalEqualityCheckVisitor.cpp @@ -93,7 +93,7 @@ namespace storm { boost::any SyntacticalEqualityCheckVisitor::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) { BaseExpression const& otherBaseExpression = boost::any_cast>(data).get(); - if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + if (otherBaseExpression.isUnaryBooleanFunctionExpression()) { UnaryBooleanFunctionExpression const& otherExpression = otherBaseExpression.asUnaryBooleanFunctionExpression(); bool result = expression.getOperatorType() == otherExpression.getOperatorType(); @@ -108,7 +108,7 @@ namespace storm { boost::any SyntacticalEqualityCheckVisitor::visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) { BaseExpression const& otherBaseExpression = boost::any_cast>(data).get(); - if (otherBaseExpression.isBinaryBooleanFunctionExpression()) { + if (otherBaseExpression.isUnaryNumericalFunctionExpression()) { UnaryNumericalFunctionExpression const& otherExpression = otherBaseExpression.asUnaryNumericalFunctionExpression(); bool result = expression.getOperatorType() == otherExpression.getOperatorType(); diff --git a/src/storm/storage/expressions/ToCppVisitor.cpp b/src/storm/storage/expressions/ToCppVisitor.cpp index b68de7132..70b76a467 100644 --- a/src/storm/storage/expressions/ToCppVisitor.cpp +++ b/src/storm/storage/expressions/ToCppVisitor.cpp @@ -142,6 +142,13 @@ namespace storm { expression.getSecondOperand()->accept(*this, data); stream << ")"; break; + case BinaryNumericalFunctionExpression::OperatorType::Modulo: + stream << "("; + expression.getFirstOperand()->accept(*this, data); + stream << " % "; + expression.getSecondOperand()->accept(*this, data); + stream << ")"; + break; } return boost::none; } diff --git a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp index d9098af2b..b3b0df9c3 100644 --- a/src/storm/storage/expressions/ToExprtkStringVisitor.cpp +++ b/src/storm/storage/expressions/ToExprtkStringVisitor.cpp @@ -100,6 +100,13 @@ namespace storm { expression.getSecondOperand()->accept(*this, data); stream << ")"; break; + case BinaryNumericalFunctionExpression::OperatorType::Modulo: + stream << "("; + expression.getFirstOperand()->accept(*this, data); + stream << "%"; + expression.getSecondOperand()->accept(*this, data); + stream << ")"; + break; case BinaryNumericalFunctionExpression::OperatorType::Max: stream << "max("; expression.getFirstOperand()->accept(*this, data); @@ -213,7 +220,7 @@ namespace storm { } boost::any ToExprtkStringVisitor::visit(RationalLiteralExpression const& expression, boost::any const&) { - stream << "(" << expression.getValue() << ")"; + stream << std::scientific << std::setprecision(std::numeric_limits::max_digits10) << "(" << expression.getValueAsDouble() << ")"; return boost::any(); } } diff --git a/src/storm/storage/expressions/ToRationalNumberVisitor.cpp b/src/storm/storage/expressions/ToRationalNumberVisitor.cpp index 15a8d61eb..c54758b12 100644 --- a/src/storm/storage/expressions/ToRationalNumberVisitor.cpp +++ b/src/storm/storage/expressions/ToRationalNumberVisitor.cpp @@ -48,6 +48,7 @@ namespace storm { RationalNumberType firstOperandAsRationalNumber = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); RationalNumberType secondOperandAsRationalNumber = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); RationalNumberType result; + uint_fast64_t exponentAsInteger; switch(expression.getOperatorType()) { case BinaryNumericalFunctionExpression::OperatorType::Plus: result = firstOperandAsRationalNumber + secondOperandAsRationalNumber; @@ -75,10 +76,12 @@ namespace storm { break; case BinaryNumericalFunctionExpression::OperatorType::Power: STORM_LOG_THROW(storm::utility::isInteger(secondOperandAsRationalNumber), storm::exceptions::InvalidArgumentException, "Exponent of power operator must be a positive integer."); - uint_fast64_t exponentAsInteger = storm::utility::convertNumber(secondOperandAsRationalNumber); + exponentAsInteger = storm::utility::convertNumber(secondOperandAsRationalNumber); result = storm::utility::pow(firstOperandAsRationalNumber, exponentAsInteger); return result; break; + default: + STORM_LOG_ASSERT(false, "Illegal operator type."); } // Return a dummy. This point must, however, never be reached. @@ -130,7 +133,7 @@ namespace storm { template boost::any ToRationalNumberVisitor::visit(IntegerLiteralExpression const& expression, boost::any const&) { - return RationalNumberType(carl::rationalize(static_cast(expression.getValue()))); + return RationalNumberType(carl::rationalize(static_cast(expression.getValue()))); } template diff --git a/src/storm/storage/expressions/Type.cpp b/src/storm/storage/expressions/Type.cpp index b51ac812a..b585b8eae 100644 --- a/src/storm/storage/expressions/Type.cpp +++ b/src/storm/storage/expressions/Type.cpp @@ -57,6 +57,14 @@ namespace storm { bool RationalType::isRationalType() const { return true; } + + bool BaseType::isArrayType() const { + return false; + } + + bool ArrayType::isArrayType() const { + return true; + } uint64_t BooleanType::getMask() const { return BooleanType::mask; @@ -102,6 +110,26 @@ namespace storm { return "rational"; } + ArrayType::ArrayType(Type elementType) : elementType(elementType) { + // Intentionally left empty + } + + Type ArrayType::getElementType() const { + return elementType; + } + + bool ArrayType::operator==(BaseType const& other) const { + return BaseType::operator==(other) && this->elementType == static_cast(other).getElementType(); + } + + uint64_t ArrayType::getMask() const { + return ArrayType::mask; + } + + std::string ArrayType::getStringRepresentation() const { + return "array[" + elementType.getStringRepresentation() + "]"; + } + bool operator<(BaseType const& first, BaseType const& second) { if (first.getMask() < second.getMask()) { return true; @@ -109,8 +137,11 @@ namespace storm { if (first.isBitVectorType() && second.isBitVectorType()) { return static_cast(first).getWidth() < static_cast(second).getWidth(); } + if (first.isArrayType() && second.isArrayType()) { + return static_cast(first).getElementType() < static_cast(second).getElementType(); + } return false; - } + } Type::Type() : manager(nullptr), innerType(nullptr) { // Intentionally left empty. @@ -144,6 +175,10 @@ namespace storm { return this->isIntegerType() || this->isRationalType(); } + bool Type::isArrayType() const { + return this->innerType->isArrayType(); + } + std::string Type::getStringRepresentation() const { return this->innerType->getStringRepresentation(); } @@ -151,6 +186,10 @@ namespace storm { std::size_t Type::getWidth() const { return static_cast(*this->innerType).getWidth(); } + + Type Type::getElementType() const { + return static_cast(*this->innerType).getElementType(); + } bool Type::isRationalType() const { return this->innerType->isRationalType(); diff --git a/src/storm/storage/expressions/Type.h b/src/storm/storage/expressions/Type.h index b173d5d53..58c02f64d 100644 --- a/src/storm/storage/expressions/Type.h +++ b/src/storm/storage/expressions/Type.h @@ -9,113 +9,8 @@ namespace storm { namespace expressions { - // Forward-declare expression manager class. class ExpressionManager; - - class BaseType { - public: - BaseType(); - virtual ~BaseType() = default; - - /*! - * Retrieves the mask that is associated with this type. - * - * @return The mask associated with this type. - */ - virtual uint64_t getMask() const = 0; - - /*! - * Checks whether two types are actually the same. - * - * @param other The type to compare with. - * @return True iff the types are the same. - */ - virtual bool operator==(BaseType const& other) const; - - /*! - * Returns a string representation of the type. - * - * @return A string representation of the type. - */ - virtual std::string getStringRepresentation() const = 0; - - virtual bool isErrorType() const; - virtual bool isBooleanType() const; - virtual bool isIntegerType() const; - virtual bool isBitVectorType() const; - virtual bool isRationalType() const; - }; - - class BooleanType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isBooleanType() const override; - - private: - static const uint64_t mask = (1ull << 60); - }; - - class IntegerType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isIntegerType() const override; - - private: - static const uint64_t mask = (1ull << 62); - }; - - class BitVectorType : public BaseType { - public: - /*! - * Creates a new bounded bitvector type with the given bit width. - * - * @param width The bit width of the type. - */ - BitVectorType(std::size_t width); - - /*! - * Retrieves the bit width of the bounded type. - * - * @return The bit width of the bounded type. - */ - std::size_t getWidth() const; - - virtual bool operator==(BaseType const& other) const override; - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isIntegerType() const override; - virtual bool isBitVectorType() const override; - - private: - static const uint64_t mask = (1ull << 61); - - // The bit width of the type. - std::size_t width; - }; - - class RationalType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isRationalType() const override; - - private: - static const uint64_t mask = (1ull << 63); - }; - - class ErrorType : public BaseType { - public: - virtual uint64_t getMask() const override; - virtual std::string getStringRepresentation() const override; - virtual bool isErrorType() const override; - - private: - static const uint64_t mask = 0; - }; - - bool operator<(BaseType const& first, BaseType const& second); + class BaseType; class Type { public: @@ -187,6 +82,13 @@ namespace storm { * @return True iff the type is a numerical one. */ bool isNumericalType() const; + + /*! + * Checks whether this type is an array type. + * + * @return True iff the type is an array. + */ + bool isArrayType() const; /*! * Retrieves the bit width of the type, provided that it is a bitvector type. @@ -195,6 +97,13 @@ namespace storm { */ std::size_t getWidth() const; + /*! + * Retrieves the element type of the type, provided that it is an Array type. + * + * @return The bit width of the bitvector type. + */ + Type getElementType() const; + /*! * Retrieves the manager of the type. * @@ -225,6 +134,130 @@ namespace storm { std::ostream& operator<<(std::ostream& stream, Type const& type); bool operator<(storm::expressions::Type const& type1, storm::expressions::Type const& type2); + + class BaseType { + public: + BaseType(); + virtual ~BaseType() = default; + + /*! + * Retrieves the mask that is associated with this type. + * + * @return The mask associated with this type. + */ + virtual uint64_t getMask() const = 0; + + /*! + * Checks whether two types are actually the same. + * + * @param other The type to compare with. + * @return True iff the types are the same. + */ + virtual bool operator==(BaseType const& other) const; + + /*! + * Returns a string representation of the type. + * + * @return A string representation of the type. + */ + virtual std::string getStringRepresentation() const = 0; + + virtual bool isErrorType() const; + virtual bool isBooleanType() const; + virtual bool isIntegerType() const; + virtual bool isBitVectorType() const; + virtual bool isRationalType() const; + virtual bool isArrayType() const; + }; + + class BooleanType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isBooleanType() const override; + + private: + static const uint64_t mask = (1ull << 60); + }; + + class IntegerType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isIntegerType() const override; + + private: + static const uint64_t mask = (1ull << 62); + }; + + class BitVectorType : public BaseType { + public: + /*! + * Creates a new bounded bitvector type with the given bit width. + * + * @param width The bit width of the type. + */ + BitVectorType(std::size_t width); + + /*! + * Retrieves the bit width of the bounded type. + * + * @return The bit width of the bounded type. + */ + std::size_t getWidth() const; + + virtual bool operator==(BaseType const& other) const override; + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isIntegerType() const override; + virtual bool isBitVectorType() const override; + + private: + static const uint64_t mask = (1ull << 61); + + // The bit width of the type. + std::size_t width; + }; + + class RationalType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isRationalType() const override; + + private: + static const uint64_t mask = (1ull << 63); + }; + + class ArrayType : public BaseType { + public: + ArrayType(Type elementType); + + Type getElementType() const; + + virtual bool operator==(BaseType const& other) const override; + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isArrayType() const override; + + private: + static const uint64_t mask = (1ull << 59); + + // The type of the array elements (can again be of type array). + Type elementType; + }; + + class ErrorType : public BaseType { + public: + virtual uint64_t getMask() const override; + virtual std::string getStringRepresentation() const override; + virtual bool isErrorType() const override; + + private: + static const uint64_t mask = 0; + }; + + bool operator<(BaseType const& first, BaseType const& second); } } diff --git a/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp b/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp index 3ed20d7b6..770c7b9f1 100644 --- a/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp +++ b/src/storm/storage/expressions/UnaryNumericalFunctionExpression.cpp @@ -74,6 +74,7 @@ namespace storm { operandEvaluation = operandSimplified->evaluateAsRational(); } + bool rationalToInteger = this->getOperatorType() == OperatorType::Floor || this->getOperatorType() == OperatorType::Ceil; if (operandSimplified->hasIntegerType()) { int_fast64_t value = 0; switch (this->getOperatorType()) { @@ -82,6 +83,15 @@ namespace storm { case OperatorType::Ceil: value = std::ceil(boost::get(operandEvaluation)); break; } return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), value)); + } else if (rationalToInteger) { + int_fast64_t value = 0; + switch (this->getOperatorType()) { + case OperatorType::Floor: value = storm::utility::convertNumber(storm::RationalNumber(carl::floor(boost::get(operandEvaluation)))); break; + case OperatorType::Ceil: value = storm::utility::convertNumber(storm::RationalNumber(carl::ceil(boost::get(operandEvaluation)))); break; + default: + STORM_LOG_ASSERT(false, "Unexpected rational to integer conversion."); + } + return std::shared_ptr(new IntegerLiteralExpression(this->getManager(), value)); } else { storm::RationalNumber value = storm::utility::zero(); switch (this->getOperatorType()) { diff --git a/src/storm/storage/expressions/Variable.cpp b/src/storm/storage/expressions/Variable.cpp index 675f1caef..0cccde8e0 100644 --- a/src/storm/storage/expressions/Variable.cpp +++ b/src/storm/storage/expressions/Variable.cpp @@ -16,7 +16,11 @@ namespace storm { } bool Variable::operator==(Variable const& other) const { +#ifndef NDEBUG return &this->getManager() == &other.getManager() && index == other.index; +#else + return index == other.index; +#endif } bool Variable::operator!=(Variable const& other) const { diff --git a/src/storm/storage/geometry/nativepolytopeconversion/SubsetEnumerator.cpp b/src/storm/storage/geometry/nativepolytopeconversion/SubsetEnumerator.cpp index c6103bf9d..2de1b1c45 100644 --- a/src/storm/storage/geometry/nativepolytopeconversion/SubsetEnumerator.cpp +++ b/src/storm/storage/geometry/nativepolytopeconversion/SubsetEnumerator.cpp @@ -84,7 +84,7 @@ namespace storm { } template< typename DataType> - bool SubsetEnumerator::trueFilter(std::vector const& subset, uint_fast64_t const& item, DataType const& data){ + bool SubsetEnumerator::trueFilter(std::vector const&, uint_fast64_t const&, DataType const&) { return true; } diff --git a/src/storm/storage/jani/ArrayEliminator.cpp b/src/storm/storage/jani/ArrayEliminator.cpp new file mode 100644 index 000000000..244eaa0b5 --- /dev/null +++ b/src/storm/storage/jani/ArrayEliminator.cpp @@ -0,0 +1,689 @@ +#include "storm/storage/jani/ArrayEliminator.h" + +#include + +#include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" + +#include "storm/storage/expressions/Expressions.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/OutOfRangeException.h" + +namespace storm { + + + + namespace jani { + namespace detail { + + class MaxArraySizeExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + MaxArraySizeExpressionVisitor() = default; + virtual ~MaxArraySizeExpressionVisitor() = default; + + std::size_t getMaxSize(storm::expressions::Expression const& expression, std::unordered_map const& arrayVariableSizeMap) { + return boost::any_cast(expression.accept(*this, &arrayVariableSizeMap)); + } + + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + if (expression.getCondition()->containsVariables()) { + return std::max(boost::any_cast(expression.getThenExpression()->accept(*this, data)), boost::any_cast(expression.getElseExpression()->accept(*this, data))); + } else { + if (expression.getCondition()->evaluateAsBool()) { + return boost::any_cast(expression.getThenExpression()->accept(*this, data)); + } + return boost::any_cast(expression.getElseExpression()->accept(*this, data)); + } + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return std::max(boost::any_cast(expression.getFirstOperand()->accept(*this, data)), boost::any_cast(expression.getSecondOperand()->accept(*this, data))); + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return std::max(boost::any_cast(expression.getFirstOperand()->accept(*this, data)), boost::any_cast(expression.getSecondOperand()->accept(*this, data))); + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + return std::max(boost::any_cast(expression.getFirstOperand()->accept(*this, data)), boost::any_cast(expression.getSecondOperand()->accept(*this, data))); + } + + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { + std::unordered_map const* arrayVariableSizeMap = boost::any_cast const*>(data); + if (expression.getType().isArrayType()) { + auto varIt = arrayVariableSizeMap->find(expression.getVariable()); + if (varIt != arrayVariableSizeMap->end()) { + return varIt->second; + } + } + return static_cast(0); + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return boost::any_cast(expression.getOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return boost::any_cast(expression.getOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const&, boost::any const&) override { + return 0; + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const&, boost::any const&) override { + return 0; + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const&, boost::any const&) override { + return 0; + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const&) override { + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + return static_cast(expression.size()->evaluateAsInt()); + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const&) override { + if (!expression.size()->containsVariables()) { + return static_cast(expression.size()->evaluateAsInt()); + } else { + auto vars = expression.size()->toExpression().getVariables(); + std::string variables = ""; + for (auto const& v : vars) { + if (variables != "") { + variables += ", "; + } + variables += v.getName(); + } + if (vars.size() == 1) { + variables = "variable " + variables; + } else { + variables = "variables " + variables; + } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unable to determine array size: Size of ConstructorArrayExpression '" << expression << "' still contains the " << variables << "."); + } + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const&, boost::any const&) override { + STORM_LOG_WARN("Found Array access expression within an array expression. This is not expected since nested arrays are currently not supported."); + return 0; + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const&, boost::any const&) override { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Found Function call expression within an array expression. This is not expected since functions are expected to be eliminated at this point."); + return 0; + } + + }; + + class ArrayExpressionEliminationVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + + typedef std::shared_ptr BaseExprPtr; + class ResultType { + public: + ResultType(ResultType const& other) = default; + ResultType(BaseExprPtr expression) : expression(expression), arrayOutOfBoundsMessage("") {} + ResultType(std::string arrayOutOfBoundsMessage) : expression(nullptr), arrayOutOfBoundsMessage(arrayOutOfBoundsMessage) {} + BaseExprPtr& expr() { + STORM_LOG_ASSERT(!isArrayOutOfBounds(), "Tried to get the result expression, but " << arrayOutOfBoundsMessage); + return expression; + }; + bool isArrayOutOfBounds() { return arrayOutOfBoundsMessage != ""; }; + std::string const& outOfBoundsMessage() const { return arrayOutOfBoundsMessage; } + private: + BaseExprPtr expression; + std::string arrayOutOfBoundsMessage; + }; + + ArrayExpressionEliminationVisitor(std::unordered_map> const& replacements, std::unordered_map const& sizes) : replacements(replacements), arraySizes(sizes) {} + virtual ~ArrayExpressionEliminationVisitor() = default; + + storm::expressions::Expression eliminate(storm::expressions::Expression const& expression) { + // here, data is the accessed index of the most recent array access expression. Initially, there is none. + auto res = boost::any_cast(expression.accept(*this, boost::any())); + STORM_LOG_THROW(!res.isArrayOutOfBounds(), storm::exceptions::OutOfRangeException, res.outOfBoundsMessage()); + STORM_LOG_ASSERT(!containsArrayExpression(res.expr()->toExpression()), "Expression still contains array expressions. Before: " << std::endl << expression << std::endl << "After:" << std::endl << res.expr()->toExpression()); + return res.expr()->simplify(); + } + + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + // for the condition expression, outer array accesses should not matter. + ResultType conditionResult = boost::any_cast(expression.getCondition()->accept(*this, boost::any())); + if (conditionResult.isArrayOutOfBounds()) { + return conditionResult; + } + + // We need to handle expressions of the kind '42(expression.getThenExpression()->accept(*this, data)); + ResultType elseResult = boost::any_cast(expression.getElseExpression()->accept(*this, data)); + if (thenResult.isArrayOutOfBounds()) { + if (elseResult.isArrayOutOfBounds()) { + return ResultType(thenResult.outOfBoundsMessage() + " and " + elseResult.outOfBoundsMessage()); + } else { + // Assume the else expression + return elseResult; + } + } else if (elseResult.isArrayOutOfBounds()) { + // Assume the then expression + return thenResult; + } else { + // If the arguments did not change, we simply push the expression itself. + if (conditionResult.expr().get() == expression.getCondition().get() && thenResult.expr().get() == expression.getThenExpression().get() && elseResult.expr().get() == expression.getElseExpression().get()) { + return ResultType(expression.getSharedPointer()); + } else { + return ResultType(std::const_pointer_cast(std::shared_ptr(new storm::expressions::IfThenElseExpression(expression.getManager(), thenResult.expr()->getType(), conditionResult.expr(), thenResult.expr(), elseResult.expr())))); + } + } + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "BinaryBooleanFunctionExpressions should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + ResultType firstResult = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + ResultType secondResult = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + if (firstResult.isArrayOutOfBounds()) { + return firstResult; + } else if (secondResult.isArrayOutOfBounds()) { + return secondResult; + } + + // If the arguments did not change, we simply push the expression itself. + if (firstResult.expr().get() == expression.getFirstOperand().get() && secondResult.expr().get() == expression.getSecondOperand().get()) { + return ResultType(expression.getSharedPointer()); + } else { + return ResultType(std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstResult.expr(), secondResult.expr(), expression.getOperatorType())))); + } + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "BinaryNumericalFunctionExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + ResultType firstResult = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + ResultType secondResult = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + if (firstResult.isArrayOutOfBounds()) { + return firstResult; + } else if (secondResult.isArrayOutOfBounds()) { + return secondResult; + } + + // If the arguments did not change, we simply push the expression itself. + if (firstResult.expr().get() == expression.getFirstOperand().get() && secondResult.expr().get() == expression.getSecondOperand().get()) { + return ResultType(expression.getSharedPointer()); + } else { + return ResultType(std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstResult.expr(), secondResult.expr(), expression.getOperatorType())))); + } + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "BinaryRelationExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + ResultType firstResult = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + ResultType secondResult = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + if (firstResult.isArrayOutOfBounds()) { + return firstResult; + } else if (secondResult.isArrayOutOfBounds()) { + return secondResult; + } + + // If the arguments did not change, we simply push the expression itself. + if (firstResult.expr().get() == expression.getFirstOperand().get() && secondResult.expr().get() == expression.getSecondOperand().get()) { + return ResultType(expression.getSharedPointer()); + } else { + return ResultType(std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryRelationExpression(expression.getManager(), expression.getType(), firstResult.expr(), secondResult.expr(), expression.getRelationType())))); + } + } + + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const& data) override { + if (expression.getType().isArrayType()) { + STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate array variable to basic variable, since it does not seem to be within an array access expression."); + uint64_t index = boost::any_cast(data); + STORM_LOG_ASSERT(replacements.find(expression.getVariable()) != replacements.end(), "Unable to find array variable " << expression << " in array replacements."); + auto const& arrayVarReplacements = replacements.at(expression.getVariable()); + if (index >= arrayVarReplacements.size()) { + return ResultType("Array index " + std::to_string(index) + " for variable " + expression.getVariableName() + " is out of bounds."); + } + return ResultType(arrayVarReplacements[index]->getExpressionVariable().getExpression().getBaseExpressionPointer()); + } else { + STORM_LOG_ASSERT(data.empty(), "VariableExpression of non-array variable should not be a subexpressions of array access expressions. However, the expression " << expression << " is."); + return ResultType(expression.getSharedPointer()); + } + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "UnaryBooleanFunctionExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + ResultType operandResult = boost::any_cast(expression.getOperand()->accept(*this, data)); + + if (operandResult.isArrayOutOfBounds()) { + return operandResult; + } + + // If the argument did not change, we simply push the expression itself. + if (operandResult.expr().get() == expression.getOperand().get()) { + return ResultType(expression.getSharedPointer()); + } else { + return ResultType(std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandResult.expr(), expression.getOperatorType())))); + } + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(data.empty(), "UnaryBooleanFunctionExpression should not be direct subexpressions of array access expressions. However, the expression " << expression << " is."); + + ResultType operandResult = boost::any_cast(expression.getOperand()->accept(*this, data)); + + if (operandResult.isArrayOutOfBounds()) { + return operandResult; + } + + // If the argument did not change, we simply push the expression itself. + if (operandResult.expr().get() == expression.getOperand().get()) { + return ResultType(expression.getSharedPointer()); + } else { + return ResultType(std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandResult.expr(), expression.getOperatorType())))); + } + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) override { + return ResultType(expression.getSharedPointer()); + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override { + return ResultType(expression.getSharedPointer()); + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override { + return ResultType(expression.getSharedPointer()); + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate ValueArrayExpression to element expression since it does not seem to be within an array access expression."); + uint64_t index = boost::any_cast(data); + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + if (index >= static_cast(expression.size()->evaluateAsInt())) { + return ResultType("Array index " + std::to_string(index) + " for ValueArrayExpression " + expression.toExpression().toString() + " is out of bounds."); + } + return ResultType(boost::any_cast(expression.at(index)->accept(*this, boost::any()))); + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_THROW(!data.empty(), storm::exceptions::NotSupportedException, "Unable to translate ValueArrayExpression to element expression since it does not seem to be within an array access expression."); + uint64_t index = boost::any_cast(data); + if (expression.size()->containsVariables()) { + STORM_LOG_WARN("Ignoring length of constructorArrayExpression " << expression << " as it still contains variables."); + } else { + if (index >= static_cast(expression.size()->evaluateAsInt())) { + return ResultType("Array index " + std::to_string(index) + " for ConstructorArrayExpression " + expression.toExpression().toString() + " is out of bounds."); + } + } + return ResultType(boost::any_cast(expression.at(index)->accept(*this, boost::any()))); + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const&) override { + if (expression.getSecondOperand()->containsVariables()) { + //get the size of the array expression + uint64_t size = MaxArraySizeExpressionVisitor().getMaxSize(expression.getFirstOperand()->toExpression(), arraySizes); + STORM_LOG_THROW(size > 0, storm::exceptions::NotSupportedException, "Unable to get size of array expression for array access " << expression << "."); + uint64_t index = size - 1; + storm::expressions::Expression result = boost::any_cast(expression.getFirstOperand()->accept(*this, index)).expr()->toExpression(); + while (index > 0) { + --index; + storm::expressions::Expression isCurrentIndex = boost::any_cast(expression.getSecondOperand()->accept(*this, boost::any())).expr()->toExpression() == expression.getManager().integer(index); + result = storm::expressions::ite(isCurrentIndex, + boost::any_cast(expression.getFirstOperand()->accept(*this, index)).expr()->toExpression(), + result); + } + return ResultType(result.getBaseExpressionPointer()); + } else { + uint64_t index = expression.getSecondOperand()->evaluateAsInt(); + return boost::any_cast(expression.getFirstOperand()->accept(*this, index)); + } + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const&, boost::any const&) override { + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Found Function call expression while eliminating array expressions. This is not expected since functions are expected to be eliminated at this point."); + return false; + } + + private: + std::unordered_map> const& replacements; + std::unordered_map const& arraySizes; + }; + + class MaxArraySizeDeterminer : public ConstJaniTraverser { + public: + + typedef std::unordered_map* MapPtr; + + MaxArraySizeDeterminer() = default; + virtual ~MaxArraySizeDeterminer() = default; + std::unordered_map getMaxSizes(Model const& model) { + // We repeatedly determine the max array sizes until convergence. This is to cover assignments of one array variable to another (A := B) + std::unordered_map result, previousResult; + do { + previousResult = result; + ConstJaniTraverser::traverse(model, &result); + } while (previousResult != result); + return result; + } + + virtual void traverse(Assignment const& assignment, boost::any const& data) override { + if (assignment.lValueIsVariable() && assignment.getExpressionVariable().getType().isArrayType()) { + auto& map = *boost::any_cast(data); + std::size_t newSize = MaxArraySizeExpressionVisitor().getMaxSize(assignment.getAssignedExpression(), map); + auto insertionRes = map.emplace(assignment.getExpressionVariable(), newSize); + if (!insertionRes.second) { + insertionRes.first->second = std::max(newSize, insertionRes.first->second); + } + } + } + + virtual void traverse(ArrayVariable const& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + auto& map = *boost::any_cast(data); + std::size_t newSize = MaxArraySizeExpressionVisitor().getMaxSize(variable.getInitExpression(), map); + auto insertionRes = map.emplace(variable.getExpressionVariable(), newSize); + if (!insertionRes.second) { + insertionRes.first->second = std::max(newSize, insertionRes.first->second); + } + } + } + }; + + + class ArrayVariableReplacer : public JaniTraverser { + public: + + typedef ArrayEliminatorData ResultType; + + ArrayVariableReplacer(storm::expressions::ExpressionManager& expressionManager, bool keepNonTrivialArrayAccess, std::unordered_map const& arrayVarToSizesMap) : expressionManager(expressionManager) , keepNonTrivialArrayAccess(keepNonTrivialArrayAccess), arraySizes(arrayVarToSizesMap) {} + + virtual ~ArrayVariableReplacer() = default; + ResultType replace(Model& model) { + + ResultType result; + arrayExprEliminator = std::make_unique(result.replacements, arraySizes); + for (auto const& arraySize : arraySizes) { + result.replacements.emplace(arraySize.first, std::vector(arraySize.second, nullptr)); + } + traverse(model, &result); + return result; + } + + virtual void traverse(Model& model, boost::any const& data) override { + + // Insert fresh basic variables for global array variables + auto& replacements = boost::any_cast(data)->replacements; + for (storm::jani::ArrayVariable const& arrayVariable : model.getGlobalVariables().getArrayVariables()) { + std::vector& basicVars = replacements.at(arrayVariable.getExpressionVariable()); + for (uint64_t index = 0; index < basicVars.size(); ++index) { + basicVars[index] = &model.addVariable(*getBasicVariable(arrayVariable, index)); + } + } + // drop all occuring array variables + auto elVars = model.getGlobalVariables().dropAllArrayVariables(); + auto& eliminatedArrayVariables = boost::any_cast(data)->eliminatedArrayVariables; + eliminatedArrayVariables.insert(eliminatedArrayVariables.end(), elVars.begin(), elVars.end()); + + // Make new variable replacements known to the expression eliminator + arrayExprEliminator = std::make_unique(replacements, arraySizes); + + for (auto& aut : model.getAutomata()) { + traverse(aut, data); + } + + // traversal of remaining components + if (model.hasInitialStatesRestriction()) { + model.setInitialStatesRestriction(arrayExprEliminator->eliminate(model.getInitialStatesRestriction())); + } + for (auto& nonTrivRew : model.getNonTrivialRewardExpressions()) { + nonTrivRew.second = arrayExprEliminator->eliminate(nonTrivRew.second); + } + } + + virtual void traverse(Automaton& automaton, boost::any const& data) override { + // No need to traverse the init restriction. + + // Insert fresh basic variables for local array variables + auto& replacements = boost::any_cast(data)->replacements; + for (storm::jani::ArrayVariable const& arrayVariable : automaton.getVariables().getArrayVariables()) { + std::vector& basicVars = replacements.at(arrayVariable.getExpressionVariable()); + for (uint64_t index = 0; index < basicVars.size(); ++index) { + basicVars[index] = &automaton.addVariable(*getBasicVariable(arrayVariable, index)); + } + } + // drop all occuring array variables + auto elVars = automaton.getVariables().dropAllArrayVariables(); + auto& eliminatedArrayVariables = boost::any_cast(data)->eliminatedArrayVariables; + eliminatedArrayVariables.insert(eliminatedArrayVariables.end(), elVars.begin(), elVars.end()); + + // Make new variable replacements known to the expression eliminator + arrayExprEliminator = std::make_unique(replacements, arraySizes); + + for (auto& loc : automaton.getLocations()) { + JaniTraverser::traverse(loc, data); + } + JaniTraverser::traverse(automaton.getEdgeContainer(), data); + + if (automaton.hasInitialStatesRestriction()) { + automaton.setInitialStatesRestriction(arrayExprEliminator->eliminate(automaton.getInitialStatesRestriction())); + } + } + + void traverse(TemplateEdge& templateEdge, boost::any const& data) override { + templateEdge.setGuard(arrayExprEliminator->eliminate(templateEdge.getGuard())); + for (auto& dest : templateEdge.getDestinations()) { + JaniTraverser::traverse(dest, data); + } + traverse(templateEdge.getAssignments(), data); + } + + + void traverse(Edge& edge, boost::any const& data) override { + if (edge.hasRate()) { + edge.setRate(arrayExprEliminator->eliminate(edge.getRate())); + } + for (auto& dest : edge.getDestinations()) { + JaniTraverser::traverse(dest, data); + } + } + + void traverse(EdgeDestination& edgeDestination, boost::any const&) override { + edgeDestination.setProbability(arrayExprEliminator->eliminate(edgeDestination.getProbability())); + } + + virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data) override { + auto const& replacements = boost::any_cast(data)->replacements; + + // Replace array occurrences in LValues and assigned expressions. + std::vector newAssignments; + if (!orderedAssignments.empty()) { + + int64_t level = orderedAssignments.getLowestLevel(); + std::unordered_map> collectedArrayAccessAssignments; + for (Assignment const& assignment : orderedAssignments) { + if (assignment.getLevel() != level) { + STORM_LOG_ASSERT(assignment.getLevel() > level, "Ordered Assignment does not have the expected order."); + for (auto const& arrayAssignments : collectedArrayAccessAssignments) { + insertLValueArrayAccessReplacements(arrayAssignments.second, replacements.at(arrayAssignments.first), level, newAssignments); + } + collectedArrayAccessAssignments.clear(); + level = assignment.getLevel(); + } + if (assignment.getLValue().isArrayAccess()) { + if (!keepNonTrivialArrayAccess || !assignment.getLValue().getArrayIndex().containsVariables()) { + auto insertionRes = collectedArrayAccessAssignments.emplace(assignment.getLValue().getArray().getExpressionVariable(), std::vector({&assignment})); + if (!insertionRes.second) { + insertionRes.first->second.push_back(&assignment); + } + } else { + // Keeping array access LValue + LValue newLValue(LValue(assignment.getLValue().getArray()), arrayExprEliminator->eliminate(assignment.getLValue().getArrayIndex())); + newAssignments.emplace_back(newLValue, arrayExprEliminator->eliminate(assignment.getAssignedExpression()), assignment.getLevel()); + } + } else if (assignment.getLValue().isVariable() && assignment.getVariable().isArrayVariable()) { + STORM_LOG_ASSERT(assignment.getAssignedExpression().getType().isArrayType(), "Assigning a non-array expression to an array variable..."); + std::vector const& arrayVariableReplacements = replacements.at(assignment.getExpressionVariable()); + // Get the maximum size of the array expression on the rhs + uint64_t rhsSize = MaxArraySizeExpressionVisitor().getMaxSize(assignment.getAssignedExpression(), arraySizes); + STORM_LOG_ASSERT(arrayVariableReplacements.size() >= rhsSize, "Array size too small."); + for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { + auto const& replacement = *arrayVariableReplacements[index]; + storm::expressions::Expression newRhs; + if (index < rhsSize) { + newRhs = std::make_shared(expressionManager, assignment.getAssignedExpression().getType().getElementType(), assignment.getAssignedExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression(); + } else { + newRhs = getOutOfBoundsValue(replacement); + } + newRhs = arrayExprEliminator->eliminate(newRhs); + newAssignments.emplace_back(LValue(replacement), newRhs, level); + } + } else { + newAssignments.emplace_back(assignment.getLValue(), arrayExprEliminator->eliminate(assignment.getAssignedExpression()), assignment.getLevel()); + } + } + for (auto const& arrayAssignments : collectedArrayAccessAssignments) { + insertLValueArrayAccessReplacements(arrayAssignments.second, replacements.at(arrayAssignments.first), level, newAssignments); + } + collectedArrayAccessAssignments.clear(); + orderedAssignments.clear(); + for (auto const& assignment : newAssignments) { + orderedAssignments.add(assignment); + } + } + } + + private: + + std::shared_ptr getBasicVariable(ArrayVariable const& arrayVariable, uint64_t index) const { + std::string name = arrayVariable.getExpressionVariable().getName() + "_at_" + std::to_string(index); + storm::expressions::Expression initValue; + if (arrayVariable.hasInitExpression()) { + initValue = arrayExprEliminator->eliminate(std::make_shared(expressionManager, arrayVariable.getExpressionVariable().getType().getElementType(), arrayVariable.getInitExpression().getBaseExpressionPointer(), expressionManager.integer(index).getBaseExpressionPointer())->toExpression()); + } + if (arrayVariable.getElementType() == ArrayVariable::ElementType::Int) { + storm::expressions::Variable exprVariable = expressionManager.declareIntegerVariable(name); + if (arrayVariable.hasElementTypeBound()) { + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient(), arrayVariable.getLowerElementTypeBound(), arrayVariable.getUpperElementTypeBound()); + } else { + return std::make_shared(name, exprVariable, arrayVariable.getLowerElementTypeBound(), arrayVariable.getUpperElementTypeBound()); + } + } else { + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient()); + } else { + return std::make_shared(name, exprVariable); + } + } + } else if (arrayVariable.getElementType() == ArrayVariable::ElementType::Real) { + storm::expressions::Variable exprVariable = expressionManager.declareRationalVariable(name); + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient()); + } else { + return std::make_shared(name, exprVariable); + } + } else if (arrayVariable.getElementType() == ArrayVariable::ElementType::Bool) { + storm::expressions::Variable exprVariable = expressionManager.declareBooleanVariable(name); + if (initValue.isInitialized()) { + return std::make_shared(name, exprVariable, initValue, arrayVariable.isTransient()); + } else { + return std::make_shared(name, exprVariable); + } + } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unhandled array base type."); + return nullptr; + } + + void insertLValueArrayAccessReplacements(std::vector const& arrayAccesses, std::vector const& arrayVariableReplacements, int64_t level, std::vector& newAssignments) const { + storm::expressions::Variable const& arrayVariable = arrayAccesses.front()->getLValue().getArray().getExpressionVariable(); + bool onlyConstantIndices = true; + for (auto const& aa : arrayAccesses) { + if (aa->getLValue().getArrayIndex().containsVariables()) { + onlyConstantIndices = false; + break; + } + } + if (onlyConstantIndices) { + for (auto const& aa : arrayAccesses) { + LValue lvalue(*arrayVariableReplacements.at(aa->getLValue().getArrayIndex().evaluateAsInt())); + newAssignments.emplace_back(lvalue, arrayExprEliminator->eliminate(aa->getAssignedExpression()), level); + } + } else { + for (uint64_t index = 0; index < arrayVariableReplacements.size(); ++index) { + storm::expressions::Expression assignedExpression = arrayVariableReplacements[index]->getExpressionVariable().getExpression(); + auto indexExpression = expressionManager.integer(index); + for (auto const& aa : arrayAccesses) { + assignedExpression = storm::expressions::ite(arrayExprEliminator->eliminate(aa->getLValue().getArrayIndex()) == indexExpression, arrayExprEliminator->eliminate(aa->getAssignedExpression()), assignedExpression); + } + newAssignments.emplace_back(LValue(*arrayVariableReplacements[index]), assignedExpression, level); + } + } + } + + storm::expressions::Expression getOutOfBoundsValue(Variable const& var) const { + if (var.hasInitExpression()) { + return var.getInitExpression(); + } + if (var.isBooleanVariable()) { + return expressionManager.boolean(false); + } + if (var.isBoundedIntegerVariable()) { + return var.asBoundedIntegerVariable().getLowerBound(); + } + if (var.isUnboundedIntegerVariable()) { + return expressionManager.integer(0); + } + if (var.isRealVariable()) { + return expressionManager.rational(0.0); + } + STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unhandled variabe type"); + return storm::expressions::Expression(); + } + + std::unique_ptr arrayExprEliminator; + storm::expressions::ExpressionManager& expressionManager; + bool const keepNonTrivialArrayAccess; + std::unordered_map const& arraySizes; + }; + } // namespace detail + + storm::expressions::Expression ArrayEliminatorData::transformExpression(storm::expressions::Expression const& arrayExpression) const { + std::unordered_map arraySizes; + for (auto const& r : replacements) { + arraySizes.emplace(r.first, r.second.size()); + } + detail::ArrayExpressionEliminationVisitor eliminator(replacements, arraySizes); + return eliminator.eliminate(arrayExpression); + } + + void ArrayEliminatorData::transformProperty(storm::jani::Property& property) const { + property = property.substitute([this](storm::expressions::Expression const& exp) {return transformExpression(exp);}); + } + + ArrayEliminatorData ArrayEliminator::eliminate(Model& model, bool keepNonTrivialArrayAccess) { + ArrayEliminatorData result; + // Only perform actions if there actually are arrays. + if (model.getModelFeatures().hasArrays()) { + auto sizes = detail::MaxArraySizeDeterminer().getMaxSizes(model); + result = detail::ArrayVariableReplacer(model.getExpressionManager(), keepNonTrivialArrayAccess, sizes).replace(model); + if (!keepNonTrivialArrayAccess) { + model.getModelFeatures().remove(ModelFeature::Arrays); + } + model.finalize(); + } + STORM_LOG_ASSERT(!containsArrayExpression(model), "the model still contains array expressions."); + return result; + } + } +} + diff --git a/src/storm/storage/jani/ArrayEliminator.h b/src/storm/storage/jani/ArrayEliminator.h new file mode 100644 index 000000000..26f4f3df8 --- /dev/null +++ b/src/storm/storage/jani/ArrayEliminator.h @@ -0,0 +1,39 @@ +#pragma once + + +#include "storm/storage/jani/Variable.h" +#include "storm/storage/expressions/Variable.h" + +namespace storm { + namespace expressions { + class Expression; + } + + namespace jani { + class Model; + class Property; + + struct ArrayEliminatorData { + std::vector> eliminatedArrayVariables; + std::unordered_map> replacements; + + // Transforms the given expression (which might contain array expressions) to an equivalent expression without array variables. + storm::expressions::Expression transformExpression(storm::expressions::Expression const& arrayExpression) const; + // Transforms the given property (which might contain array expressions) to an equivalent property without array variables. + void transformProperty(storm::jani::Property& property) const; + }; + + class ArrayEliminator { + public: + ArrayEliminator() = default; + + /*! + * Eliminates all array references in the given model by replacing them with basic variables. + */ + + ArrayEliminatorData eliminate(Model& model, bool keepNonTrivialArrayAccess = false); + + }; + } +} + diff --git a/src/storm/storage/jani/ArrayVariable.cpp b/src/storm/storage/jani/ArrayVariable.cpp new file mode 100644 index 000000000..997ab8d67 --- /dev/null +++ b/src/storm/storage/jani/ArrayVariable.cpp @@ -0,0 +1,66 @@ +#include "storm/storage/jani/ArrayVariable.h" + +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + +namespace storm { + namespace jani { + + ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType) : Variable(name, variable), elementType(elementType) { + // Intentionally left empty. + } + + ArrayVariable::ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType, storm::expressions::Expression const& initValue, bool transient) : Variable(name, variable, initValue, transient), elementType(elementType) { + // Intentionally left empty. + } + + void ArrayVariable::setLowerElementTypeBound(storm::expressions::Expression const& lowerBound) { + lowerElementTypeBound = lowerBound; + } + + void ArrayVariable::setUpperElementTypeBound(storm::expressions::Expression const& upperBound) { + upperElementTypeBound = upperBound; + } + + bool ArrayVariable::hasElementTypeBound() const { + return hasLowerElementTypeBound() || hasUpperElementTypeBound(); + } + + bool ArrayVariable::hasLowerElementTypeBound() const { + return lowerElementTypeBound.isInitialized(); + } + + bool ArrayVariable::hasUpperElementTypeBound() const { + return upperElementTypeBound.isInitialized(); + } + + storm::expressions::Expression const& ArrayVariable::getLowerElementTypeBound() const { + return lowerElementTypeBound; + } + + storm::expressions::Expression const& ArrayVariable::getUpperElementTypeBound() const { + return upperElementTypeBound; + } + + typename ArrayVariable::ElementType ArrayVariable::getElementType() const { + return elementType; + } + + std::unique_ptr ArrayVariable::clone() const { + return std::make_unique(*this); + } + + bool ArrayVariable::isArrayVariable() const { + return true; + } + + void ArrayVariable::substitute(std::map const& substitution) { + Variable::substitute(substitution); + if (hasLowerElementTypeBound()) { + setLowerElementTypeBound(substituteJaniExpression(getLowerElementTypeBound(), substitution)); + } + if (hasUpperElementTypeBound()) { + setUpperElementTypeBound(substituteJaniExpression(getUpperElementTypeBound(), substitution)); + } + } + } +} diff --git a/src/storm/storage/jani/ArrayVariable.h b/src/storm/storage/jani/ArrayVariable.h new file mode 100644 index 000000000..9420cd77a --- /dev/null +++ b/src/storm/storage/jani/ArrayVariable.h @@ -0,0 +1,75 @@ +#pragma once + +#include "storm/storage/jani/Variable.h" + +namespace storm { + namespace jani { + + class ArrayVariable : public Variable { + public: + + enum class ElementType {Bool, Int, Real}; + + /*! + * Creates an Array variable + */ + ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType); + + /*! + * Creates an Array variable with initial value + */ + ArrayVariable(std::string const& name, storm::expressions::Variable const& variable, ElementType const& elementType, storm::expressions::Expression const& initValue, bool transient); + + /*! + * Sets the lower bound to the values stored in this array + */ + void setLowerElementTypeBound(storm::expressions::Expression const& lowerBound); + + /*! + * Sets the upper bound to the values stored in this array + */ + void setUpperElementTypeBound(storm::expressions::Expression const& upperBound); + + /*! + * Returns true if there is either an upper bound or a lower bound + */ + bool hasElementTypeBound() const; + + /*! + * Returns true if there is an upper element type bound + */ + bool hasUpperElementTypeBound() const; + + /*! + * Returns true if there is a lower element type bound + */ + bool hasLowerElementTypeBound() const; + + /*! + * Returns the upper element type bound. The returned expression might not be initialized if there is no such bound. + */ + storm::expressions::Expression const& getUpperElementTypeBound() const; + + /*! + * Returns the lower element type bound. The returned expression might not be initialized if there is no such bound. + */ + storm::expressions::Expression const& getLowerElementTypeBound() const; + + std::pair const& getElementTypeBounds() const; + + + ElementType getElementType() const; + + virtual std::unique_ptr clone() const override; + virtual bool isArrayVariable() const override; + virtual void substitute(std::map const& substitution) override; + + + private: + ElementType elementType; + storm::expressions::Expression lowerElementTypeBound, upperElementTypeBound; + }; + + + } +} diff --git a/src/storm/storage/jani/Assignment.cpp b/src/storm/storage/jani/Assignment.cpp index 25fa036af..3235eacfe 100644 --- a/src/storm/storage/jani/Assignment.cpp +++ b/src/storm/storage/jani/Assignment.cpp @@ -1,5 +1,8 @@ #include "storm/storage/jani/Assignment.h" +#include "storm/storage/jani/LValue.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + #include "storm/storage/expressions/LinearityCheckVisitor.h" #include "storm/utility/macros.h" @@ -8,20 +11,36 @@ namespace storm { namespace jani { - Assignment::Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t level) : variable(variable), expression(expression), level(level) { - + Assignment::Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, int64_t level) : lValue(lValue), expression(expression), level(level) { + // Intentionally left empty } bool Assignment::operator==(Assignment const& other) const { - return this->isTransient() == other.isTransient() && this->getExpressionVariable() == other.getExpressionVariable() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()) && this->getLevel() == other.getLevel(); + return this->isTransient() == other.isTransient() && this->getLValue() == other.getLValue() && this->getAssignedExpression().isSyntacticallyEqual(other.getAssignedExpression()) && this->getLevel() == other.getLevel(); + } + + bool Assignment::lValueIsVariable() const { + return lValue.isVariable(); + } + + bool Assignment::lValueIsArrayAccess() const { + return lValue.isArrayAccess(); + } + + storm::jani::LValue& Assignment::getLValue() { + return lValue; + } + + storm::jani::LValue const& Assignment::getLValue() const { + return lValue; } storm::jani::Variable const& Assignment::getVariable() const { - return variable.get(); + return lValue.getVariable(); } storm::expressions::Variable const& Assignment::getExpressionVariable() const { - return variable.get().getExpressionVariable(); + return getVariable().getExpressionVariable(); } storm::expressions::Expression const& Assignment::getAssignedExpression() const { @@ -33,11 +52,14 @@ namespace storm { } bool Assignment::isTransient() const { - return this->variable.get().isTransient(); + return lValue.isTransient(); } void Assignment::substitute(std::map const& substitution) { - this->setAssignedExpression(this->getAssignedExpression().substitute(substitution)); + this->setAssignedExpression(substituteJaniExpression(this->getAssignedExpression(), substitution).simplify()); + if (lValue.isArrayAccess()) { + lValue = LValue(LValue(lValue.getArray()), substituteJaniExpression(lValue.getArrayIndex(), substitution).simplify()); + } } int64_t Assignment::getLevel() const { @@ -54,24 +76,24 @@ namespace storm { } std::ostream& operator<<(std::ostream& stream, Assignment const& assignment) { - stream << assignment.getVariable().getName() << " := " << assignment.getAssignedExpression(); + stream << assignment.getLValue() << " := " << assignment.getAssignedExpression(); return stream; } - bool AssignmentPartialOrderByLevelAndVariable::operator()(Assignment const& left, Assignment const& right) const { - return left.getLevel() < right.getLevel() || (left.getLevel() == right.getLevel() && left.getExpressionVariable() < right.getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(Assignment const& left, Assignment const& right) const { + return left.getLevel() < right.getLevel() || (left.getLevel() == right.getLevel() && left.getLValue() < right.getLValue()); } - bool AssignmentPartialOrderByLevelAndVariable::operator()(Assignment const& left, std::shared_ptr const& right) const { - return left.getLevel() < right->getLevel() || (left.getLevel() == right->getLevel() && left.getExpressionVariable() < right->getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(Assignment const& left, std::shared_ptr const& right) const { + return left.getLevel() < right->getLevel() || (left.getLevel() == right->getLevel() && left.getLValue() < right->getLValue()); } - bool AssignmentPartialOrderByLevelAndVariable::operator()(std::shared_ptr const& left, std::shared_ptr const& right) const { - return left->getLevel() < right->getLevel() || (left->getLevel() == right->getLevel() && left->getExpressionVariable() < right->getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(std::shared_ptr const& left, std::shared_ptr const& right) const { + return left->getLevel() < right->getLevel() || (left->getLevel() == right->getLevel() && left->getLValue() < right->getLValue()); } - bool AssignmentPartialOrderByLevelAndVariable::operator()(std::shared_ptr const& left, Assignment const& right) const { - return left->getLevel() < right.getLevel() || (left->getLevel() == right.getLevel() && left->getExpressionVariable() < right.getExpressionVariable()); + bool AssignmentPartialOrderByLevelAndLValue::operator()(std::shared_ptr const& left, Assignment const& right) const { + return left->getLevel() < right.getLevel() || (left->getLevel() == right.getLevel() && left->getLValue() < right.getLValue()); } } } diff --git a/src/storm/storage/jani/Assignment.h b/src/storm/storage/jani/Assignment.h index a4e2dbd23..ac616cd39 100644 --- a/src/storm/storage/jani/Assignment.h +++ b/src/storm/storage/jani/Assignment.h @@ -2,7 +2,7 @@ #include -#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/LValue.h" #include "storm/storage/expressions/Expression.h" namespace storm { @@ -11,19 +11,43 @@ namespace storm { class Assignment { public: /*! - * Creates an assignment of the given expression to the given variable. + * Creates an assignment of the given expression to the given LValue. */ - Assignment(storm::jani::Variable const& variable, storm::expressions::Expression const& expression, uint64_t index = 0); - + Assignment(storm::jani::LValue const& lValue, storm::expressions::Expression const& expression, int64_t level = 0); + + Assignment(Assignment const&) = default; bool operator==(Assignment const& other) const; + /*! - * Retrieves the expression variable that is written in this assignment. + * Returns true if the lValue is a variable + */ + bool lValueIsVariable() const; + + /*! + * Returns true if the lValue is an array access + */ + bool lValueIsArrayAccess() const; + + /*! + * Retrieves the lValue that is written in this assignment. + */ + storm::jani::LValue const& getLValue() const; + + /*! + * Retrieves the lValue that is written in this assignment. + */ + storm::jani::LValue& getLValue(); + + /*! + * Retrieves the Variable that is written in this assignment. + * This assumes that the lValue is a variable. */ storm::jani::Variable const& getVariable() const; - + /*! * Retrieves the expression variable that is written in this assignment. + * This assumes that the lValue is a variable. */ storm::expressions::Variable const& getExpressionVariable() const; @@ -33,7 +57,7 @@ namespace storm { storm::expressions::Expression const& getAssignedExpression() const; /*! - * Sets a new expression that is assigned to the target variable. + * Sets a new expression that is assigned to the target LValue. */ void setAssignedExpression(storm::expressions::Expression const& expression); @@ -65,21 +89,21 @@ namespace storm { friend std::ostream& operator<<(std::ostream& stream, Assignment const& assignment); private: - // The variable being assigned. - std::reference_wrapper variable; + // The lValue being assigned. + LValue lValue; - // The expression that is being assigned to the variable. + // The expression that is being assigned to the lValue. storm::expressions::Expression expression; // The level of the assignment. - uint64_t level; + int64_t level; }; /*! - * This functor enables ordering the assignments first by the assignment level and then by variable. + * This functor enables ordering the assignments first by the assignment level and then by lValue. * Note that this is a partial order. */ - struct AssignmentPartialOrderByLevelAndVariable { + struct AssignmentPartialOrderByLevelAndLValue { bool operator()(Assignment const& left, Assignment const& right) const; bool operator()(Assignment const& left, std::shared_ptr const& right) const; bool operator()(std::shared_ptr const& left, std::shared_ptr const& right) const; diff --git a/src/storm/storage/jani/Automaton.cpp b/src/storm/storage/jani/Automaton.cpp index 8715a27a8..08cec4105 100644 --- a/src/storm/storage/jani/Automaton.cpp +++ b/src/storm/storage/jani/Automaton.cpp @@ -3,56 +3,18 @@ #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/TemplateEdge.h" #include "storm/storage/jani/Location.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/utility/macros.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/InvalidTypeException.h" +#include "storm/exceptions/NotSupportedException.h" namespace storm { namespace jani { - namespace detail { - Edges::Edges(iterator it, iterator ite) : it(it), ite(ite) { - // Intentionally left empty. - } - - Edges::iterator Edges::begin() const { - return it; - } - - Edges::iterator Edges::end() const { - return ite; - } - - bool Edges::empty() const { - return it == ite; - } - - std::size_t Edges::size() const { - return std::distance(it, ite); - } - - ConstEdges::ConstEdges(const_iterator it, const_iterator ite) : it(it), ite(ite) { - // Intentionally left empty. - } - - ConstEdges::const_iterator ConstEdges::begin() const { - return it; - } - - ConstEdges::const_iterator ConstEdges::end() const { - return ite; - } - - bool ConstEdges::empty() const { - return it == ite; - } - std::size_t ConstEdges::size() const { - return std::distance(it, ite); - } - } Automaton::Automaton(std::string const& name, storm::expressions::Variable const& locationExpressionVariable) : name(name), locationExpressionVariable(locationExpressionVariable) { // Add a sentinel element to the mapping from locations to starting indices. @@ -72,6 +34,8 @@ namespace storm { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); + } else if (variable.isArrayVariable()) { + return addVariable(variable.asArrayVariable()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); } @@ -92,6 +56,14 @@ namespace storm { RealVariable const& Automaton::addVariable(RealVariable const& variable) { return variables.addVariable(variable); } + + ArrayVariable const& Automaton::addVariable(ArrayVariable const& variable) { + return variables.addVariable(variable); + } + + bool Automaton::hasVariable(std::string const& name) const { + return variables.hasVariable(name); + } VariableSet& Automaton::getVariables() { return variables; @@ -113,6 +85,20 @@ namespace storm { return variables.hasTransientVariable(); } + FunctionDefinition const& Automaton::addFunctionDefinition(FunctionDefinition const& functionDefinition) { + auto insertionRes = functionDefinitions.emplace(functionDefinition.getName(), functionDefinition); + STORM_LOG_THROW(insertionRes.second, storm::exceptions::InvalidArgumentException, " a function with the name " << functionDefinition.getName() << " already exists in this automaton (" << this->getName() << ")"); + return insertionRes.first->second; + } + + std::unordered_map const& Automaton::getFunctionDefinitions() const { + return functionDefinitions; + } + + std::unordered_map& Automaton::getFunctionDefinitions() { + return functionDefinitions; + } + bool Automaton::hasLocation(std::string const& name) const { return locationToIndex.find(name) != locationToIndex.end(); } @@ -176,7 +162,7 @@ namespace storm { } Edge const& Automaton::getEdge(uint64_t index) const { - return edges[index]; + return edges.getConcreteEdges()[index]; } Automaton::Edges Automaton::getEdgesFromLocation(std::string const& name) { @@ -305,44 +291,38 @@ namespace storm { return ConstEdges(it1, it2); } + EdgeContainer const& Automaton::getEdgeContainer() const { + return edges; + } + + EdgeContainer& Automaton::getEdgeContainer() { + return edges; + } + void Automaton::addEdge(Edge const& edge) { STORM_LOG_THROW(edge.getSourceLocationIndex() < locations.size(), storm::exceptions::InvalidArgumentException, "Cannot add edge with unknown source location index '" << edge.getSourceLocationIndex() << "'."); - - // Find the right position for the edge and insert it properly. - auto posIt = edges.begin(); - std::advance(posIt, locationToStartingIndex[edge.getSourceLocationIndex() + 1]); - edges.insert(posIt, edge); - + assert(validate()); + + edges.insertEdge(edge, locationToStartingIndex[edge.getSourceLocationIndex()], locationToStartingIndex[edge.getSourceLocationIndex() + 1]); + // Update the set of action indices of this automaton. + actionIndices.insert(edge.getActionIndex()); + // Now update the starting indices of all subsequent locations. for (uint64_t locationIndex = edge.getSourceLocationIndex() + 1; locationIndex < locationToStartingIndex.size(); ++locationIndex) { ++locationToStartingIndex[locationIndex]; } - - // Sort all edges form the source location of the newly introduced edge by their action indices. - auto it = edges.begin(); - std::advance(it, locationToStartingIndex[edge.getSourceLocationIndex()]); - auto ite = edges.begin(); - std::advance(ite, locationToStartingIndex[edge.getSourceLocationIndex() + 1]); - std::sort(it, ite, [] (Edge const& a, Edge const& b) { return a.getActionIndex() < b.getActionIndex(); } ); - - // Update the set of action indices of this automaton. - actionIndices.insert(edge.getActionIndex()); } std::vector& Automaton::getEdges() { - return edges; + return edges.getConcreteEdges(); } std::vector const& Automaton::getEdges() const { - return edges; + return edges.getConcreteEdges(); } std::set Automaton::getActionIndices() const { - std::set result; - for (auto const& edge : edges) { - result.insert(edge.getActionIndex()); - } - return result; + return edges.getActionIndices(); } uint64_t Automaton::getNumberOfLocations() const { @@ -368,6 +348,20 @@ namespace storm { return initialStatesRestriction.isInitialized(); } + bool Automaton::hasNonTrivialInitialStates() const { + if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) { + return true; + } + + for (auto const& variable : this->getVariables()) { + if (variable.hasInitExpression() && !variable.isTransient()) { + return true; + } + } + + return false; + } + storm::expressions::Expression const& Automaton::getInitialStatesRestriction() const { return initialStatesRestriction; } @@ -380,7 +374,7 @@ namespace storm { storm::expressions::Expression result; // Add initial state restriction if there is one. - if (this->hasInitialStatesRestriction()) { + if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) { result = this->getInitialStatesRestriction(); } @@ -403,6 +397,27 @@ namespace storm { return result; } + bool Automaton::hasTrivialInitialStatesExpression() const { + if (this->hasInitialStatesRestriction()) { + return false; + } + + bool result = true; + for (auto const& variable : this->getVariables()) { + if (variable.isTransient()) { + continue; + } + + result &= variable.hasInitExpression(); + + if (!result) { + break; + } + } + + return result; + } + bool Automaton::hasEdgeLabeledWithActionIndex(uint64_t actionIndex) const { return actionIndices.find(actionIndex) != actionIndices.end(); } @@ -416,45 +431,38 @@ namespace storm { } void Automaton::substitute(std::map const& substitution) { + for (auto& functionDefinition : this->getFunctionDefinitions()) { + functionDefinition.second.substitute(substitution); + } for (auto& variable : this->getVariables().getBoundedIntegerVariables()) { variable.substitute(substitution); } + for (auto& variable : this->getVariables().getArrayVariables()) { + variable.substitute(substitution); + } for (auto& location : this->getLocations()) { location.substitute(substitution); } - this->setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(substitution)); + this->setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), substitution)); - for (auto& templateEdge : templateEdges) { - templateEdge->substitute(substitution); - } - for (auto& edge : this->getEdges()) { - edge.substitute(substitution); - } + edges.substitute(substitution); } void Automaton::registerTemplateEdge(std::shared_ptr const& te) { - templateEdges.insert(te); + edges.insertTemplateEdge(te); } void Automaton::changeAssignmentVariables(std::map> const& remapping) { for (auto& location : locations) { location.changeAssignmentVariables(remapping); } - for (auto& templateEdge : templateEdges) { - templateEdge->changeAssignmentVariables(remapping); - } + edges.changeAssignmentVariables(remapping); } void Automaton::finalize(Model const& containingModel) { //simplifyIndexedAssignments(); - templateEdges.clear(); - for (auto& edge : edges) { - templateEdges.insert(edge.getTemplateEdge()); - } - for (auto& templateEdge : templateEdges) { - templateEdge->finalize(containingModel); - } + edges.finalize(containingModel); } bool Automaton::containsVariablesOnlyInProbabilitiesOrTransientAssignments(std::set const& variables) const { @@ -481,8 +489,38 @@ namespace storm { } void Automaton::pushEdgeAssignmentsToDestinations() { - for (auto& templateEdge : templateEdges) { - templateEdge->pushAssignmentsToDestinations(); + edges.pushAssignmentsToDestinations(); + } + + void Automaton::pushTransientRealLocationAssignmentsToEdges() { + std::set> encounteredTemplateEdges; + + for (uint64_t locationIndex = 0; locationIndex < locations.size(); ++locationIndex) { + auto& location = locations[locationIndex]; + auto edges = this->getEdgesFromLocation(locationIndex); + + storm::jani::Location newLocation(location.getName()); + bool createNewLocation = true; + for (auto& edge : edges) { + STORM_LOG_THROW(encounteredTemplateEdges.find(edge.getTemplateEdge()) == encounteredTemplateEdges.end(), storm::exceptions::NotSupportedException, "Pushing location assignments to edges is only supported for automata with unique template edges."); + + auto& templateEdge = edge.getTemplateEdge(); + encounteredTemplateEdges.insert(templateEdge); + + for (auto const& assignment : location.getAssignments().getTransientAssignments()) { + if (assignment.getVariable().isTransient() && assignment.getVariable().isRealVariable()) { + templateEdge->addTransientAssignment(assignment, true); + } else if (createNewLocation) { + newLocation.addTransientAssignment(assignment); + } + } + + if (createNewLocation) { + createNewLocation = false; + } + } + + location = std::move(newLocation); } } @@ -495,26 +533,20 @@ namespace storm { return false; } - void Automaton::liftTransientEdgeDestinationAssignments() { - for (auto& templateEdge : templateEdges) { - templateEdge->liftTransientDestinationAssignments(); - } + void Automaton::liftTransientEdgeDestinationAssignments(int64_t maxLevel) { + edges.liftTransientDestinationAssignments(maxLevel); } - void Automaton::simplifyIndexedAssignments() { - // TODO has to be fixed. - for (auto& edge : edges) { - edge.simplifyIndexedAssignments(variables); + bool Automaton::validate() const { + assert(locationToStartingIndex.size() == locations.size() + 1); + for(uint64_t i = 0; i < locations.size(); i++) { + assert(locationToStartingIndex[i] <= locationToStartingIndex[i+1]); } + return true; } - bool Automaton::usesAssignmentLevels() const { - for (auto const& edge : this->getEdges()) { - if (edge.usesAssignmentLevels()) { - return true; - } - } - return false; + bool Automaton::usesAssignmentLevels(bool onlyTransient) const { + return edges.usesAssignmentLevels(onlyTransient); } bool Automaton::isLinear() const { @@ -523,18 +555,16 @@ namespace storm { for (auto const& location : this->getLocations()) { result &= location.isLinear(); } - - for (auto const& templateEdge : templateEdges) { - result &= templateEdge->isLinear(); + if (result) { + result &= edges.isLinear(); } - return result; } void Automaton::restrictToEdges(boost::container::flat_set const& edgeIndices) { - std::vector oldEdges = this->edges; + std::vector oldEdges = this->edges.getConcreteEdges(); - this->edges.clear(); + this->edges.clearConcreteEdges(); actionIndices.clear(); for (auto& e : locationToStartingIndex) { e = 0; diff --git a/src/storm/storage/jani/Automaton.h b/src/storm/storage/jani/Automaton.h index 3ca635f7b..0dd74eeb9 100644 --- a/src/storm/storage/jani/Automaton.h +++ b/src/storm/storage/jani/Automaton.h @@ -7,7 +7,9 @@ #include #include "storm/storage/jani/VariableSet.h" - +#include "storm/storage/jani/TemplateEdgeContainer.h" +#include "storm/storage/jani/EdgeContainer.h" +#include "storm/storage/jani/FunctionDefinition.h" namespace storm { namespace jani { @@ -16,73 +18,8 @@ namespace storm { class Edge; class TemplateEdge; class Location; - - namespace detail { - class Edges { - public: - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - - Edges(iterator it, iterator ite); - - /*! - * Retrieves an iterator to the edges. - */ - iterator begin() const; - - /*! - * Retrieves an end iterator to the edges. - */ - iterator end() const; - - /*! - * Determines whether this set of edges is empty. - */ - bool empty() const; - - /*! - * Retrieves the number of edges. - */ - std::size_t size() const; - - private: - iterator it; - iterator ite; - }; - - class ConstEdges { - public: - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - - ConstEdges(const_iterator it, const_iterator ite); - - /*! - * Retrieves an iterator to the edges. - */ - const_iterator begin() const; - - /*! - * Retrieves an end iterator to the edges. - */ - const_iterator end() const; - /*! - * Determines whether this set of edges is empty. - */ - bool empty() const; - /*! - * Retrieves the number of edges. - */ - std::size_t size() const; - - private: - const_iterator it; - const_iterator ite; - }; - } - class Model; class Automaton { @@ -133,6 +70,11 @@ namespace storm { */ RealVariable const& addVariable(RealVariable const& variable); + /*! + * Adds the given array variable to this automaton. + */ + ArrayVariable const& addVariable(ArrayVariable const& variable); + /*! * Retrieves the variables of this automaton. */ @@ -142,6 +84,8 @@ namespace storm { * Retrieves the variables of this automaton. */ VariableSet const& getVariables() const; + + bool hasVariable(std::string const& name) const; /*! * Retrieves all expression variables used by this automaton. @@ -155,6 +99,21 @@ namespace storm { */ bool hasTransientVariable() const; + /*! + * Adds the given function definition + */ + FunctionDefinition const& addFunctionDefinition(FunctionDefinition const& functionDefinition); + + /*! + * Retrieves all function definitions of this automaton + */ + std::unordered_map const& getFunctionDefinitions() const; + + /*! + * Retrieves all function definitions of this automaton + */ + std::unordered_map& getFunctionDefinitions(); + /*! * Retrieves whether the automaton has a location with the given name. */ @@ -253,6 +212,16 @@ namespace storm { */ ConstEdges getEdgesFromLocation(uint64_t locationIndex, uint64_t actionIndex) const; + /*! + * Retrieves the container of all edges of this automaton. + */ + EdgeContainer const& getEdgeContainer() const; + + /*! + * Retrieves the container of all edges of this automaton. + */ + EdgeContainer& getEdgeContainer(); + /*! * Adds the template edge to the list of edges */ @@ -262,6 +231,8 @@ namespace storm { * Adds an edge to the automaton. */ void addEdge(Edge const& edge); + + bool validate() const; /*! * Retrieves the edges of the automaton. @@ -298,6 +269,11 @@ namespace storm { */ bool hasInitialStatesRestriction() const; + /*! + * Retrieves whether this automaton has non-trivial initial states. + */ + bool hasNonTrivialInitialStates() const; + /*! * Gets the expression restricting the legal initial values of the automaton's variables. */ @@ -313,6 +289,12 @@ namespace storm { */ storm::expressions::Expression getInitialStatesExpression() const; + /*! + * Retrieves whether the initial states expression is trivial in the sense that the automaton has no initial + * states restriction and all non-transient variables have initial values. + */ + bool hasTrivialInitialStatesExpression() const; + /*! * Retrieves whether there is an edge labeled with the action with the given index in this automaton. */ @@ -355,6 +337,12 @@ namespace storm { */ void pushEdgeAssignmentsToDestinations(); + /*! + * Pushes the assignments to real-valued transient variables to the edges. + * Note: This is currently only supported if the template edges are uniquely coupled with one source location. + */ + void pushTransientRealLocationAssignmentsToEdges(); + /*! * Retrieves whether there is any transient edge destination assignment in the automaton. */ @@ -363,12 +351,12 @@ namespace storm { /*! * Lifts the common edge destination assignments to edge assignments. */ - void liftTransientEdgeDestinationAssignments(); + void liftTransientEdgeDestinationAssignments(int64_t maxLevel = 0); /*! * Retrieves whether the automaton uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; void simplifyIndexedAssignments(); @@ -394,6 +382,10 @@ namespace storm { /// The set of variables of this automaton. VariableSet variables; + /// A mapping from names to function definitions + /// Since we use an unordered_map, references to function definitions will not get invalidated when more function definitions are added + std::unordered_map functionDefinitions; + /// The locations of the automaton. std::vector locations; @@ -401,10 +393,7 @@ namespace storm { std::unordered_map locationToIndex; /// All edges of the automaton - std::vector edges; - - /// The templates for the contained edges. - std::unordered_set> templateEdges; + EdgeContainer edges; /// A mapping from location indices to the starting indices. If l is mapped to i, it means that the edges /// leaving location l start at index i of the edges vector. diff --git a/src/storm/storage/jani/BoundedIntegerVariable.cpp b/src/storm/storage/jani/BoundedIntegerVariable.cpp index 5b851b127..88c9ad9ad 100644 --- a/src/storm/storage/jani/BoundedIntegerVariable.cpp +++ b/src/storm/storage/jani/BoundedIntegerVariable.cpp @@ -1,5 +1,6 @@ #include "storm/storage/jani/BoundedIntegerVariable.h" #include "storm/exceptions/NotImplementedException.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/utility/macros.h" namespace storm { @@ -29,6 +30,10 @@ namespace storm { this->lowerBound = expression; } + bool BoundedIntegerVariable::hasLowerBound() const { + return this->lowerBound.isInitialized(); + } + storm::expressions::Expression const& BoundedIntegerVariable::getUpperBound() const { return upperBound; } @@ -37,8 +42,23 @@ namespace storm { this->upperBound = expression; } + bool BoundedIntegerVariable::hasUpperBound() const { + return this->upperBound.isInitialized(); + } + storm::expressions::Expression BoundedIntegerVariable::getRangeExpression() const { - return this->getLowerBound() <= this->getExpressionVariable() && this->getExpressionVariable() <= this->getUpperBound(); + storm::expressions::Expression range; + if (this->hasLowerBound()) { + range = this->getLowerBound() <= this->getExpressionVariable(); + } + if (this->hasUpperBound()) { + if (range.isInitialized()) { + range = range && this->getExpressionVariable() <= this->getUpperBound(); + } else { + range = this->getExpressionVariable() <= this->getUpperBound(); + } + } + return range; } bool BoundedIntegerVariable::isBoundedIntegerVariable() const { @@ -47,17 +67,20 @@ namespace storm { void BoundedIntegerVariable::substitute(std::map const& substitution) { Variable::substitute(substitution); - this->setLowerBound(this->getLowerBound().substitute(substitution)); - this->setUpperBound(this->getUpperBound().substitute(substitution)); + if (this->hasLowerBound()) { + this->setLowerBound(substituteJaniExpression(this->getLowerBound(), substitution)); + } + if (this->hasUpperBound()) { + this->setUpperBound(substituteJaniExpression(this->getUpperBound(), substitution)); + } } std::shared_ptr makeBoundedIntegerVariable(std::string const& name, storm::expressions::Variable const& variable, boost::optional initValue, bool transient, boost::optional lowerBound, boost::optional upperBound) { - STORM_LOG_THROW(lowerBound && upperBound, storm::exceptions::NotImplementedException, "Jani Bounded Integer variables (for now) have to be bounded from both sides"); if (initValue) { - return std::make_shared(name, variable, initValue.get(), transient, lowerBound.get(), upperBound.get()); + return std::make_shared(name, variable, initValue.get(), transient, lowerBound ? lowerBound.get() : storm::expressions::Expression(), upperBound ? upperBound.get() : storm::expressions::Expression()); } else { assert(!transient); - return std::make_shared(name, variable, lowerBound.get(), upperBound.get()); + return std::make_shared(name, variable, lowerBound ? lowerBound.get() : storm::expressions::Expression(), upperBound ? upperBound.get() : storm::expressions::Expression()); } } } diff --git a/src/storm/storage/jani/BoundedIntegerVariable.h b/src/storm/storage/jani/BoundedIntegerVariable.h index 1f201ba2e..221d9dceb 100644 --- a/src/storm/storage/jani/BoundedIntegerVariable.h +++ b/src/storm/storage/jani/BoundedIntegerVariable.h @@ -33,6 +33,11 @@ namespace storm { */ void setLowerBound(storm::expressions::Expression const& expression); + /*! + * Retrieves whether the variable has a lower bound. + */ + bool hasLowerBound() const; + /*! * Retrieves the expression defining the upper bound of the variable. */ @@ -43,6 +48,11 @@ namespace storm { */ void setUpperBound(storm::expressions::Expression const& expression); + /*! + * Retrieves whether the variable has an upper bound. + */ + bool hasUpperBound() const; + /*! * Retrieves an expression characterizing the legal range of the bounded integer variable. */ diff --git a/src/storm/storage/jani/Edge.cpp b/src/storm/storage/jani/Edge.cpp index 18fb35f4f..301c695a0 100644 --- a/src/storm/storage/jani/Edge.cpp +++ b/src/storm/storage/jani/Edge.cpp @@ -1,6 +1,7 @@ #include "storm/storage/jani/Edge.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -66,6 +67,10 @@ namespace storm { return destinations; } + std::vector& Edge::getDestinations() { + return destinations; + } + std::size_t Edge::getNumberOfDestinations() const { return destinations.size(); } @@ -76,7 +81,7 @@ namespace storm { void Edge::substitute(std::map const& substitution) { if (this->hasRate()) { - this->setRate(this->getRate().substitute(substitution)); + this->setRate(substituteJaniExpression(this->getRate(), substitution)); } for (auto& destination : destinations) { destination.substitute(substitution); @@ -99,8 +104,8 @@ namespace storm { return templateEdge->hasTransientEdgeDestinationAssignments(); } - bool Edge::usesAssignmentLevels() const { - return templateEdge->usesAssignmentLevels(); + bool Edge::usesAssignmentLevels(bool onlyTransient) const { + return templateEdge->usesAssignmentLevels(onlyTransient); } void Edge::simplifyIndexedAssignments(VariableSet const& localVars) { @@ -116,8 +121,59 @@ namespace storm { } } + int64_t const& Edge::getLowestAssignmentLevel() const { + return templateEdge->getLowestAssignmentLevel(); + } + + int64_t const& Edge::getHighestAssignmentLevel() const { + return templateEdge->getHighestAssignmentLevel(); + } + + void Edge::setTemplateEdge(std::shared_ptr const& newTe) { + templateEdge = newTe; + uint64_t i = 0; + std::vector newdestinations; + + assert(destinations.size() == newTe->getNumberOfDestinations()); + for (auto& destination : destinations) { + newdestinations.emplace_back(destination.getLocationIndex(), destination.getProbability(), newTe->getDestination(i)); + //destination.updateTemplateEdgeDestination(newTe->getDestination(i)); + ++i; + } + destinations = newdestinations; + } + std::shared_ptr const& Edge::getTemplateEdge() { return templateEdge; } + + std::ostream& operator<<(std::ostream& stream, Edge const& edge) { + stream << "[" << (edge.hasSilentAction() ? "" : ("action_id: " + std::to_string(edge.getActionIndex()))) << "]"; + stream << "guard: '" << edge.getGuard() << "'\t from_location_id: " << edge.getSourceLocationIndex(); + if (edge.hasRate()) { + stream << " with rate '" << edge.getRate() << "'"; + } + if (edge.getDestinations().empty()) { + stream << "without any destination"; + } else { + stream << " to ... [" << std::endl; + for (auto const& dest : edge.getDestinations()) { + stream << "\tlocation_id: " << dest.getLocationIndex() << " with probability '" << dest.getProbability() << "' and updates: "; + if (dest.getOrderedAssignments().empty()) { + stream << "none" << std::endl; + } + bool first = true; + for (auto const& a : dest.getOrderedAssignments()) { + if (first) { + first = false; + stream << a; + } + stream << ", " << a; + } + } + stream << "]"; + } + return stream; + } } } diff --git a/src/storm/storage/jani/Edge.h b/src/storm/storage/jani/Edge.h index 5585296e6..099f5ca14 100644 --- a/src/storm/storage/jani/Edge.h +++ b/src/storm/storage/jani/Edge.h @@ -4,6 +4,7 @@ #include #include +#include #include "storm/storage/jani/EdgeDestination.h" #include "storm/storage/jani/OrderedAssignments.h" @@ -70,6 +71,11 @@ namespace storm { */ std::vector const& getDestinations() const; + /*! + * Retrieves the destinations of this edge. + */ + std::vector& getDestinations(); + /*! * Retrieves the number of destinations of this edge. */ @@ -103,7 +109,7 @@ namespace storm { /*! * Retrieves whether the edge uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; /*! * @@ -112,6 +118,22 @@ namespace storm { void simplifyIndexedAssignments(VariableSet const& localVars); std::shared_ptr const& getTemplateEdge(); + void setTemplateEdge(std::shared_ptr const& newTe); + + /*! + * Retrieves the lowest assignment level occurring in a destination assignment. + * If no assignment exists, this value is the highest possible integer + */ + int64_t const& getLowestAssignmentLevel() const; + + /*! + * Retrieves the highest assignment level occurring in a destination assignment + * If no assignment exists, this value is always zero + */ + int64_t const& getHighestAssignmentLevel() const; + + + void assertValid() const; private: /// The index of the source location. @@ -131,5 +153,8 @@ namespace storm { std::vector destinations; }; + std::ostream& operator<<(std::ostream& stream, Edge const& edge); + + } } diff --git a/src/storm/storage/jani/EdgeContainer.cpp b/src/storm/storage/jani/EdgeContainer.cpp new file mode 100644 index 000000000..f2e3b9855 --- /dev/null +++ b/src/storm/storage/jani/EdgeContainer.cpp @@ -0,0 +1,202 @@ +#include "storm/storage/jani/EdgeContainer.h" +#include "storm/storage/jani/Edge.h" +#include "storm/storage/jani/TemplateEdge.h" +#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/Model.h" + + + +namespace storm { + namespace jani { + namespace detail { + Edges::Edges(iterator it, iterator ite) : it(it), ite(ite) { + // Intentionally left empty. + } + + Edges::iterator Edges::begin() const { + return it; + } + + Edges::iterator Edges::end() const { + return ite; + } + + bool Edges::empty() const { + return it == ite; + } + + std::size_t Edges::size() const { + return std::distance(it, ite); + } + + ConstEdges::ConstEdges(const_iterator it, const_iterator ite) : it(it), ite(ite) { + // Intentionally left empty. + } + + ConstEdges::const_iterator ConstEdges::begin() const { + return it; + } + + ConstEdges::const_iterator ConstEdges::end() const { + return ite; + } + + bool ConstEdges::empty() const { + return it == ite; + } + + std::size_t ConstEdges::size() const { + return std::distance(it, ite); + } + } + + EdgeContainer::EdgeContainer(EdgeContainer const& other) { + edges = other.getConcreteEdges(); + //templates = other.templates; + std::map, std::shared_ptr> map; + for (auto const& te : other.templates) { + auto newTe = std::make_shared(*te); + this->templates.insert(newTe); + map[te] = newTe; + } + + for (auto& e : edges) { + if(map.count(e.getTemplateEdge()) == 0) { + e.setTemplateEdge(std::make_shared(*(e.getTemplateEdge()))); + } else { + e.setTemplateEdge(map[e.getTemplateEdge()]); + } + } + + + + } + + void EdgeContainer::finalize(Model const& containingModel) { + templates.clear(); + for (auto& edge : edges) { + templates.insert(edge.getTemplateEdge()); + } + for (auto& templateEdge : templates) { + templateEdge->finalize(containingModel); + } + } + + void EdgeContainer::clearConcreteEdges() { + edges.clear(); + } + + void EdgeContainer::liftTransientDestinationAssignments(int64_t maxLevel) { + for (auto& templateEdge : templates) { + templateEdge->liftTransientDestinationAssignments(maxLevel); + } + } + + void EdgeContainer::substitute(std::map const& substitution) { + for (auto& templateEdge : templates) { + templateEdge->substitute(substitution); + } + for (auto& edge : edges) { + edge.substitute(substitution); + } + } + + bool EdgeContainer::isLinear() const { + for (auto const& templateEdge : templates) { + if (!templateEdge->isLinear()) { + return false; + } + } + return true; + } + + + bool EdgeContainer::usesAssignmentLevels(bool onlyTransient) const { + for (auto const& edge : edges) { + if (edge.usesAssignmentLevels(onlyTransient)) { + return true; + } + } + return false; + + } + + std::vector & EdgeContainer::getConcreteEdges() { + return edges; + } + + std::vector const& EdgeContainer::getConcreteEdges() const { + return edges; + } + + TemplateEdgeContainer const& EdgeContainer::getTemplateEdges() const { + return templates; + } + + std::set EdgeContainer::getActionIndices() const { + std::set result; + for (auto const& edge : edges) { + result.insert(edge.getActionIndex()); + } + return result; + } + + /** + * Insert an edge, then sort the range between locstart and locend according to the action index. + * @param e + * @param locStart index where to start + * @param locEnd index where to end + */ + void EdgeContainer::insertEdge(Edge const &e, uint64_t locStart, uint64_t locEnd) { + assert(locStart <= locEnd); + // Find the right position for the edge and insert it properly. + auto posIt = edges.begin(); + std::advance(posIt, locEnd); + edges.insert(posIt, e); + + // Sort all edges form the source location of the newly introduced edge by their action indices. + auto it = edges.begin(); + std::advance(it, locStart); + auto ite = edges.begin(); + std::advance(ite, locEnd + 1); + std::sort(it, ite, [] (Edge const& a, Edge const& b) { return a.getActionIndex() < b.getActionIndex(); } ); + + } + + void EdgeContainer::insertTemplateEdge(std::shared_ptr const &te) { + templates.insert(te); + } + + void EdgeContainer::pushAssignmentsToDestinations() { + for (auto& templateEdge : templates) { + templateEdge->pushAssignmentsToDestinations(); + } + } + + void EdgeContainer::changeAssignmentVariables(std::map> const& remapping) { + for (auto& templateEdge : templates) { + templateEdge->changeAssignmentVariables(remapping); + } + } + + size_t EdgeContainer::size() const { + return edges.size(); + } + + EdgeContainer::iterator EdgeContainer::begin() { + return edges.begin(); + } + EdgeContainer::iterator EdgeContainer::end() { + return edges.end(); + } + EdgeContainer::const_iterator EdgeContainer::begin() const { + return edges.begin(); + } + EdgeContainer::const_iterator EdgeContainer::end() const { + return edges.end(); + } + + + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/EdgeContainer.h b/src/storm/storage/jani/EdgeContainer.h new file mode 100644 index 000000000..bf1e0cbe9 --- /dev/null +++ b/src/storm/storage/jani/EdgeContainer.h @@ -0,0 +1,127 @@ +#pragma once + +#include +#include +#include +#include "storm/storage/expressions/Expression.h" +#include "storm/storage/jani/TemplateEdgeContainer.h" + +namespace storm { + namespace jani { + + class Edge; + class TemplateEdge; + class Variable; + class Model; + + namespace detail { + class Edges { + public: + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + Edges(iterator it, iterator ite); + + /*! + * Retrieves an iterator to the edges. + */ + iterator begin() const; + + /*! + * Retrieves an end iterator to the edges. + */ + iterator end() const; + + /*! + * Determines whether this set of edges is empty. + */ + bool empty() const; + + /*! + * Retrieves the number of edges. + */ + std::size_t size() const; + + private: + iterator it; + iterator ite; + }; + + + class ConstEdges { + public: + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + ConstEdges(const_iterator it, const_iterator ite); + + /*! + * Retrieves an iterator to the edges. + */ + const_iterator begin() const; + + /*! + * Retrieves an end iterator to the edges. + */ + const_iterator end() const; + + /*! + * Determines whether this set of edges is empty. + */ + bool empty() const; + + /*! + * Retrieves the number of edges. + */ + std::size_t size() const; + + private: + const_iterator it; + const_iterator ite; + }; + } + + + class EdgeContainer { + public: + + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + + EdgeContainer() = default; + EdgeContainer(EdgeContainer const& other); + + void clearConcreteEdges(); + std::vector const& getConcreteEdges() const; + std::vector & getConcreteEdges(); + TemplateEdgeContainer const& getTemplateEdges() const; + + size_t size() const; + + iterator begin(); + const_iterator begin() const; + iterator end(); + const_iterator end() const; + + std::set getActionIndices() const; + + void substitute(std::map const& substitution); + void liftTransientDestinationAssignments(int64_t maxLevel = 0); + void pushAssignmentsToDestinations(); + void insertEdge(Edge const& e, uint64_t locStart, uint64_t locEnd); + void insertTemplateEdge(std::shared_ptr const& te); + bool isLinear() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; + void finalize(Model const& containingModel); + + void changeAssignmentVariables(std::map> const& remapping); + + + private: + std::vector edges; + TemplateEdgeContainer templates; + }; + } +} + diff --git a/src/storm/storage/jani/EdgeDestination.cpp b/src/storm/storage/jani/EdgeDestination.cpp index 81efbfff5..0a9dd4b32 100644 --- a/src/storm/storage/jani/EdgeDestination.cpp +++ b/src/storm/storage/jani/EdgeDestination.cpp @@ -1,6 +1,8 @@ #include "storm/storage/jani/EdgeDestination.h" #include "storm/utility/macros.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + #include "storm/exceptions/WrongFormatException.h" namespace storm { @@ -37,7 +39,7 @@ namespace storm { } void EdgeDestination::substitute(std::map const& substitution) { - this->setProbability(this->getProbability().substitute(substitution)); + this->setProbability(substituteJaniExpression(this->getProbability(), substitution)); } bool EdgeDestination::hasAssignment(Assignment const& assignment) const { @@ -58,5 +60,9 @@ namespace storm { TemplateEdgeDestination const& EdgeDestination::getTemplateEdgeDestination() const { return templateEdgeDestination.get(); } + + void EdgeDestination::updateTemplateEdgeDestination(TemplateEdgeDestination const& newTed) { + templateEdgeDestination = newTed; + } } } diff --git a/src/storm/storage/jani/EdgeDestination.h b/src/storm/storage/jani/EdgeDestination.h index 7cefe9c7a..62dd6114e 100644 --- a/src/storm/storage/jani/EdgeDestination.h +++ b/src/storm/storage/jani/EdgeDestination.h @@ -66,6 +66,8 @@ namespace storm { * Retrieves the template destination for this destination. */ TemplateEdgeDestination const& getTemplateEdgeDestination() const; + + void updateTemplateEdgeDestination(TemplateEdgeDestination const& newTed); private: // The index of the destination location. diff --git a/src/storm/storage/jani/FunctionDefinition.cpp b/src/storm/storage/jani/FunctionDefinition.cpp new file mode 100644 index 000000000..8be6beac6 --- /dev/null +++ b/src/storm/storage/jani/FunctionDefinition.cpp @@ -0,0 +1,49 @@ +#include "storm/storage/jani/FunctionDefinition.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + + +#include "storm/utility/macros.h" +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + namespace jani { + + FunctionDefinition::FunctionDefinition(std::string const& name, storm::expressions::Type const& type, std::vector const& parameters, storm::expressions::Expression const& functionBody) : name(name), type(type), parameters(parameters), functionBody(functionBody) { + // Intentionally left empty. + } + + std::string const& FunctionDefinition::getName() const { + return name; + } + + storm::expressions::Type const& FunctionDefinition::getType() const { + return type; + } + + std::vector const& FunctionDefinition::getParameters() const { + return parameters; + } + + storm::expressions::Expression const& FunctionDefinition::getFunctionBody() const { + return functionBody; + } + + storm::expressions::Expression FunctionDefinition::call(std::vector> const& arguments ) const { + // substitute the parameters in the function body + STORM_LOG_THROW(arguments.size() == parameters.size(), storm::exceptions::InvalidArgumentException, "The number of arguments does not match the number of parameters."); + std::unordered_map parameterSubstitution; + for (uint64_t i = 0; i < arguments.size(); ++i) { + parameterSubstitution.emplace(parameters[i], arguments[i]); + } + return substituteJaniExpression(functionBody, parameterSubstitution); + } + + void FunctionDefinition::substitute(std::map const& substitution) { + this->setFunctionBody(substituteJaniExpression(this->getFunctionBody(), substitution)); + } + + void FunctionDefinition::setFunctionBody(storm::expressions::Expression const& body) { + functionBody = body; + } + } +} diff --git a/src/storm/storage/jani/FunctionDefinition.h b/src/storm/storage/jani/FunctionDefinition.h new file mode 100644 index 000000000..4a46bb663 --- /dev/null +++ b/src/storm/storage/jani/FunctionDefinition.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +#include + +#include "storm/storage/expressions/Variable.h" +#include "storm/storage/expressions/Expression.h" + +namespace storm { + namespace jani { + + class FunctionDefinition { + public: + /*! + * Creates a functionDefinition. + */ + FunctionDefinition(std::string const& name, storm::expressions::Type const& type, std::vector const& parameters, storm::expressions::Expression const& functionBody); + + /*! + * Retrieves the name of the function. + */ + std::string const& getName() const; + + /*! + * Retrieves the type of the function. + */ + storm::expressions::Type const& getType() const; + + /*! + * Retrieves the parameters of the function + */ + std::vector const& getParameters() const; + + /*! + * Retrieves the expression that defines the function + */ + storm::expressions::Expression const& getFunctionBody() const; + + /*! + * sets the expression that defines the function + */ + void setFunctionBody(storm::expressions::Expression const& body); + + /*! + * Calls the function with the given arguments + */ + storm::expressions::Expression call(std::vector> const& arguments ) const; + + void substitute(std::map const& substitution); + + + private: + // The name of the function. + std::string name; + + // The type of the function + storm::expressions::Type type; + + // The parameters + std::vector parameters; + + // The body of the function + storm::expressions::Expression functionBody; + }; + + } +} diff --git a/src/storm/storage/jani/FunctionEliminator.cpp b/src/storm/storage/jani/FunctionEliminator.cpp new file mode 100644 index 000000000..32a9895de --- /dev/null +++ b/src/storm/storage/jani/FunctionEliminator.cpp @@ -0,0 +1,417 @@ +#include "storm/storage/jani/FunctionEliminator.h" + +#include + +#include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/Variable.h" +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/traverser/FunctionCallExpressionFinder.h" +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Property.h" + +#include "storm/storage/expressions/Expressions.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/UnexpectedException.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + + + + namespace jani { + namespace detail { + + class FunctionEliminationExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + + typedef std::shared_ptr BaseExprPtr; + + FunctionEliminationExpressionVisitor(std::unordered_map const* globalFunctions, std::unordered_map const* localFunctions = nullptr) : globalFunctions(globalFunctions), localFunctions(localFunctions) {} + + virtual ~FunctionEliminationExpressionVisitor() = default; + + FunctionEliminationExpressionVisitor setLocalFunctions(std::unordered_map const* localFunctions) { + return FunctionEliminationExpressionVisitor(this->globalFunctions, localFunctions); + } + + storm::expressions::Expression eliminate(storm::expressions::Expression const& expression) { + auto res = storm::expressions::Expression(boost::any_cast(expression.accept(*this, boost::any()))); + return res.simplify(); + } + + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + BaseExprPtr conditionExpression = boost::any_cast(expression.getCondition()->accept(*this, data)); + BaseExprPtr thenExpression = boost::any_cast(expression.getThenExpression()->accept(*this, data)); + BaseExprPtr elseExpression = boost::any_cast(expression.getElseExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (conditionExpression.get() == expression.getCondition().get() && thenExpression.get() == expression.getThenExpression().get() && elseExpression.get() == expression.getElseExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::IfThenElseExpression(expression.getManager(), thenExpression->getType(), conditionExpression, thenExpression, elseExpression))); + } + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryBooleanFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryNumericalFunctionExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::BinaryRelationExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression, expression.getRelationType()))); + } + } + + virtual boost::any visit(storm::expressions::VariableExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr operandExpression = boost::any_cast(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryBooleanFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + BaseExprPtr operandExpression = boost::any_cast(expression.getOperand()->accept(*this, data)); + + // If the argument did not change, we simply push the expression itself. + if (operandExpression.get() == expression.getOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::UnaryNumericalFunctionExpression(expression.getManager(), expression.getType(), operandExpression, expression.getOperatorType()))); + } + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) override { + return expression.getSharedPointer(); + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + uint64_t size = expression.size()->evaluateAsInt(); + std::vector elements; + bool changed = false; + for (uint64_t i = 0; i(expression.at(i)->accept(*this, data)); + if (element.get() != expression.at(i).get()) { + changed = true; + } + elements.push_back(element); + } + if (changed) { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::ValueArrayExpression(expression.getManager(), expression.getType(), elements))); + } else { + return expression.getSharedPointer(); + } + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + BaseExprPtr sizeExpression = boost::any_cast(expression.size()->accept(*this, data)); + BaseExprPtr elementExpression = boost::any_cast(expression.getElementExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (sizeExpression.get() == expression.size().get() && elementExpression.get() == expression.getElementExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::ConstructorArrayExpression(expression.getManager(), expression.getType(), sizeExpression, expression.getIndexVar(), elementExpression))); + } + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + BaseExprPtr firstExpression = boost::any_cast(expression.getFirstOperand()->accept(*this, data)); + BaseExprPtr secondExpression = boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new storm::expressions::ArrayAccessExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression))); + } + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + // Find the associated function definition + FunctionDefinition const* funDef = nullptr; + if (localFunctions != nullptr) { + auto funDefIt = localFunctions->find(expression.getFunctionIdentifier()); + if (funDefIt != localFunctions->end()) { + funDef = &(funDefIt->second); + } + } + if (globalFunctions != nullptr) { + auto funDefIt = globalFunctions->find(expression.getFunctionIdentifier()); + if (funDefIt != globalFunctions->end()) { + funDef = &(funDefIt->second); + } + } + + STORM_LOG_THROW(funDef != nullptr, storm::exceptions::UnexpectedException, "Unable to find function definition for function call " << expression << "."); + + return boost::any_cast(funDef->call(expression.getArguments()).getBaseExpression().accept(*this, data)); + } + + private: + std::unordered_map const* globalFunctions; + std::unordered_map const* localFunctions; + }; + + class FunctionEliminatorTraverser : public JaniTraverser { + public: + + FunctionEliminatorTraverser() = default; + + virtual ~FunctionEliminatorTraverser() = default; + + void eliminate(Model& model, std::vector& properties) { + + // Replace all function calls by the function definition + traverse(model, boost::any()); + + // Replace function definitions in properties + if (!model.getGlobalFunctionDefinitions().empty()) { + FunctionEliminationExpressionVisitor v(&model.getGlobalFunctionDefinitions()); + for (auto& property : properties) { + property = property.substitute([&v](storm::expressions::Expression const& exp) {return v.eliminate(exp);}); + } + } + + // Erase function definitions in model and automata + model.getGlobalFunctionDefinitions().clear(); + for (auto& automaton : model.getAutomata()) { + automaton.getFunctionDefinitions().clear(); + } + + // Clear the model feature 'functions' + model.getModelFeatures().remove(ModelFeature::Functions); + + // finalize the model + model.finalize(); + } + + + + // To detect cyclic dependencies between function bodies, we need to eliminate the functions in a topological order + enum class FunctionDefinitionStatus {Unprocessed, Current, Processed}; + void eliminateFunctionsInFunctionBodies(FunctionEliminationExpressionVisitor& eliminationVisitor, std::unordered_map& functions, std::unordered_map& status, std::string const& current) { + status[current] = FunctionDefinitionStatus::Current; + FunctionDefinition& funDef = functions.find(current)->second; + auto calledFunctions = getOccurringFunctionCalls(funDef.getFunctionBody()); + for (auto const& calledFunction : calledFunctions) { + STORM_LOG_THROW(calledFunction != current, storm::exceptions::NotSupportedException, "Function '" << calledFunction << "' calls itself. This is not supported."); + auto calledStatus = status.find(calledFunction); + // Check whether the called function belongs to the ones that actually needed processing + if (calledStatus != status.end()) { + STORM_LOG_THROW(calledStatus->second != FunctionDefinitionStatus::Current, storm::exceptions::NotSupportedException, "Found cyclic dependencies between functions '" << calledFunction << "' and '" << current << "'. This is not supported."); + if (calledStatus->second == FunctionDefinitionStatus::Unprocessed) { + eliminateFunctionsInFunctionBodies(eliminationVisitor, functions, status, calledFunction); + } + } + } + // At this point, all called functions are processed already. So we can finally process this one. + funDef.setFunctionBody(eliminationVisitor.eliminate(funDef.getFunctionBody())); + status[current] = FunctionDefinitionStatus::Processed; + } + void eliminateFunctionsInFunctionBodies(FunctionEliminationExpressionVisitor& eliminationVisitor, std::unordered_map& functions) { + + std::unordered_map status; + for (auto const& f : functions) { + status.emplace(f.first, FunctionDefinitionStatus::Unprocessed); + } + for (auto const& f : functions) { + if (status[f.first] == FunctionDefinitionStatus::Unprocessed) { + eliminateFunctionsInFunctionBodies(eliminationVisitor, functions, status, f.first); + } + } + } + + virtual void traverse(Model& model, boost::any const&) override { + + // First we need to apply functions called in function bodies + FunctionEliminationExpressionVisitor globalFunctionEliminationVisitor(&model.getGlobalFunctionDefinitions()); + eliminateFunctionsInFunctionBodies(globalFunctionEliminationVisitor, model.getGlobalFunctionDefinitions()); + + // Now run through the remaining components + for (auto& c : model.getConstants()) { + traverse(c, &globalFunctionEliminationVisitor); + } + JaniTraverser::traverse(model.getGlobalVariables(), &globalFunctionEliminationVisitor); + for (auto& aut : model.getAutomata()) { + traverse(aut, &globalFunctionEliminationVisitor); + } + if (model.hasInitialStatesRestriction()) { + model.setInitialStatesRestriction(globalFunctionEliminationVisitor.eliminate(model.getInitialStatesRestriction())); + } + for (auto& nonTrivRew : model.getNonTrivialRewardExpressions()) { + nonTrivRew.second = globalFunctionEliminationVisitor.eliminate(nonTrivRew.second); + } + } + + void traverse(Automaton& automaton, boost::any const& data) override { + // First we need to apply functions called in function bodies + auto functionEliminationVisitor = boost::any_cast(data)->setLocalFunctions(&automaton.getFunctionDefinitions()); + eliminateFunctionsInFunctionBodies(functionEliminationVisitor, automaton.getFunctionDefinitions()); + + // Now run through the remaining components + JaniTraverser::traverse(automaton.getVariables(), &functionEliminationVisitor); + for (auto& loc : automaton.getLocations()) { + JaniTraverser::traverse(loc, &functionEliminationVisitor); + } + JaniTraverser::traverse(automaton.getEdgeContainer(), &functionEliminationVisitor); + if (automaton.hasInitialStatesRestriction()) { + automaton.setInitialStatesRestriction(functionEliminationVisitor.eliminate(automaton.getInitialStatesRestriction())); + } + } + + void traverse(Constant& constant, boost::any const& data) override { + if (constant.isDefined()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + constant.define(functionEliminationVisitor->eliminate(constant.getExpression())); + } + } + + void traverse(BooleanVariable& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + } + + void traverse(BoundedIntegerVariable& variable, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + if (variable.hasInitExpression()) { + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + variable.setLowerBound(functionEliminationVisitor->eliminate(variable.getLowerBound())); + variable.setUpperBound(functionEliminationVisitor->eliminate(variable.getUpperBound())); + } + + void traverse(UnboundedIntegerVariable& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + } + + void traverse(RealVariable& variable, boost::any const& data) override { + if (variable.hasInitExpression()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + } + + void traverse(ArrayVariable& variable, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + if (variable.hasInitExpression()) { + variable.setInitExpression(functionEliminationVisitor->eliminate(variable.getInitExpression())); + } + if (variable.hasLowerElementTypeBound()) { + variable.setLowerElementTypeBound(functionEliminationVisitor->eliminate(variable.getLowerElementTypeBound())); + } + if (variable.hasUpperElementTypeBound()) { + variable.setUpperElementTypeBound(functionEliminationVisitor->eliminate(variable.getUpperElementTypeBound())); + } + } + + void traverse(TemplateEdge& templateEdge, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + templateEdge.setGuard(functionEliminationVisitor->eliminate(templateEdge.getGuard())); + for (auto& dest : templateEdge.getDestinations()) { + JaniTraverser::traverse(dest, data); + } + JaniTraverser::traverse(templateEdge.getAssignments(), data); + } + + void traverse(Edge& edge, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + if (edge.hasRate()) { + edge.setRate(functionEliminationVisitor->eliminate(edge.getRate())); + } + for (auto& dest : edge.getDestinations()) { + traverse(dest, data); + } + } + + void traverse(EdgeDestination& edgeDestination, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + edgeDestination.setProbability(functionEliminationVisitor->eliminate(edgeDestination.getProbability())); + } + + void traverse(Assignment& assignment, boost::any const& data) override { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + assignment.setAssignedExpression(functionEliminationVisitor->eliminate(assignment.getAssignedExpression())); + traverse(assignment.getLValue(), data); + } + + void traverse(LValue& lValue, boost::any const& data) override { + if (lValue.isArrayAccess()) { + FunctionEliminationExpressionVisitor* functionEliminationVisitor = boost::any_cast(data); + lValue.setArrayIndex(functionEliminationVisitor->eliminate(lValue.getArrayIndex())); + } + } + + void traverse(storm::expressions::Expression const& expression, boost::any const&) override { + STORM_LOG_THROW(getOccurringFunctionCalls(expression).empty(), storm::exceptions::UnexpectedException, "Did not translate functions in expression " << expression); + } + }; + } // namespace detail + + + void eliminateFunctions(Model& model, std::vector& properties) { + // Only perform actions if there actually are functions. + if (model.getModelFeatures().hasFunctions()) { + detail::FunctionEliminatorTraverser().eliminate(model, properties); + } + STORM_LOG_ASSERT(!containsFunctionCallExpression(model), "The model still seems to contain function calls."); + } + + storm::expressions::Expression eliminateFunctionCallsInExpression(storm::expressions::Expression const& expression, Model const& model) { + detail::FunctionEliminationExpressionVisitor visitor(&model.getGlobalFunctionDefinitions()); + return visitor.eliminate(expression); + } + + } +} + diff --git a/src/storm/storage/jani/FunctionEliminator.h b/src/storm/storage/jani/FunctionEliminator.h new file mode 100644 index 000000000..c7a3b74eb --- /dev/null +++ b/src/storm/storage/jani/FunctionEliminator.h @@ -0,0 +1,30 @@ +#pragma once + + +#include + + +namespace storm { + + namespace expressions { + class Expression; + } + + namespace jani { + class Model; + class Property; + + /*! + * Eliminates all function references in the given model and the given properties by replacing them with their corresponding definitions. + */ + void eliminateFunctions(Model& model, std::vector& properties); + + /*! + * Eliminates all function calls in the given expression by replacing them with their corresponding definitions. + * Only global function definitions are considered. + */ + storm::expressions::Expression eliminateFunctionCallsInExpression(storm::expressions::Expression const& expression, Model const& model); + + } +} + diff --git a/src/storm/storage/jani/JSONExporter.cpp b/src/storm/storage/jani/JSONExporter.cpp index 5fde8267a..be2c74471 100644 --- a/src/storm/storage/jani/JSONExporter.cpp +++ b/src/storm/storage/jani/JSONExporter.cpp @@ -11,6 +11,7 @@ #include "storm/exceptions/InvalidJaniException.h" #include "storm/exceptions/NotImplementedException.h" +#include "storm/exceptions/InvalidPropertyException.h" #include "storm/storage/expressions/RationalLiteralExpression.h" #include "storm/storage/expressions/IntegerLiteralExpression.h" @@ -29,13 +30,23 @@ #include "storm/storage/jani/AutomatonComposition.h" #include "storm/storage/jani/ParallelComposition.h" #include "storm/storage/jani/Property.h" +#include "storm/storage/jani/traverser/AssignmentsFinder.h" +#include "storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.h" +#include "storm/storage/jani/FunctionEliminator.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" namespace storm { namespace jani { - - modernjson::json buildExpression(storm::expressions::Expression const& exp, std::vector const& constants, VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet()) { - return ExpressionToJson::translate(exp, constants, globalVariables, localVariables); + modernjson::json anyToJson(boost::any&& input) { + boost::any tmp(std::move(input)); + modernjson::json res = std::move(*boost::any_cast(&tmp)); + return std::move(res); + } + + modernjson::json buildExpression(storm::expressions::Expression const& exp, std::vector const& constants, VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet(), std::unordered_set const& auxiliaryVariables = {}) { + STORM_LOG_TRACE("Exporting " << exp); + return ExpressionToJson::translate(exp, constants, globalVariables, localVariables, auxiliaryVariables); } class CompositionJsonExporter : public CompositionVisitor { @@ -46,7 +57,7 @@ namespace storm { static modernjson::json translate(storm::jani::Composition const& comp, bool allowRecursion = true) { CompositionJsonExporter visitor(allowRecursion); - return boost::any_cast(comp.accept(visitor, boost::none)); + return anyToJson(comp.accept(visitor, boost::none)); } virtual boost::any visit(AutomatonComposition const& composition, boost::any const&) { @@ -69,7 +80,7 @@ namespace storm { elemDecl["automaton"] = std::static_pointer_cast(subcomp)->getAutomatonName(); } else { STORM_LOG_THROW(allowRecursion, storm::exceptions::InvalidJaniException, "Nesting composition " << *subcomp << " is not supported by JANI."); - elemDecl = boost::any_cast(subcomp->accept(*this, data)); + elemDecl = anyToJson(subcomp->accept(*this, data)); } elems.push_back(elemDecl); } @@ -152,9 +163,73 @@ namespace storm { return iDecl; } - modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model) { + modernjson::json FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation, std::string const& rewardModelName) const { + bool steps = false; + bool time = false; + bool exit = false; + + auto rewardExpression = storm::jani::eliminateFunctionCallsInExpression(model.getRewardModelExpression(rewardModelName), model); + + auto variablesInRewardExpression = rewardExpression.getVariables(); + std::map initialSubstitution; + for (auto const& v : variablesInRewardExpression) { + STORM_LOG_ASSERT(model.hasGlobalVariable(v.getName()), "Unable to find global variable " << v.getName() << " occurring in a reward expression."); + auto const& janiVar = model.getGlobalVariable(v.getName()); + if (janiVar.hasInitExpression()) { + initialSubstitution.emplace(v, janiVar.getInitExpression()); + } + auto assignmentKinds = storm::jani::AssignmentsFinder().find(model, v); + steps = steps || assignmentKinds.hasEdgeAssignment || assignmentKinds.hasEdgeDestinationAssignment; + time = time || (!model.isDeterministicModel() && assignmentKinds.hasLocationAssignment); + exit = exit || assignmentKinds.hasLocationAssignment; + } + storm::jani::substituteJaniExpression(rewardExpression, initialSubstitution); + if (rewardExpression.containsVariables() || !storm::utility::isZero(rewardExpression.evaluateAsRational())) { + steps = true; + time = true; + exit = true; + } + + steps = steps && rewardAccumulation.isStepsSet(); + time = time && rewardAccumulation.isTimeSet(); + exit = exit && rewardAccumulation.isExitSet(); + return constructRewardAccumulation(storm::logic::RewardAccumulation(steps, time, exit)); + } + + modernjson::json FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const { + std::vector res; + if (rewardAccumulation.isStepsSet()) { + res.push_back("steps"); + } + if (rewardAccumulation.isTimeSet()) { + res.push_back("time"); + } + if (rewardAccumulation.isExitSet()) { + stateExitRewards = true; + res.push_back("exit"); + } + return res; + } + + modernjson::json FormulaToJaniJson::constructStandardRewardAccumulation(std::string const& rewardModelName) const { + if (model.isDiscreteTimeModel()) { + return constructRewardAccumulation(storm::logic::RewardAccumulation(true, false, true), rewardModelName); + } else { + return constructRewardAccumulation(storm::logic::RewardAccumulation(true, true, false), rewardModelName); + } + } + + modernjson::json FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures) { FormulaToJaniJson translator(model); - return boost::any_cast(formula.accept(translator)); + auto result = anyToJson(formula.accept(translator)); + if (translator.containsStateExitRewards()) { + modelFeatures.add(storm::jani::ModelFeature::StateExitRewards); + } + return result; + } + + bool FormulaToJaniJson::containsStateExitRewards() const { + return stateExitRewards; } boost::any FormulaToJaniJson::visit(storm::logic::AtomicExpressionFormula const& f, boost::any const&) const { @@ -169,8 +244,8 @@ namespace storm { modernjson::json opDecl; storm::logic::BinaryBooleanStateFormula::OperatorType op = f.getOperator(); opDecl["op"] = op == storm::logic::BinaryBooleanStateFormula::OperatorType::And ? "∧" : "∨"; - opDecl["left"] = boost::any_cast(f.getLeftSubformula().accept(*this, data)); - opDecl["right"] = boost::any_cast(f.getRightSubformula().accept(*this, data)); + opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data)); + opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data)); return opDecl; } boost::any FormulaToJaniJson::visit(storm::logic::BooleanLiteralFormula const& f, boost::any const&) const { @@ -178,32 +253,54 @@ namespace storm { return opDecl; } boost::any FormulaToJaniJson::visit(storm::logic::BoundedUntilFormula const& f, boost::any const& data) const { + STORM_LOG_THROW(!f.hasMultiDimensionalSubformulas(), storm::exceptions::NotSupportedException, "Jani export of multi-dimensional bounded until formulas is not supported."); modernjson::json opDecl; opDecl["op"] = "U"; - opDecl["left"] = boost::any_cast(f.getLeftSubformula().accept(*this, data)); - opDecl["right"] = boost::any_cast(f.getRightSubformula().accept(*this, data)); + opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data)); + opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data)); - boost::optional lower, upper; - boost::optional lowerExclusive, upperExclusive; - if (f.hasLowerBound()) { - lower = f.getLowerBound(); - lowerExclusive = f.isLowerBoundStrict(); - } - if (f.hasUpperBound()) { - upper = f.getUpperBound(); - upperExclusive = f.isUpperBoundStrict(); + bool hasStepBounds(false), hasTimeBounds(false); + std::vector rewardBounds; + + for (uint64_t i = 0; i < f.getDimension(); ++i) { + boost::optional lower, upper; + boost::optional lowerExclusive, upperExclusive; + if (f.hasLowerBound(i)) { + lower = f.getLowerBound(i); + lowerExclusive = f.isLowerBoundStrict(i); + } + if (f.hasUpperBound(i)) { + upper = f.getUpperBound(i); + upperExclusive = f.isUpperBoundStrict(i); + } + modernjson::json propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive); + + auto tbr = f.getTimeBoundReference(i); + if (tbr.isStepBound()) { + STORM_LOG_THROW(!hasStepBounds, storm::exceptions::NotSupportedException, "Jani export of until formulas with multiple step bounds is not supported."); + hasStepBounds = true; + opDecl["step-bounds"] = propertyInterval; + } else if(tbr.isRewardBound()) { + modernjson::json rewbound; + rewbound["exp"] = buildExpression(model.getRewardModelExpression(tbr.getRewardName()), model.getConstants(), model.getGlobalVariables()); + if (tbr.hasRewardAccumulation()) { + rewbound["accumulate"] = constructRewardAccumulation(tbr.getRewardAccumulation(), tbr.getRewardName()); + } else { + rewbound["accumulate"] = constructStandardRewardAccumulation(tbr.getRewardName()); + } + rewbound["bounds"] = propertyInterval; + rewardBounds.push_back(std::move(rewbound)); + } else { + STORM_LOG_THROW(!hasTimeBounds, storm::exceptions::NotSupportedException, "Jani export of until formulas with multiple step bounds is not supported."); + hasTimeBounds = true; + opDecl["time-bounds"] = propertyInterval; + } } - modernjson::json propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive); - - auto tbr = f.getTimeBoundReference(); - if(tbr.isStepBound()) { - opDecl["step-bounds"] = propertyInterval; - } else if(tbr.isRewardBound()) { - opDecl["time-bounds"] = propertyInterval; - } else { - opDecl["reward-bounds"] = propertyInterval; + if (!rewardBounds.empty()) { + opDecl["reward-bounds"] = modernjson::json(rewardBounds); } return opDecl; + } boost::any FormulaToJaniJson::visit(storm::logic::ConditionalFormula const&, boost::any const&) const { @@ -217,40 +314,53 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::EventuallyFormula const& f, boost::any const& data) const { modernjson::json opDecl; opDecl["op"] = "U"; - opDecl["left"] = boost::any_cast(f.getTrueFormula()->accept(*this, data)); - opDecl["right"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"] = anyToJson(f.getTrueFormula()->accept(*this, data)); + opDecl["right"] = anyToJson(f.getSubformula().accept(*this, data)); return opDecl; } boost::any FormulaToJaniJson::visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; - std::vector tvec; - tvec.push_back("time"); + + // Create standard reward accumulation for time operator formulas. + storm::logic::RewardAccumulation rewAcc(model.isDiscreteTimeModel(), !model.isDiscreteTimeModel(), false); + if (f.getSubformula().isEventuallyFormula() && f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { + rewAcc = f.getSubformula().asEventuallyFormula().getRewardAccumulation(); + } + auto rewAccJson = constructRewardAccumulation(rewAcc); + if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); if(f.hasOptimalityType()) { opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); + if (f.getSubformula().isEventuallyFormula()) { + opDecl["left"]["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported subformula for time operator formula " << f); + } } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"]["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["left"]["exp"] = modernjson::json(1); - opDecl["left"]["accumulate"] = modernjson::json(tvec); + opDecl["left"]["accumulate"] = rewAccJson; opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { if(f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); - + if (f.getSubformula().isEventuallyFormula()) { + opDecl["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unsupported subformula for time operator formula " << f); + } } else { // TODO add checks opDecl["op"] = "Emin"; - opDecl["reach"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } opDecl["exp"] = modernjson::json(1); - opDecl["accumulate"] = modernjson::json(tvec); + opDecl["accumulate"] = rewAccJson; } return opDecl; } @@ -264,31 +374,30 @@ namespace storm { } boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageOperatorFormula const& f, boost::any const& data) const { - modernjson::json opDecl; + modernjson::json opDecl; if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); if(f.hasOptimalityType()) { opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax"; - opDecl["left"]["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Smax" : "Smin"; - opDecl["left"]["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { if(f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax"; - opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } else { // TODO add checks opDecl["op"] = "Pmin"; - opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } } return opDecl; - } boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageRewardFormula const&, boost::any const&) const { @@ -298,21 +407,21 @@ namespace storm { // opDecl["op"] = comparisonTypeToJani(bound.comparisonType); // if(f.hasOptimalityType()) { // opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax"; -// opDecl["left"]["exp"] = boost::any_cast(f.getSubformula().accept(*this, boost::none)); +// opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none)); // } else { // opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Smax" : "Smin"; -// opDecl["left"]["exp"] = boost::any_cast(f.getSubformula().accept(*this, boost::none)); +// opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none)); // } // opDecl["right"] = ExpressionToJson::translate(bound.threshold); // } else { // if(f.hasOptimalityType()) { // opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax"; -// opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, boost::none)); +// opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none)); // // } else { // // TODO add checks // opDecl["op"] = "Pmin"; -// opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, boost::none)); +// opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none)); // } // } // return opDecl; @@ -328,8 +437,8 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::NextFormula const& f, boost::any const& data) const { modernjson::json opDecl; opDecl["op"] = "U"; - opDecl["left"] = boost::any_cast(f.getTrueFormula()->accept(*this, data)); - opDecl["right"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"] = anyToJson(f.getTrueFormula()->accept(*this, data)); + opDecl["right"] = anyToJson(f.getSubformula().accept(*this, data)); auto intervalExpressionManager = std::make_shared(); opDecl["step-bounds"] = constructPropertyInterval(intervalExpressionManager->integer(1), false, intervalExpressionManager->integer(1), false); return opDecl; @@ -346,21 +455,21 @@ namespace storm { opDecl["op"] = comparisonTypeToJani(bound.comparisonType); if(f.hasOptimalityType()) { opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax"; - opDecl["left"]["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Pmax" : "Pmin"; - opDecl["left"]["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["left"]["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { if(f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax"; - opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } else { // TODO add checks opDecl["op"] = "Pmin"; - opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data)); } } return opDecl; @@ -368,39 +477,88 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const { modernjson::json opDecl; - std::vector accvec; - if(model.isDiscreteTimeModel()) { - accvec.push_back("steps"); + + std::string instantName; + if (model.isDiscreteTimeModel()) { + instantName = "step-instant"; } else { - accvec.push_back("time"); + instantName = "time-instant"; } + + std::string rewardModelName; + if (f.hasRewardModelName()) { + rewardModelName = f.getRewardModelName(); + } else { + if (model.getGlobalVariables().getNumberOfRealTransientVariables() == 1) { + for (auto const& variable : model.getGlobalVariables().getRealVariables()) { + if (variable.isTransient()) { + rewardModelName = variable.getName(); + STORM_LOG_WARN("Reward model name was not given, assuming the only global real transient variable '" << rewardModelName << "' to measure the reward."); + break; + } + } + } + } + STORM_LOG_THROW(!rewardModelName.empty(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); + if(f.hasBound()) { auto bound = f.getBound(); opDecl["op"] = comparisonTypeToJani(bound.comparisonType); if(f.hasOptimalityType()) { opDecl["left"]["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } else { opDecl["left"]["op"] = (bound.comparisonType == storm::logic::ComparisonType::Less || bound.comparisonType == storm::logic::ComparisonType::LessEqual) ? "Emax" : "Emin"; - opDecl["left"]["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + } + if (f.getSubformula().isEventuallyFormula()) { + opDecl["left"]["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + if (f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { + opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation(), rewardModelName); + } else { + opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(rewardModelName); + } + } else if (f.getSubformula().isCumulativeRewardFormula()) { + // TODO: support for reward bounded formulas + STORM_LOG_WARN_COND(!f.getSubformula().asCumulativeRewardFormula().getTimeBoundReference().isRewardBound(), "Export for reward bounded cumulative reward formulas currently unsupported."); + opDecl["left"][instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + if (f.getSubformula().asCumulativeRewardFormula().hasRewardAccumulation()) { + opDecl["left"]["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation(), rewardModelName); + } else { + opDecl["left"]["accumulate"] = constructStandardRewardAccumulation(rewardModelName); + } + } else if (f.getSubformula().isInstantaneousRewardFormula()) { + opDecl["left"][instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); } STORM_LOG_THROW(f.hasRewardModelName(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); - opDecl["left"]["exp"] = f.getRewardModelName(); - opDecl["left"]["accumulate"] = modernjson::json(accvec); + opDecl["left"]["exp"] = buildExpression(model.getRewardModelExpression(rewardModelName), model.getConstants(), model.getGlobalVariables()); opDecl["right"] = buildExpression(bound.threshold, model.getConstants(), model.getGlobalVariables()); } else { - if(f.hasOptimalityType()) { + if (f.hasOptimalityType()) { opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Emin" : "Emax"; - opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); - } else { // TODO add checks opDecl["op"] = "Emin"; - opDecl["reach"] = boost::any_cast(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); } - STORM_LOG_THROW(f.hasRewardModelName(), storm::exceptions::NotSupportedException, "Reward name has to be specified for Jani-conversion"); - opDecl["exp"] = f.getRewardModelName(); - opDecl["accumulate"] = modernjson::json(accvec); + + if (f.getSubformula().isEventuallyFormula()) { + opDecl["reach"] = anyToJson(f.getSubformula().asEventuallyFormula().getSubformula().accept(*this, data)); + if (f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) { + opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asEventuallyFormula().getRewardAccumulation(), rewardModelName); + } else { + opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName); + } + } else if (f.getSubformula().isCumulativeRewardFormula()) { + // TODO: support for reward bounded formulas + STORM_LOG_WARN_COND(!f.getSubformula().asCumulativeRewardFormula().getTimeBoundReference().isRewardBound(), "Export for reward bounded cumulative reward formulas currently unsupported."); + opDecl[instantName] = buildExpression(f.getSubformula().asCumulativeRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + if (f.getSubformula().asCumulativeRewardFormula().hasRewardAccumulation()) { + opDecl["accumulate"] = constructRewardAccumulation(f.getSubformula().asCumulativeRewardFormula().getRewardAccumulation(), rewardModelName); + } else { + opDecl["accumulate"] = constructStandardRewardAccumulation(rewardModelName); + } + } else if (f.getSubformula().isInstantaneousRewardFormula()) { + opDecl[instantName] = buildExpression(f.getSubformula().asInstantaneousRewardFormula().getBound(), model.getConstants(), model.getGlobalVariables()); + } + opDecl["exp"] = buildExpression(model.getRewardModelExpression(rewardModelName), model.getConstants(), model.getGlobalVariables()); } return opDecl; } @@ -408,22 +566,21 @@ namespace storm { boost::any FormulaToJaniJson::visit(storm::logic::TotalRewardFormula const&, boost::any const&) const { STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support a total reward formula"); } - boost::any FormulaToJaniJson::visit(storm::logic::UnaryBooleanStateFormula const& f, boost::any const& data) const { modernjson::json opDecl; storm::logic::UnaryBooleanStateFormula::OperatorType op = f.getOperator(); assert(op == storm::logic::UnaryBooleanStateFormula::OperatorType::Not); opDecl["op"] = "¬"; - opDecl["exp"] = boost::any_cast(f.getSubformula().accept(*this, data)); + opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data)); return opDecl; } boost::any FormulaToJaniJson::visit(storm::logic::UntilFormula const& f, boost::any const& data) const { modernjson::json opDecl; opDecl["op"] = "U"; - opDecl["left"] = boost::any_cast(f.getLeftSubformula().accept(*this, data)); - opDecl["right"] = boost::any_cast(f.getRightSubformula().accept(*this, data)); + opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data)); + opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data)); return opDecl; } @@ -455,6 +612,8 @@ namespace storm { return "max"; case OpType::Power: return "pow"; + case OpType::Modulo: + return "%"; case OpType::Equal: return "="; case OpType::NotEqual: @@ -480,43 +639,48 @@ namespace storm { } } - modernjson::json ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { - ExpressionToJson visitor(constants, globalVariables, localVariables); - return boost::any_cast(expr.accept(visitor, boost::none)); + modernjson::json ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set const& auxiliaryVariables) { + + // Simplify the expression first and reduce the nesting + auto simplifiedExpr = storm::jani::reduceNestingInJaniExpression(expr.simplify()); + + ExpressionToJson visitor(constants, globalVariables, localVariables, auxiliaryVariables); + return anyToJson(simplifiedExpr.accept(visitor, boost::none)); } - boost::any ExpressionToJson::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) { modernjson::json opDecl; opDecl["op"] = "ite"; - opDecl["if"] = boost::any_cast(expression.getCondition()->accept(*this, data)); - opDecl["then"] = boost::any_cast(expression.getThenExpression()->accept(*this, data)); - opDecl["else"] = boost::any_cast(expression.getElseExpression()->accept(*this, data)); + opDecl["if"] = anyToJson(expression.getCondition()->accept(*this, data)); + opDecl["then"] = anyToJson(expression.getThenExpression()->accept(*this, data)); + opDecl["else"] = anyToJson(expression.getElseExpression()->accept(*this, data)); return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) { modernjson::json opDecl; opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); - opDecl["left"] = boost::any_cast(expression.getOperand(0)->accept(*this, data)); - opDecl["right"] = boost::any_cast(expression.getOperand(1)->accept(*this, data)); + opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data)); + opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data)); return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) { modernjson::json opDecl; opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); - opDecl["left"] = boost::any_cast(expression.getOperand(0)->accept(*this, data)); - opDecl["right"] = boost::any_cast(expression.getOperand(1)->accept(*this, data)); + opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data)); + opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data)); return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) { modernjson::json opDecl; opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); - opDecl["left"] = boost::any_cast(expression.getOperand(0)->accept(*this, data)); - opDecl["right"] = boost::any_cast(expression.getOperand(1)->accept(*this, data)); + opDecl["left"] = anyToJson(expression.getOperand(0)->accept(*this, data)); + opDecl["right"] = anyToJson(expression.getOperand(1)->accept(*this, data)); return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::VariableExpression const& expression, boost::any const&) { - if (globalVariables.hasVariable(expression.getVariable())) { + if (auxiliaryVariables.count(expression.getVariableName())) { + return modernjson::json(expression.getVariableName()); + } else if (globalVariables.hasVariable(expression.getVariable())) { return modernjson::json(globalVariables.getVariable(expression.getVariable()).getName()); } else if (localVariables.hasVariable(expression.getVariable())) { return modernjson::json(localVariables.getVariable(expression.getVariable()).getName()); @@ -527,19 +691,19 @@ namespace storm { } } } - STORM_LOG_ASSERT(false, "Expression variable '" << expression.getVariableName() << "' not known in Jani data structures."); + STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Expression variable '" << expression.getVariableName() << "' not known in Jani data structures."); return modernjson::json(); // should not reach this point. } boost::any ExpressionToJson::visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) { modernjson::json opDecl; opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); - opDecl["exp"] = boost::any_cast(expression.getOperand()->accept(*this, data)); + opDecl["exp"] = anyToJson(expression.getOperand()->accept(*this, data)); return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) { modernjson::json opDecl; opDecl["op"] = operatorTypeToJaniString(expression.getOperator()); - opDecl["exp"] = boost::any_cast(expression.getOperand()->accept(*this, data)); + opDecl["exp"] = anyToJson(expression.getOperand()->accept(*this, data)); return opDecl; } boost::any ExpressionToJson::visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const&) { @@ -552,21 +716,77 @@ namespace storm { return modernjson::json(expression.getValueAsDouble()); } - void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid) { + boost::any ExpressionToJson::visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "av"; + std::vector elements; + uint64_t size = expression.size()->evaluateAsInt(); + for (uint64_t i = 0; i < size; ++i) { + elements.push_back(anyToJson(expression.at(i)->accept(*this, data))); + } + opDecl["elements"] = std::move(elements); + return opDecl; + } + + boost::any ExpressionToJson::visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "ac"; + opDecl["var"] = expression.getIndexVar().getName(); + opDecl["length"] = anyToJson(expression.size()->accept(*this, data)); + bool inserted = auxiliaryVariables.insert(expression.getIndexVar().getName()).second; + opDecl["exp"] = anyToJson(expression.getElementExpression()->accept(*this, data)); + if (inserted) { + auxiliaryVariables.erase(expression.getIndexVar().getName()); + } + return opDecl; + } + + boost::any ExpressionToJson::visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "aa"; + opDecl["exp"] = anyToJson(expression.getOperand(0)->accept(*this, data)); + opDecl["index"] = anyToJson(expression.getOperand(1)->accept(*this, data)); + return opDecl; + } + + boost::any ExpressionToJson::visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) { + modernjson::json opDecl; + opDecl["op"] = "call"; + opDecl["function"] = expression.getFunctionIdentifier(); + std::vector arguments; + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + arguments.push_back(anyToJson(expression.getArgument(i)->accept(*this, data))); + } + opDecl["args"] = std::move(arguments); + return opDecl; + } + + void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid, bool compact) { std::ofstream stream; - storm::utility::openFile(filepath, stream); - toStream(janiModel, formulas, stream, checkValid); + storm::utility::openFile(filepath, stream, false, true); + toStream(janiModel, formulas, stream, checkValid, compact); storm::utility::closeFile(stream); } - void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& os, bool checkValid) { + void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& os, bool checkValid, bool compact) { if(checkValid) { janiModel.checkValid(); } JsonExporter exporter; - exporter.convertModel(janiModel); + STORM_LOG_INFO("Started to convert model " << janiModel.getName() << "."); + exporter.convertModel(janiModel, !compact); + STORM_LOG_INFO("Started to convert properties of model " << janiModel.getName() << "."); exporter.convertProperties(formulas, janiModel); - os << exporter.finalize().dump(4) << std::endl; + if (compact) { + // Dump without line breaks/indents + STORM_LOG_INFO("Producing compact json output... " << janiModel.getName() << "."); + os << exporter.finalize().dump() << std::endl; + } else { + // Dump with line breaks and indention with 4 spaces + STORM_LOG_INFO("Producing json output... " << janiModel.getName() << "."); + os << exporter.finalize().dump(4) << std::endl; + } + STORM_LOG_INFO("Conversion completed " << janiModel.getName() << "."); } modernjson::json buildActionArray(std::vector const& actions) { @@ -612,8 +832,9 @@ namespace storm { return modernjson::json(constantDeclarations); } + modernjson::json buildVariablesArray(storm::jani::VariableSet const& varSet, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) { - std::vector variableDeclarations; + modernjson::json variableDeclarations; for(auto const& variable : varSet) { modernjson::json varEntry; varEntry["name"] = variable.getName(); @@ -623,55 +844,131 @@ namespace storm { modernjson::json typeDesc; if(variable.isBooleanVariable()) { typeDesc = "bool"; - } else if(variable.isRealVariable()) { + } else if (variable.isRealVariable()) { typeDesc = "real"; - } else if(variable.isUnboundedIntegerVariable()) { + } else if (variable.isUnboundedIntegerVariable()) { typeDesc = "int"; - } else { - assert(variable.isBoundedIntegerVariable()); + } else if (variable.isBoundedIntegerVariable()) { typeDesc["kind"] = "bounded"; typeDesc["base"] = "int"; typeDesc["lower-bound"] = buildExpression(variable.asBoundedIntegerVariable().getLowerBound(), constants, globalVariables, localVariables); typeDesc["upper-bound"] = buildExpression(variable.asBoundedIntegerVariable().getUpperBound(), constants, globalVariables, localVariables); + } else { + assert(variable.isArrayVariable()); + typeDesc["kind"] = "array"; + switch (variable.asArrayVariable().getElementType()) { + case storm::jani::ArrayVariable::ElementType::Bool: + typeDesc["base"] = "bool"; + break; + case storm::jani::ArrayVariable::ElementType::Real: + typeDesc["base"] = "real"; + break; + case storm::jani::ArrayVariable::ElementType::Int: + if (variable.asArrayVariable().hasElementTypeBound()) { + modernjson::json baseTypeDescr; + baseTypeDescr["kind"] = "bounded"; + baseTypeDescr["base "] = "int"; + if (variable.asArrayVariable().hasLowerElementTypeBound()) { + baseTypeDescr["lower-bound"] = buildExpression(variable.asArrayVariable().getLowerElementTypeBound(), constants, globalVariables, localVariables); + } + if (variable.asArrayVariable().hasUpperElementTypeBound()) { + baseTypeDescr["upper-bound"] = buildExpression(variable.asArrayVariable().getUpperElementTypeBound(), constants, globalVariables, localVariables); + } + typeDesc["base"] = baseTypeDescr; + } else { + typeDesc["base"] = "int"; + } + break; + } } - varEntry["type"] = typeDesc; - if(variable.hasInitExpression()) { + if (variable.hasInitExpression()) { varEntry["initial-value"] = buildExpression(variable.getInitExpression(), constants, globalVariables, localVariables); } - variableDeclarations.push_back(varEntry); + variableDeclarations.push_back(std::move(varEntry)); } - return modernjson::json(variableDeclarations); - + return variableDeclarations; + } + + modernjson::json buildTypeDescription(storm::expressions::Type const& type) { + modernjson::json typeDescr; + if (type.isIntegerType()) { + typeDescr = "int"; + } else if (type.isRationalType()) { + typeDescr = "real"; + } else if (type.isBooleanType()) { + typeDescr = "bool"; + } else if (type.isArrayType()) { + typeDescr["kind"] = "array"; + typeDescr["base"] = buildTypeDescription(type.getElementType()); + } else { + assert(false); + } + return typeDescr; } - modernjson::json buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { - std::vector assignmentDeclarations; + modernjson::json buildFunctionsArray(std::unordered_map const& functionDefinitions, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) { + modernjson::json functionDeclarations; + for (auto const& nameFunDef : functionDefinitions) { + storm::jani::FunctionDefinition const& funDef = nameFunDef.second; + modernjson::json funDefJson; + funDefJson["name"] = nameFunDef.first; + funDefJson["type"] = buildTypeDescription(funDef.getType()); + std::vector parameterDeclarations; + std::unordered_set parameterNames; + for (auto const& p : funDef.getParameters()) { + modernjson::json parDefJson; + parDefJson["name"] = p.getName(); + parameterNames.insert(p.getName()); + parDefJson["type"] = buildTypeDescription(p.getType()); + parameterDeclarations.push_back(parDefJson); + } + funDefJson["parameters"] = parameterDeclarations; + funDefJson["body"] = buildExpression(funDef.getFunctionBody(), constants, globalVariables, localVariables, parameterNames); + functionDeclarations.push_back(std::move(funDefJson)); + } + return functionDeclarations; + } + + modernjson::json buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { + modernjson::json assignmentDeclarations; bool addIndex = orderedAssignments.hasMultipleLevels(); for(auto const& assignment : orderedAssignments) { modernjson::json assignmentEntry; - assignmentEntry["ref"] = assignment.getVariable().getName(); + if (assignment.getLValue().isVariable()) { + assignmentEntry["ref"] = assignment.getVariable().getName(); + } else { + STORM_LOG_ASSERT(assignment.getLValue().isArrayAccess(), "Unhandled LValue " << assignment.getLValue()); + modernjson::json arrayAccess; + arrayAccess["op"] = "aa"; + arrayAccess["exp"] = assignment.getLValue().getArray().getName(); + arrayAccess["index"] = buildExpression(assignment.getLValue().getArrayIndex(), constants, globalVariables, localVariables); + assignmentEntry["ref"] = std::move(arrayAccess); + } assignmentEntry["value"] = buildExpression(assignment.getAssignedExpression(), constants, globalVariables, localVariables); if(addIndex) { assignmentEntry["index"] = assignment.getLevel(); } - assignmentDeclarations.push_back(assignmentEntry); + if (commentExpressions) { + assignmentEntry["comment"] = assignment.getVariable().getName() + " <- " + assignment.getAssignedExpression().toString(); + } + assignmentDeclarations.push_back(std::move(assignmentEntry)); } - return modernjson::json(assignmentDeclarations); + return assignmentDeclarations; } - modernjson::json buildLocationsArray(std::vector const& locations, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { - std::vector locationDeclarations; + modernjson::json buildLocationsArray(std::vector const& locations, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { + modernjson::json locationDeclarations; for(auto const& location : locations) { modernjson::json locEntry; locEntry["name"] = location.getName(); // TODO support invariants? if (!location.getAssignments().empty()) { - locEntry["transient-values"] = buildAssignmentArray(location.getAssignments(), constants, globalVariables, localVariables); + locEntry["transient-values"] = buildAssignmentArray(location.getAssignments(), constants, globalVariables, localVariables, commentExpressions); } - locationDeclarations.push_back(locEntry); + locationDeclarations.push_back(std::move(locEntry)); } - return modernjson::json(locationDeclarations); + return locationDeclarations; } modernjson::json buildInitialLocations(storm::jani::Automaton const& automaton) { @@ -682,9 +979,9 @@ namespace storm { return modernjson::json(names); } - modernjson::json buildDestinations(std::vector const& destinations, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { + modernjson::json buildDestinations(std::vector const& destinations, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { assert(destinations.size() > 0); - std::vector destDeclarations; + modernjson::json destDeclarations; for(auto const& destination : destinations) { modernjson::json destEntry; destEntry["location"] = locationNames.at(destination.getLocationIndex()); @@ -696,17 +993,20 @@ namespace storm { } if (!prob1) { destEntry["probability"]["exp"] = buildExpression(destination.getProbability(), constants, globalVariables, localVariables); + if (commentExpressions) { + destEntry["probability"]["comment"] = destination.getProbability().toString(); + } } if (!destination.getOrderedAssignments().empty()) { - destEntry["assignments"] = buildAssignmentArray(destination.getOrderedAssignments(), constants, globalVariables, localVariables); + destEntry["assignments"] = buildAssignmentArray(destination.getOrderedAssignments(), constants, globalVariables, localVariables, commentExpressions); } - destDeclarations.push_back(destEntry); + destDeclarations.push_back(std::move(destEntry)); } - return modernjson::json(destDeclarations); + return destDeclarations; } - modernjson::json buildEdges(std::vector const& edges , std::map const& actionNames, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) { - std::vector edgeDeclarations; + modernjson::json buildEdges(std::vector const& edges , std::map const& actionNames, std::map const& locationNames, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) { + modernjson::json edgeDeclarations; for(auto const& edge : edges) { if (edge.getGuard().isFalse()) { continue; @@ -719,56 +1019,62 @@ namespace storm { } if(edge.hasRate()) { edgeEntry["rate"]["exp"] = buildExpression(edge.getRate(), constants, globalVariables, localVariables); + if (commentExpressions) { + edgeEntry["rate"]["comment"] = edge.getRate().toString(); + } } if (!edge.getGuard().isTrue()) { edgeEntry["guard"]["exp"] = buildExpression(edge.getGuard(), constants, globalVariables, localVariables); + if (commentExpressions) { + edgeEntry["guard"]["comment"] = edge.getGuard().toString(); + } } - edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames, constants, globalVariables, localVariables); + edgeEntry["destinations"] = buildDestinations(edge.getDestinations(), locationNames, constants, globalVariables, localVariables, commentExpressions); if (!edge.getAssignments().empty()) { - edgeEntry["assignments"] = buildAssignmentArray(edge.getAssignments(), constants, globalVariables, localVariables); + edgeEntry["assignments"] = buildAssignmentArray(edge.getAssignments(), constants, globalVariables, localVariables, commentExpressions); } - edgeDeclarations.push_back(edgeEntry); + edgeDeclarations.push_back(std::move(edgeEntry)); } - return modernjson::json(edgeDeclarations); + return edgeDeclarations; } - modernjson::json buildAutomataArray(std::vector const& automata, std::map const& actionNames, std::vector const& constants, VariableSet const& globalVariables) { - std::vector automataDeclarations; + modernjson::json buildAutomataArray(std::vector const& automata, std::map const& actionNames, std::vector const& constants, VariableSet const& globalVariables, bool commentExpressions) { + modernjson::json automataDeclarations; for(auto const& automaton : automata) { modernjson::json autoEntry; autoEntry["name"] = automaton.getName(); autoEntry["variables"] = buildVariablesArray(automaton.getVariables(), constants, globalVariables, automaton.getVariables()); + if (!automaton.getFunctionDefinitions().empty()) { + autoEntry["functions"] = buildFunctionsArray(automaton.getFunctionDefinitions(), constants, globalVariables, automaton.getVariables()); + } if(automaton.hasRestrictedInitialStates()) { autoEntry["restrict-initial"]["exp"] = buildExpression(automaton.getInitialStatesRestriction(), constants, globalVariables, automaton.getVariables()); } - autoEntry["locations"] = buildLocationsArray(automaton.getLocations(), constants, globalVariables, automaton.getVariables()); + autoEntry["locations"] = buildLocationsArray(automaton.getLocations(), constants, globalVariables, automaton.getVariables(), commentExpressions); autoEntry["initial-locations"] = buildInitialLocations(automaton); - autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables, automaton.getVariables()); - automataDeclarations.push_back(autoEntry); + autoEntry["edges"] = buildEdges(automaton.getEdges(), actionNames, automaton.buildIdToLocationNameMap(), constants, globalVariables, automaton.getVariables(), commentExpressions); + automataDeclarations.push_back(std::move(autoEntry)); } - return modernjson::json(automataDeclarations); + return automataDeclarations; } - - void JsonExporter::convertModel(storm::jani::Model const& janiModel) { + void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) { + modelFeatures = janiModel.getModelFeatures(); jsonStruct["jani-version"] = janiModel.getJaniVersion(); jsonStruct["name"] = janiModel.getName(); jsonStruct["type"] = to_string(janiModel.getModelType()); jsonStruct["actions"] = buildActionArray(janiModel.getActions()); jsonStruct["constants"] = buildConstantsArray(janiModel.getConstants()); jsonStruct["variables"] = buildVariablesArray(janiModel.getGlobalVariables(), janiModel.getConstants(), janiModel.getGlobalVariables()); + if (!janiModel.getGlobalFunctionDefinitions().empty()) { + jsonStruct["functions"] = buildFunctionsArray(janiModel.getGlobalFunctionDefinitions(), janiModel.getConstants(), janiModel.getGlobalVariables()); + } jsonStruct["restrict-initial"]["exp"] = buildExpression(janiModel.getInitialStatesRestriction(), janiModel.getConstants(), janiModel.getGlobalVariables()); - jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables()); + jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables(), commentExpressions); jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition()); - std::vector standardFeatureVector = {"derived-operators"}; - jsonStruct["features"] = standardFeatureVector; - } - - - std::string janiFilterTypeString(storm::modelchecker::FilterType const& ft) { switch(ft) { case storm::modelchecker::FilterType::MIN: @@ -797,29 +1103,37 @@ namespace storm { } } - modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model) { + modernjson::json convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures) { modernjson::json propDecl; propDecl["states"]["op"] = "initial"; propDecl["op"] = "filter"; propDecl["fun"] = janiFilterTypeString(fe.getFilterType()); - propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model); + propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model, modelFeatures); return propDecl; } void JsonExporter::convertProperties( std::vector const& formulas, storm::jani::Model const& model) { - std::vector properties; + modernjson::json properties; + + // Unset model-features that only relate to properties. These are only set if such properties actually exist. + modelFeatures.remove(storm::jani::ModelFeature::StateExitRewards); + uint64_t index = 0; for(auto const& f : formulas) { modernjson::json propDecl; propDecl["name"] = f.getName(); - propDecl["expression"] = convertFilterExpression(f.getFilter(), model); + propDecl["expression"] = convertFilterExpression(f.getFilter(), model, modelFeatures); ++index; - properties.push_back(propDecl); + properties.push_back(std::move(propDecl)); } - jsonStruct["properties"] = properties; + jsonStruct["properties"] = std::move(properties); } - + modernjson::json JsonExporter::finalize() { + jsonStruct["features"] = modernjson::json::parse(modelFeatures.toString()); + return jsonStruct; + } + } } diff --git a/src/storm/storage/jani/JSONExporter.h b/src/storm/storage/jani/JSONExporter.h index 17fa97ad6..0bd1486f2 100644 --- a/src/storm/storage/jani/JSONExporter.h +++ b/src/storm/storage/jani/JSONExporter.h @@ -2,8 +2,9 @@ #include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" #include "storm/logic/FormulaVisitor.h" -#include "Model.h" +#include "storm/storage/jani/Model.h" #include "storm/storage/jani/Property.h" #include "storm/adapters/RationalNumberAdapter.h" // JSON parser @@ -15,10 +16,10 @@ namespace modernjson { namespace storm { namespace jani { - class ExpressionToJson : public storm::expressions::ExpressionVisitor { + class ExpressionToJson : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { public: - static modernjson::json translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables); + static modernjson::json translate(storm::expressions::Expression const& expr, std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set const& auxiliaryVariables); virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data); @@ -30,18 +31,25 @@ namespace storm { virtual boost::any visit(storm::expressions::BooleanLiteralExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::IntegerLiteralExpression const& expression, boost::any const& data); virtual boost::any visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data); + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data); + private: - ExpressionToJson(std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables) : constants(constants), globalVariables(globalVariables), localVariables(localVariables) {} + ExpressionToJson(std::vector const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set const& auxiliaryVariables) : constants(constants), globalVariables(globalVariables), localVariables(localVariables), auxiliaryVariables(auxiliaryVariables) {} std::vector const& constants; VariableSet const& globalVariables; VariableSet const& localVariables; + std::unordered_set auxiliaryVariables; }; class FormulaToJaniJson : public storm::logic::FormulaVisitor { public: - static modernjson::json translate(storm::logic::Formula const& formula, storm::jani::Model const& modeln); + static modernjson::json translate(storm::logic::Formula const& formula, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures); + bool containsStateExitRewards() const; // Returns true iff the previously translated formula contained state exit rewards virtual boost::any visit(storm::logic::AtomicExpressionFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::AtomicLabelFormula const& f, boost::any const& data) const; virtual boost::any visit(storm::logic::BinaryBooleanStateFormula const& f, boost::any const& data) const; @@ -64,32 +72,35 @@ namespace storm { virtual boost::any visit(storm::logic::UntilFormula const& f, boost::any const& data) const; private: - FormulaToJaniJson(storm::jani::Model const& model) : model(model) { } + FormulaToJaniJson(storm::jani::Model const& model) : model(model), stateExitRewards(false) { } modernjson::json constructPropertyInterval(boost::optional const& lower, boost::optional const& lowerExclusive, boost::optional const& upper, boost::optional const& upperExclusive) const; + + modernjson::json constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const; + modernjson::json constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation, std::string const& rewardModelName) const; + modernjson::json constructStandardRewardAccumulation(std::string const& rewardModelName) const; storm::jani::Model const& model; + mutable bool stateExitRewards; }; class JsonExporter { JsonExporter() = default; public: - static void toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid = true); - static void toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& ostream, bool checkValid = false); + static void toFile(storm::jani::Model const& janiModel, std::vector const& formulas, std::string const& filepath, bool checkValid = true, bool compact = false); + static void toStream(storm::jani::Model const& janiModel, std::vector const& formulas, std::ostream& ostream, bool checkValid = false, bool compact = false); private: - void convertModel(storm::jani::Model const& model); + void convertModel(storm::jani::Model const& model, bool commentExpressions = true); void convertProperties(std::vector const& formulas, storm::jani::Model const& model); void appendVariableDeclaration(storm::jani::Variable const& variable); - modernjson::json finalize() { - return jsonStruct; - } + modernjson::json finalize(); modernjson::json jsonStruct; - + storm::jani::ModelFeatures modelFeatures; }; } diff --git a/src/storm/storage/jani/JaniLocationExpander.cpp b/src/storm/storage/jani/JaniLocationExpander.cpp new file mode 100644 index 000000000..8c06fb3c1 --- /dev/null +++ b/src/storm/storage/jani/JaniLocationExpander.cpp @@ -0,0 +1,123 @@ +#include "storm/storage/jani/JaniLocationExpander.h" + +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + +#include "storm/storage/expressions/ExpressionManager.h" +#include "storm/exceptions/NotSupportedException.h" +#include "storm/exceptions/IllegalArgumentException.h" + + +namespace storm { + namespace jani { + JaniLocationExpander::JaniLocationExpander(Model const& origModel) : original(origModel) { + + } + + void JaniLocationExpander::transform(std::string const& automatonName, std::string const& variableName) { + STORM_LOG_THROW(original.hasAutomaton(automatonName), storm::exceptions::IllegalArgumentException, "Model has no automaton with name " << automatonName << ". "); + STORM_LOG_THROW(original.getAutomaton(automatonName).hasVariable(variableName), storm::exceptions::IllegalArgumentException, "Automaton " << automatonName << " has no variable with name " << variableName << ". "); + newModel = original; + newModel.replaceAutomaton(newModel.getAutomatonIndex(automatonName), transformAutomaton(original.getAutomaton(automatonName), variableName)); + } + + + Model const& JaniLocationExpander::getResult() const { + return newModel; + } + + Automaton JaniLocationExpander::transformAutomaton(Automaton const& automaton, std::string const& variableName) { + + Automaton newAutomaton(automaton.getName(), automaton.getLocationExpressionVariable()); + int64_t initialVariableValue; + int64_t variableLowerBound; + int64_t variableUpperBound; + storm::expressions::Variable eliminatedExpressionVariable; + const storm::jani::Variable* variable; + + for (auto const& var : automaton.getVariables()) { + if (var.getName() == variableName) { + // This variable will be eliminated in the new automaton. + STORM_LOG_THROW(var.hasInitExpression(), storm::exceptions::IllegalArgumentException, "Variable to be eliminated has to have an initexpression."); + STORM_LOG_THROW(var.isBoundedIntegerVariable(), storm::exceptions::IllegalArgumentException, "Variable to be eliminated has to be an bounded integer variable."); + STORM_LOG_THROW(!var.isTransient(), storm::exceptions::IllegalArgumentException, "Cannot eliminate transient variable"); + + variableUpperBound = var.asBoundedIntegerVariable().getUpperBound().evaluateAsInt(); + variableLowerBound = var.asBoundedIntegerVariable().getLowerBound().evaluateAsInt(); + initialVariableValue = var.getInitExpression().evaluateAsInt(); + variable = &var; + eliminatedExpressionVariable = var.getExpressionVariable(); + + } else { + // Other variables are just copied. + newAutomaton.addVariable(var); + } + } + + STORM_LOG_THROW(!automaton.getInitialStatesRestriction().containsVariable({eliminatedExpressionVariable}), storm::exceptions::NotSupportedException, "Elimination of variable that occurs in the initial state restriction is not allowed"); + newAutomaton.setInitialStatesRestriction(automaton.getInitialStatesRestriction()); + + + std::map substitutionMap; + std::map> locationNames; + std::map> locationVariableValueMap; + for (auto const& loc : automaton.getLocations()) { + locationNames[loc.getName()] = std::vector(); + uint64_t origIndex = automaton.getLocationIndex(loc.getName()); + + for (int64_t i = variableLowerBound; i <= variableUpperBound; i++) { + std::string newLocationName = loc.getName() + "_" + variableName + "_" + std::to_string(i); + substitutionMap[eliminatedExpressionVariable] = original.getExpressionManager().integer(i); + std::cout << "eliminate " << eliminatedExpressionVariable.getName() << " with " << i << std::endl; + OrderedAssignments newAssignments = loc.getAssignments().clone(); + newAssignments.substitute(substitutionMap); + std::cout << newAssignments << std::endl; + uint64_t newLocationIndex = newAutomaton.addLocation(Location(newLocationName, newAssignments)); + + locationVariableValueMap[origIndex][i] = newLocationIndex; + locationNames[loc.getName()].push_back(newLocationName); + } + } + + + + for (auto const& edge : automaton.getEdges()) { + for (auto const& newValueAndLocation : locationVariableValueMap[edge.getSourceLocationIndex()]) { + substitutionMap[eliminatedExpressionVariable] = original.getExpressionManager().integer(newValueAndLocation.first); + + uint64_t newSourceIndex = newValueAndLocation.second; + storm::expressions::Expression newGuard = substituteJaniExpression(edge.getGuard(), substitutionMap).simplify(); + if (!newGuard.containsVariables() && !newGuard.evaluateAsBool()) { + continue; + } + std::shared_ptr templateEdge = std::make_shared(newGuard); + + STORM_LOG_THROW(edge.getAssignments().empty(), storm::exceptions::NotImplementedException, "Support for edge-assignments is not implemented"); + + std::vector> destinationLocationsAndProbabilities; + for (auto const& destination : edge.getDestinations()) { + OrderedAssignments oa(destination.getOrderedAssignments().clone()); + oa.substitute(substitutionMap); + int64_t value; + for (auto const& assignment : oa) { + if (assignment.getVariable() == *variable) { + oa.remove(assignment); + value = assignment.getAssignedExpression().evaluateAsInt(); + break; + } + } + TemplateEdgeDestination ted(oa); + templateEdge->addDestination(ted); + destinationLocationsAndProbabilities.emplace_back(locationVariableValueMap[destination.getLocationIndex()][value], substituteJaniExpression(destination.getProbability(), substitutionMap)); + } + newAutomaton.addEdge(storm::jani::Edge(newSourceIndex, edge.getActionIndex(), edge.hasRate() ? boost::optional(substituteJaniExpression(edge.getRate(), substitutionMap)) : boost::none, templateEdge, destinationLocationsAndProbabilities)); + + } + } + return newAutomaton; + + + } + + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/JaniLocationExpander.h b/src/storm/storage/jani/JaniLocationExpander.h new file mode 100644 index 000000000..6b4ec0709 --- /dev/null +++ b/src/storm/storage/jani/JaniLocationExpander.h @@ -0,0 +1,26 @@ +#pragma once + +#include "storm/storage/jani/Model.h" +#include "storm/storage/jani/Automaton.h" + + +namespace storm { + namespace jani { + class JaniLocationExpander { + public: + JaniLocationExpander(Model const& original); + void transform(std::string const& automatonName, std::string const& variableName); + Model const& getResult() const; + + private: + Model const& original; + Model newModel; + + Automaton transformAutomaton(Automaton const& automaton, std::string const& variableName); + + + + }; + } + +} diff --git a/src/storm/storage/jani/LValue.cpp b/src/storm/storage/jani/LValue.cpp new file mode 100644 index 000000000..57d80bfdd --- /dev/null +++ b/src/storm/storage/jani/LValue.cpp @@ -0,0 +1,101 @@ +#include "storm/storage/jani/LValue.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/NotSupportedException.h" + +namespace storm { + namespace jani { + + LValue::LValue(storm::jani::Variable const& variable) : variable(&variable) { + // Intentionally left empty + } + + LValue::LValue(LValue const& array, storm::expressions::Expression const& index) : arrayIndex(index) { + STORM_LOG_THROW(array.isVariable(), storm::exceptions::NotSupportedException, "Nested arrays as LValues are currently not implemented."); + variable = &array.getVariable(); + } + + bool LValue::isVariable() const { + return !arrayIndex.isInitialized(); + } + + storm::jani::Variable const& LValue::getVariable() const { + STORM_LOG_ASSERT(isVariable(), "Tried to get the variable of an LValue, that actually is not a variable."); + return *variable; + } + + bool LValue::isArrayAccess() const { + return arrayIndex.isInitialized(); + } + + storm::jani::ArrayVariable const& LValue::getArray() const { + STORM_LOG_ASSERT(isArrayAccess(), "Tried to get the array variable of an LValue that is not an array access."); + STORM_LOG_ASSERT(variable->isArrayVariable(), "Tried to get the array variable of an array access LValue, but the variable is not of type array."); + return variable->asArrayVariable(); + } + + storm::expressions::Expression const& LValue::getArrayIndex() const { + STORM_LOG_ASSERT(isArrayAccess(), "Tried to get the array index of an LValue that is not an array access."); + return arrayIndex; + } + + void LValue::setArrayIndex(storm::expressions::Expression const& newIndex) { + STORM_LOG_ASSERT(isArrayAccess(), "Tried to set the array index of an LValue that is not an array access."); + arrayIndex = newIndex; + } + + bool LValue::isTransient() const { + return variable->isTransient(); + } + + LValue LValue::changeAssignmentVariables(std::map> const& remapping) const { + if (isVariable()) { + return LValue(remapping.at(variable)); + } else { + STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); + return LValue(LValue(remapping.at(variable)), arrayIndex); + } + } + + + bool LValue::operator<(LValue const& other) const { + if (isVariable()) { + return !other.isVariable() || variable->getExpressionVariable() < other.getVariable().getExpressionVariable(); + } else { + STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); + if (other.isVariable()) { + return false; + } + STORM_LOG_ASSERT(other.isArrayAccess(), "Unhandled LValue."); + if (getArray().getExpressionVariable() < other.getArray().getExpressionVariable()) { + return true; + } else if (other.getArray().getExpressionVariable() < getArray().getExpressionVariable()) { + return false; + } else { + return std::less()(arrayIndex, other.getArrayIndex()); + } + } + } + + bool LValue::operator==(LValue const& other) const { + if (isVariable()) { + return other.isVariable() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable(); + } else { + STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); + return other.isArrayAccess() && getArray().getExpressionVariable() == other.getArray().getExpressionVariable() && getArrayIndex().isSyntacticallyEqual(other.getArrayIndex()); + } + } + + std::ostream& operator<<(std::ostream& stream, LValue const& lValue) { + if (lValue.isVariable()) { + stream << lValue.getVariable().getName(); + } else { + STORM_LOG_ASSERT(lValue.isArrayAccess(), "Unhandled LValue."); + stream << lValue.getArray().getName() << "[" << lValue.getArrayIndex() << "]"; + } + return stream; + } + + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/LValue.h b/src/storm/storage/jani/LValue.h new file mode 100644 index 000000000..1c6fa32c7 --- /dev/null +++ b/src/storm/storage/jani/LValue.h @@ -0,0 +1,42 @@ +#pragma once + +#include "storm/storage/jani/ArrayVariable.h" +#include "storm/storage/expressions/Expressions.h" + +namespace storm { + namespace jani { + + class LValue { + public: + explicit LValue(storm::jani::Variable const& variable); + LValue(LValue const& array, storm::expressions::Expression const& index); + + LValue(LValue const&) = default; + bool operator==(LValue const& other) const; + + bool isVariable() const; + storm::jani::Variable const& getVariable() const; + + bool isArrayAccess() const; + storm::jani::ArrayVariable const& getArray() const; + storm::expressions::Expression const& getArrayIndex() const; + void setArrayIndex(storm::expressions::Expression const& newIndex); + + bool isTransient() const; + bool operator< (LValue const& other) const; + + LValue changeAssignmentVariables(std::map> const& remapping) const; + + friend std::ostream& operator<<(std::ostream& stream, LValue const& lvalue); + + private: + + // The variable being assigned. + storm::jani::Variable const* variable; + + + // In case of an array access LValue, this is the accessed index of the array. + storm::expressions::Expression arrayIndex; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/Location.cpp b/src/storm/storage/jani/Location.cpp index b957d5e9a..7831436a7 100644 --- a/src/storm/storage/jani/Location.cpp +++ b/src/storm/storage/jani/Location.cpp @@ -10,6 +10,10 @@ namespace storm { Location::Location(std::string const& name, std::vector const& transientAssignments) : name(name), assignments(transientAssignments) { // Intentionally left empty. } + + Location::Location(std::string const& name, OrderedAssignments const& assignments) : name(name), assignments(assignments) { + // Intentionally left empty. + } std::string const& Location::getName() const { return name; @@ -19,6 +23,10 @@ namespace storm { return assignments; } + OrderedAssignments& Location::getAssignments() { + return assignments; + } + void Location::addTransientAssignment(storm::jani::Assignment const& assignment) { STORM_LOG_THROW(assignment.isTransient(), storm::exceptions::InvalidArgumentException, "Must not add non-transient assignment to location."); assignments.add(assignment); diff --git a/src/storm/storage/jani/Location.h b/src/storm/storage/jani/Location.h index b2bda7b23..1fc3cd65d 100644 --- a/src/storm/storage/jani/Location.h +++ b/src/storm/storage/jani/Location.h @@ -18,7 +18,8 @@ namespace storm { * Creates a new location. */ Location(std::string const& name, std::vector const& transientAssignments = {}); - + + Location(std::string const& name, OrderedAssignments const& assignments); /*! * Retrieves the name of the location. */ @@ -29,6 +30,11 @@ namespace storm { */ OrderedAssignments const& getAssignments() const; + /*! + * Retrieves the assignments of this location. + */ + OrderedAssignments& getAssignments(); + /*! * Adds the given transient assignment to this location. */ diff --git a/src/storm/storage/jani/Model.cpp b/src/storm/storage/jani/Model.cpp index 37031bb4b..79a37d384 100644 --- a/src/storm/storage/jani/Model.cpp +++ b/src/storm/storage/jani/Model.cpp @@ -16,6 +16,9 @@ #include "storm/storage/jani/CompositionInformationVisitor.h" #include "storm/storage/jani/Compositions.h" #include "storm/storage/jani/JSONExporter.h" +#include "storm/storage/jani/ArrayEliminator.h" +#include "storm/storage/jani/FunctionEliminator.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" @@ -67,6 +70,7 @@ namespace storm { if (this != &other) { this->name = other.name; this->modelType = other.modelType; + this->modelFeatures = other.modelFeatures; this->version = other.version; this->expressionManager = other.expressionManager; this->actions = other.actions; @@ -75,10 +79,12 @@ namespace storm { this->constants = other.constants; this->constantToIndex = other.constantToIndex; this->globalVariables = other.globalVariables; + this->nonTrivialRewardModels = other.nonTrivialRewardModels; this->automata = other.automata; this->automatonToIndex = other.automatonToIndex; this->composition = other.composition; this->initialStatesRestriction = other.initialStatesRestriction; + this->globalFunctions = other.globalFunctions; // Now that we have copied all the data, we need to fix all assignments as they contain references to the old model. std::map> remapping; @@ -112,10 +118,22 @@ namespace storm { return modelType; } + ModelFeatures const& Model::getModelFeatures() const { + return modelFeatures; + } + + ModelFeatures& Model::getModelFeatures() { + return modelFeatures; + } + std::string const& Model::getName() const { return name; } + void Model::setName(std::string const& newName) { + name = newName; + } + struct ConditionalMetaEdge { ConditionalMetaEdge() : actionIndex(0) { // Intentionally left empty. @@ -212,11 +230,14 @@ namespace storm { if (!SynchronizationVector::isNoActionInput(actionName)) { components.push_back(i); uint64_t actionIndex = oldModel.getActionIndex(actionName); + // store that automaton occurs in the sync vector. participatingAutomataAndActions.push_back(std::make_pair(composedAutomata[i], actionIndex)); + // Store for later that this action is one of the possible actions that synchronise synchronizingActionIndices[i].insert(actionIndex); } } - + + // What is the action label that should be attached to the composed actions uint64_t resultingActionIndex = Model::SILENT_ACTION_INDEX; if (vector.getOutput() != Model::SILENT_ACTION_NAME) { if (newModel.hasAction(vector.getOutput())) { @@ -415,6 +436,8 @@ namespace storm { // Otherwise, we need to actually flatten composition. Model flattenedModel(this->getName() + "_flattened", this->getModelType(), this->getJaniVersion(), this->getManager().shared_from_this()); + + flattenedModel.getModelFeatures() = getModelFeatures(); // Get an SMT solver for computing possible guard combinations. std::unique_ptr solver = smtSolverFactory->create(*expressionManager); @@ -439,6 +462,18 @@ namespace storm { variableRemapping.emplace(&variable, flattenedModel.addVariable(*renamedVariable)); } + for (auto const& constant : getConstants()) { + flattenedModel.addConstant(constant); + } + + for (auto const& nonTrivRew : getNonTrivialRewardExpressions()) { + flattenedModel.addNonTrivialRewardExpression(nonTrivRew.first, nonTrivRew.second); + } + + for (auto const& funDef : getGlobalFunctionDefinitions()) { + flattenedModel.addFunctionDefinition(funDef.second); + } + std::vector> composedAutomata; for (auto const& element : parallelComposition.getSubcompositions()) { STORM_LOG_THROW(element->isAutomatonComposition(), storm::exceptions::WrongFormatException, "Cannot flatten recursive (not standard-compliant) composition."); @@ -459,7 +494,11 @@ namespace storm { // Assert the values of the constants. for (auto const& constant : this->getConstants()) { if (constant.isDefined()) { - solver->add(constant.getExpressionVariable() == constant.getExpression()); + if (constant.isBooleanConstant()) { + solver->add(storm::expressions::iff(constant.getExpressionVariable(), constant.getExpression())); + } else { + solver->add(constant.getExpressionVariable() == constant.getExpression()); + } } } // Assert the bounds of the global variables. @@ -530,6 +569,9 @@ namespace storm { if (automaton.get().hasInitialStatesRestriction()) { initialStatesRestriction = initialStatesRestriction && automaton.get().getInitialStatesRestriction(); } + for (auto const& funDef : automaton.get().getFunctionDefinitions()) { + newAutomaton.addFunctionDefinition(funDef.second); + } } newAutomaton.setInitialStatesRestriction(this->getInitialStatesExpression(composedAutomata)); @@ -580,12 +622,12 @@ namespace storm { return nonsilentActionIndices; } - uint64_t Model::addConstant(Constant const& constant) { + void Model::addConstant(Constant const& constant) { auto it = constantToIndex.find(constant.getName()); STORM_LOG_THROW(it == constantToIndex.end(), storm::exceptions::WrongFormatException, "Cannot add constant with name '" << constant.getName() << "', because a constant with that name already exists."); constantToIndex.emplace(constant.getName(), constants.size()); constants.push_back(constant); - return constants.size() - 1; + // Note that we should not return a reference to the inserted constant as it might get invalidated when more constants are added. } bool Model::hasConstant(std::string const& name) const { @@ -605,7 +647,15 @@ namespace storm { std::vector& Model::getConstants() { return constants; } - + + std::size_t Model::getNumberOfEdges() const { + size_t res = 0; + for (auto const& aut : getAutomata()) { + res += aut.getNumberOfEdges(); + } + return res; + } + Variable const& Model::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { return addVariable(variable.asBooleanVariable()); @@ -615,6 +665,8 @@ namespace storm { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); + } else if (variable.isArrayVariable()) { + return addVariable(variable.asArrayVariable()); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Variable has invalid type."); } @@ -635,6 +687,10 @@ namespace storm { RealVariable const& Model::addVariable(RealVariable const& variable) { return globalVariables.addVariable(variable); } + + ArrayVariable const& Model::addVariable(ArrayVariable const& variable) { + return globalVariables.addVariable(variable); + } VariableSet& Model::getGlobalVariables() { return globalVariables; @@ -689,14 +745,80 @@ namespace storm { return false; } - storm::expressions::ExpressionManager& Model::getExpressionManager() { - return *expressionManager; + FunctionDefinition const& Model::addFunctionDefinition(FunctionDefinition const& functionDefinition) { + auto insertionRes = globalFunctions.emplace(functionDefinition.getName(), functionDefinition); + STORM_LOG_THROW(insertionRes.second, storm::exceptions::InvalidOperationException, " a function with the name " << functionDefinition.getName() << " already exists in this model."); + return insertionRes.first->second; + } + + std::unordered_map const& Model::getGlobalFunctionDefinitions() const { + return globalFunctions; + } + + std::unordered_map& Model::getGlobalFunctionDefinitions() { + return globalFunctions; } - storm::expressions::ExpressionManager const& Model::getExpressionManager() const { + storm::expressions::ExpressionManager& Model::getExpressionManager() const { return *expressionManager; } + bool Model::addNonTrivialRewardExpression(std::string const& identifier, storm::expressions::Expression const& rewardExpression) { + if (nonTrivialRewardModels.count(identifier) > 0) { + return false; + } else { + nonTrivialRewardModels.emplace(identifier, rewardExpression); + return true; + } + } + + storm::expressions::Expression Model::getRewardModelExpression(std::string const& identifier) const { + auto findRes = nonTrivialRewardModels.find(identifier); + if (findRes != nonTrivialRewardModels.end()) { + return findRes->second; + } else { + // Check whether the reward model refers to a global variable + if (globalVariables.hasVariable(identifier)) { + return globalVariables.getVariable(identifier).getExpressionVariable().getExpression(); + } else { + STORM_LOG_THROW(identifier.empty(), storm::exceptions::InvalidArgumentException, "Cannot find unknown reward model '" << identifier << "'."); + STORM_LOG_THROW(nonTrivialRewardModels.size() + globalVariables.getNumberOfNumericalTransientVariables() == 1, storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous."); + if (nonTrivialRewardModels.size() == 1) { + return nonTrivialRewardModels.begin()->second; + } else { + for (auto const& variable : globalVariables.getTransientVariables()) { + if (variable.isRealVariable() || variable.isUnboundedIntegerVariable() || variable.isBoundedIntegerVariable()) { + return variable.getExpressionVariable().getExpression(); + } + } + } + } + } + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot find unknown reward model '" << identifier << "'."); + return storm::expressions::Expression(); + } + + std::vector> Model::getAllRewardModelExpressions() const { + std::vector> result; + for (auto const& nonTrivExpr : nonTrivialRewardModels) { + result.emplace_back(nonTrivExpr.first, nonTrivExpr.second); + } + for (auto const& variable : globalVariables.getTransientVariables()) { + if (variable.isRealVariable() || variable.isUnboundedIntegerVariable() || variable.isBoundedIntegerVariable()) { + result.emplace_back(variable.getName(), variable.getExpressionVariable().getExpression()); + } + } + return result; + } + + std::unordered_map const& Model::getNonTrivialRewardExpressions() const { + return nonTrivialRewardModels; + } + + std::unordered_map& Model::getNonTrivialRewardExpressions() { + return nonTrivialRewardModels; + } + uint64_t Model::addAutomaton(Automaton const& automaton) { auto it = automatonToIndex.find(automaton.getName()); STORM_LOG_THROW(it == automatonToIndex.end(), storm::exceptions::WrongFormatException, "Automaton with name '" << automaton.getName() << "' already exists."); @@ -712,7 +834,15 @@ namespace storm { std::vector const& Model::getAutomata() const { return automata; } - + + bool Model::hasAutomaton(std::string const& name) const { + return automatonToIndex.find(name) != automatonToIndex.end(); + } + + void Model::replaceAutomaton(uint64_t index, Automaton const& automaton) { + automata[index] = automaton; + } + Automaton& Model::getAutomaton(std::string const& name) { auto it = automatonToIndex.find(name); STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'."); @@ -743,11 +873,6 @@ namespace storm { } std::shared_ptr Model::getStandardSystemComposition() const { - // If there's just one automaton, we must not use the parallel composition operator. - if (this->getNumberOfAutomata() == 1) { - return std::make_shared(this->getAutomata().front().getName()); - } - // Determine the action indices used by each of the automata and create the standard subcompositions. std::set allActionIndices; std::vector> automatonActionIndices; @@ -872,18 +997,29 @@ namespace storm { std::map constantSubstitution; for (auto& constant : result.getConstants()) { if (constant.isDefined()) { - constant.define(constant.getExpression().substitute(constantSubstitution)); + constant.define(substituteJaniExpression(constant.getExpression(), constantSubstitution)); constantSubstitution[constant.getExpressionVariable()] = constant.getExpression(); } } + for (auto& functionDefinition : result.getGlobalFunctionDefinitions()) { + functionDefinition.second.substitute(constantSubstitution); + } + // Substitute constants in all global variables. for (auto& variable : result.getGlobalVariables().getBoundedIntegerVariables()) { variable.substitute(constantSubstitution); } + for (auto& variable : result.getGlobalVariables().getArrayVariables()) { + variable.substitute(constantSubstitution); + } // Substitute constants in initial states expression. - result.setInitialStatesRestriction(this->getInitialStatesRestriction().substitute(constantSubstitution)); + result.setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), constantSubstitution)); + + for (auto& rewMod : result.getNonTrivialRewardExpressions()) { + rewMod.second = substituteJaniExpression(rewMod.second, constantSubstitution); + } // Substitute constants in variables of automata and their edges. for (auto& automaton : result.getAutomata()) { @@ -893,6 +1029,12 @@ namespace storm { return result; } + Model Model::substituteConstantsFunctions() const { + auto result = substituteConstants(); + result.substituteFunctions(); + return result; + } + std::map Model::getConstantsSubstitution() const { std::map result; @@ -905,6 +1047,105 @@ namespace storm { return result; } + void Model::substitute(std::map const& substitution) { + // substitute in all defining expressions of constants + for (auto& constant : this->getConstants()) { + if (constant.isDefined()) { + constant.define(substituteJaniExpression(constant.getExpression(), substitution)); + } + } + + for (auto& functionDefinition : this->getGlobalFunctionDefinitions()) { + functionDefinition.second.substitute(substitution); + } + + // Substitute in all global variables. + for (auto& variable : this->getGlobalVariables().getBoundedIntegerVariables()) { + variable.substitute(substitution); + } + for (auto& variable : this->getGlobalVariables().getArrayVariables()) { + variable.substitute(substitution); + } + + // Substitute in initial states expression. + this->setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), substitution)); + + for (auto& rewMod : getNonTrivialRewardExpressions()) { + rewMod.second = substituteJaniExpression(rewMod.second, substitution); + } + + // Substitute in variables of automata and their edges. + for (auto& automaton : this->getAutomata()) { + automaton.substitute(substitution); + } + } + + void Model::substituteFunctions() { + std::vector emptyPropertyVector; + substituteFunctions(emptyPropertyVector); + } + + void Model::substituteFunctions(std::vector& properties) { + eliminateFunctions(*this, properties); + } + + bool Model::containsArrayVariables() const { + if (getGlobalVariables().containsArrayVariables()) { + return true; + } + for (auto const& a : getAutomata()) { + if (a.getVariables().containsArrayVariables()) { + return true; + } + } + return false; + } + + ArrayEliminatorData Model::eliminateArrays(bool keepNonTrivialArrayAccess) { + ArrayEliminator arrayEliminator; + return arrayEliminator.eliminate(*this, keepNonTrivialArrayAccess); + } + + void Model::eliminateArrays(std::vector& properties) { + auto data = eliminateArrays(false); + for (auto& p : properties) { + data.transformProperty(p); + } + } + + ModelFeatures Model::restrictToFeatures(ModelFeatures const& modelFeatures) { + std::vector emptyPropertyVector; + return restrictToFeatures(modelFeatures, emptyPropertyVector); + } + + ModelFeatures Model::restrictToFeatures(ModelFeatures const& features, std::vector& properties) { + + ModelFeatures uncheckedFeatures = getModelFeatures(); + // Check if functions need to be eliminated. + if (uncheckedFeatures.hasFunctions() && !features.hasFunctions()) { + substituteFunctions(properties); + } + uncheckedFeatures.remove(ModelFeature::Functions); + + // Check if arrays need to be eliminated. This should be done after! eliminating the functions + if (uncheckedFeatures.hasArrays() && !features.hasArrays()) { + eliminateArrays(properties); + } + uncheckedFeatures.remove(ModelFeature::Arrays); + + // There is no elimination for state exit rewards + if (features.hasStateExitRewards()) { + uncheckedFeatures.remove(ModelFeature::StateExitRewards); + } + + // There is no elimination of derived operators + if (features.hasDerivedOperators()) { + uncheckedFeatures.remove(ModelFeature::DerivedOperators); + } + + return uncheckedFeatures; + } + void Model::setInitialStatesRestriction(storm::expressions::Expression const& initialStatesRestriction) { this->initialStatesRestriction = initialStatesRestriction; } @@ -917,6 +1158,26 @@ namespace storm { return initialStatesRestriction; } + bool Model::hasNonTrivialInitialStates() const { + if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) { + return true; + } else { + for (auto const& variable : this->getGlobalVariables()) { + if (variable.hasInitExpression() && !variable.isTransient()) { + return true; + } + } + + for (auto const& automaton : this->automata) { + if (automaton.hasNonTrivialInitialStates()) { + return true; + } + } + } + + return false; + } + storm::expressions::Expression Model::getInitialStatesExpression() const { std::vector> allAutomata; for (auto const& automaton : this->getAutomata()) { @@ -925,6 +1186,21 @@ namespace storm { return getInitialStatesExpression(allAutomata); } + bool Model::hasTrivialInitialStatesExpression() const { + if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) { + return false; + } + + bool result = true; + for (auto const& automaton : this->getAutomata()) { + result &= automaton.hasTrivialInitialStatesExpression(); + if (!result) { + break; + } + } + return result; + } + storm::expressions::Expression Model::getInitialStatesExpression(std::vector> const& automata) const { // Start with the restriction of variables. storm::expressions::Expression result = initialStatesRestriction; @@ -966,6 +1242,7 @@ namespace storm { for (auto const& variable : this->getGlobalVariables().getBoundedIntegerVariables()) { result.push_back(variable.getRangeExpression()); } + STORM_LOG_ASSERT(this->getGlobalVariables().getArrayVariables().empty(), "This operation is unsupported if array variables are present."); if (automata.empty()) { for (auto const& automaton : this->getAutomata()) { @@ -1107,14 +1384,25 @@ namespace storm { } void Model::makeStandardJaniCompliant() { + for (auto& automaton : automata) { + // For discrete-time models, we push the assignments to real-valued transient variables (rewards) to the + // edges. + if (this->isDiscreteTimeModel()) { + automaton.pushTransientRealLocationAssignmentsToEdges(); + } + automaton.pushEdgeAssignmentsToDestinations(); + } + } + + void Model::pushEdgeAssignmentsToDestinations() { for (auto& automaton : automata) { automaton.pushEdgeAssignmentsToDestinations(); } } - void Model::liftTransientEdgeDestinationAssignments() { + void Model::liftTransientEdgeDestinationAssignments(int64_t maxLevel) { for (auto& automaton : this->getAutomata()) { - automaton.liftTransientEdgeDestinationAssignments(); + automaton.liftTransientEdgeDestinationAssignments(maxLevel); } } @@ -1127,9 +1415,9 @@ namespace storm { return false; } - bool Model::usesAssignmentLevels() const { + bool Model::usesAssignmentLevels(bool onlyTransient) const { for (auto const& automaton : this->getAutomata()) { - if (automaton.usesAssignmentLevels()) { + if (automaton.usesAssignmentLevels(onlyTransient)) { return true; } } @@ -1156,11 +1444,11 @@ namespace storm { return false; } - uint64_t Model::encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) const { + uint64_t Model::encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) { return automatonIndex << 32 | edgeIndex; } - std::pair Model::decodeAutomatonAndEdgeIndices(uint64_t index) const { + std::pair Model::decodeAutomatonAndEdgeIndices(uint64_t index) { return std::make_pair(index >> 32, index & ((1ull << 32) - 1)); } diff --git a/src/storm/storage/jani/Model.h b/src/storm/storage/jani/Model.h index f45f78b29..401d1a54a 100644 --- a/src/storm/storage/jani/Model.h +++ b/src/storm/storage/jani/Model.h @@ -12,8 +12,10 @@ #include "storm/storage/jani/Constant.h" #include "storm/storage/jani/Composition.h" #include "storm/storage/jani/Edge.h" +#include "storm/storage/jani/FunctionDefinition.h" #include "storm/storage/jani/Location.h" #include "storm/storage/jani/TemplateEdge.h" +#include "storm/storage/jani/ModelFeatures.h" #include "storm/utility/solver.h" #include "storm/utility/vector.h" @@ -33,6 +35,8 @@ namespace storm { class Automaton; class Exporter; class SynchronizationVector; + struct ArrayEliminatorData; + class Property; class Model { public: @@ -77,10 +81,25 @@ namespace storm { ModelType const& getModelType() const; /*! - * Retrievest the name of the model. + * Retrieves the enabled model features + */ + ModelFeatures const& getModelFeatures() const; + + /*! + * Retrieves the enabled model features + */ + ModelFeatures& getModelFeatures(); + + /*! + * Retrieves the name of the model. */ std::string const& getName() const; + /*! + * Sets the name of the model. + */ + void setName(std::string const& newName); + /*! * Flatten the composition to obtain an equivalent model that contains exactly one automaton that has the * standard composition. @@ -138,7 +157,7 @@ namespace storm { /*! * Adds the given constant to the model. */ - uint64_t addConstant(Constant const& constant); + void addConstant(Constant const& constant); /*! * Retrieves whether the model has a constant with the given name. @@ -157,6 +176,7 @@ namespace storm { /*! * Retrieves the constant with the given name (if any). + * @note the reference to the constant is invalidated whenever a new constant is added. */ Constant const& getConstant(std::string const& name) const; @@ -185,6 +205,11 @@ namespace storm { */ RealVariable const& addVariable(RealVariable const& variable); + /*! + * Adds the given array variable to this model. + */ + ArrayVariable const& addVariable(ArrayVariable const& variable); + /*! * Retrieves the variables of this automaton. */ @@ -225,15 +250,52 @@ namespace storm { */ bool hasNonGlobalTransientVariable() const; + /*! + * Adds the given function definition + */ + FunctionDefinition const& addFunctionDefinition(FunctionDefinition const& functionDefinition); + + /*! + * Retrieves all global function definitions + */ + std::unordered_map const& getGlobalFunctionDefinitions() const; + + /*! + * Retrieves all global function definitions + */ + std::unordered_map& getGlobalFunctionDefinitions(); + /*! * Retrieves the manager responsible for the expressions in the JANI model. */ - storm::expressions::ExpressionManager& getExpressionManager(); + storm::expressions::ExpressionManager& getExpressionManager() const; /*! - * Retrieves the manager responsible for the expressions in the JANI model. + * Adds a (non-trivial) reward model, i.e., a reward model that does not consist of a single, global, numerical 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); + + /*! + * Retrieves the defining reward expression of the reward model with the given identifier. + */ + storm::expressions::Expression getRewardModelExpression(std::string const& identifier) const; + + /*! + * Retrieves all available reward model names and expressions of the model. + * This includes defined non-trivial reward expressions as well as transient, global, numerical variables + */ + std::vector> getAllRewardModelExpressions() const; + + /*! + * Retrieves all available non-trivial reward model names and expressions of the model. */ - storm::expressions::ExpressionManager const& getExpressionManager() const; + std::unordered_map const& getNonTrivialRewardExpressions() const; + + /*! + * Retrieves all available non-trivial reward model names and expressions of the model. + */ + std::unordered_map& getNonTrivialRewardExpressions(); /*! * Adds the given automaton to the automata of this model. @@ -250,6 +312,19 @@ namespace storm { */ std::vector const& getAutomata() const; + /** + * Replaces the automaton at index with a new automaton. + * @param index + * @param newAutomaton + */ + void replaceAutomaton(uint64_t index, Automaton const& newAutomaton); + + /*! + * Rerieves whether there exists an automaton with the given name. + * @param name + * @return + */ + bool hasAutomaton(std::string const& name) const; /*! * Retrieves the automaton with the given name. */ @@ -279,6 +354,11 @@ namespace storm { * Retrieves the number of automata in this model. */ std::size_t getNumberOfAutomata() const; + + /*! + * Retrieves the total number of edges in this model. + */ + std::size_t getNumberOfEdges() const; /*! * Sets the system composition expression of the JANI model. @@ -334,11 +414,65 @@ namespace storm { */ std::map getConstantsSubstitution() const; + /*! + * Substitutes all expression variables in all expressions of the model. The original model is not modified, but + * instead a new model is created. + */ + void substitute(std::map const& substitution); + + /*! + * Substitutes all function calls with the corresponding function definition + * @param properties also eliminates function call expressions in the given properties + */ + void substituteFunctions(); + void substituteFunctions(std::vector& properties); + + /*! + * Substitutes all constants in all expressions of the model. The original model is not modified, but + * instead a new model is created. Afterwards, all function calls are substituted with the defining expression. + */ + Model substituteConstantsFunctions() const; + + /*! + * Returns true if at least one array variable occurs in the model. + */ + bool containsArrayVariables() const; + + /*! + * Eliminates occurring array variables and expressions by replacing array variables by multiple basic variables. + * @param keepNonTrivialArrayAccess if set, array access expressions in LValues and expressions are only replaced, if the index expression is constant. + * @return data from the elimination. If non-trivial array accesses are kept, pointers to remaining array variables point to this data. + */ + ArrayEliminatorData eliminateArrays(bool keepNonTrivialArrayAccess = false); + + /*! + * Eliminates occurring array variables and expressions by replacing array variables by multiple basic variables. + * @param properties also eliminates array expressions in the given properties + */ + void eliminateArrays(std::vector& properties); + + /*! + * Attempts to eliminate all features of this model that are not in the given set of features. + * @return The model features that could not be eliminated. + */ + ModelFeatures restrictToFeatures(ModelFeatures const& modelFeatures); + + /*! + * Attempts to eliminate all features of this model and the given properties that are not in the given set of features. + * @return The model features that could not be eliminated. + */ + ModelFeatures restrictToFeatures(ModelFeatures const& modelFeatures, std::vector& properties); + /*! * Retrieves whether there is an expression restricting the legal initial values of the global variables. */ bool hasInitialStatesRestriction() const; + /*! + * Retrieves whether there are non-trivial initial states in the model or any of the contained automata. + */ + bool hasNonTrivialInitialStates() const; + /*! * Sets the expression restricting the legal initial values of the global variables. */ @@ -354,6 +488,12 @@ namespace storm { */ storm::expressions::Expression getInitialStatesExpression() const; + /*! + * Retrieves whether the initial states expression is trivial in the sense that no automaton has an initial + * states restriction and all variables have initial values. + */ + bool hasTrivialInitialStatesExpression() const; + /*! * Retrieves the expression defining the legal initial values of the variables. * @@ -422,8 +562,9 @@ namespace storm { /*! * Lifts the common edge destination assignments to edge assignments. + * @param maxLevel the maximum level of assignments that are to be lifted. */ - void liftTransientEdgeDestinationAssignments(); + void liftTransientEdgeDestinationAssignments(int64_t maxLevel = 0); /*! * Retrieves whether there is any transient edge destination assignment in the model. @@ -432,8 +573,9 @@ namespace storm { /*! * Retrieves whether the model uses an assignment level other than zero. + * @param onlyTransient if set, only transient assignments are considered */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; /*! * Checks the model for linearity. A model is linear if all expressions appearing in guards and assignments @@ -443,6 +585,9 @@ namespace storm { void makeStandardJaniCompliant(); + // Pushes all edge assignments to their destination + void pushEdgeAssignmentsToDestinations(); + /*! * Checks whether in the composition, actions are reused: That is, if the model is put in parallel composition and the same action potentially leads to multiple edges from the same state. * @return @@ -452,8 +597,8 @@ namespace storm { /*! * Encode and decode a tuple of automaton and edge index in one 64-bit index. */ - uint64_t encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) const; - std::pair decodeAutomatonAndEdgeIndices(uint64_t index) const; + static uint64_t encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex); + static std::pair decodeAutomatonAndEdgeIndices(uint64_t index); /*! * Creates a new model that only contains the selected edges. The edge indices encode the automata and @@ -484,6 +629,9 @@ namespace storm { /// The JANI-version used to specify the model. uint64_t version; + /// The features enabled for this model. + ModelFeatures modelFeatures; + /// The manager responsible for the expressions in this model. std::shared_ptr expressionManager; @@ -493,6 +641,10 @@ namespace storm { /// A mapping from names to action indices. std::unordered_map actionToIndex; + /// A mapping from non-trivial reward model names to their defining expression. + /// (A reward model is trivial, if it is represented by a single, global, numeric variable) + std::unordered_map nonTrivialRewardModels; + /// The set of non-silent action indices. boost::container::flat_set nonsilentActionIndices; @@ -505,6 +657,10 @@ namespace storm { /// The global variables of the model. VariableSet globalVariables; + /// A mapping from names to function definitions + /// Since we use an unordered_map, references to function definitions will not get invalidated when more function definitions are added + std::unordered_map globalFunctions; + /// The list of automata. std::vector automata; diff --git a/src/storm/storage/jani/ModelFeatures.cpp b/src/storm/storage/jani/ModelFeatures.cpp new file mode 100644 index 000000000..5a3aa9794 --- /dev/null +++ b/src/storm/storage/jani/ModelFeatures.cpp @@ -0,0 +1,74 @@ +#include "storm/storage/jani/ModelFeatures.h" + +#include "storm/utility/macros.h" + +namespace storm { + namespace jani { + + std::string toString(ModelFeature const& modelFeature) { + switch(modelFeature) { + case ModelFeature::Arrays: + return "arrays"; + case ModelFeature::DerivedOperators: + return "derived-operators"; + case ModelFeature::Functions: + return "functions"; + case ModelFeature::StateExitRewards: + return "state-exit-rewards"; + } + STORM_LOG_ASSERT(false, "Unhandled model feature"); + return "Unhandled-feature"; + } + + std::string ModelFeatures::toString() const { + std::string res = "["; + bool first = true; + for (auto const& f : features) { + if (!first) { + res += ", "; + } + res += "\"" + storm::jani::toString(f) + "\""; + first = false; + } + res += "]"; + return res; + } + + bool ModelFeatures::hasArrays() const { + return features.count(ModelFeature::Arrays) > 0; + } + + bool ModelFeatures::hasDerivedOperators() const { + return features.count(ModelFeature::DerivedOperators) > 0; + } + + bool ModelFeatures::hasFunctions() const { + return features.count(ModelFeature::Functions) > 0; + } + + bool ModelFeatures::hasStateExitRewards() const { + return features.count(ModelFeature::StateExitRewards) > 0; + } + + std::set const& ModelFeatures::asSet() const { + return features; + } + + bool ModelFeatures::empty() const { + return features.empty(); + } + + ModelFeatures& ModelFeatures::add(ModelFeature const& modelFeature) { + features.insert(modelFeature); + return *this; + } + + void ModelFeatures::remove(ModelFeature const& modelFeature) { + features.erase(modelFeature); + } + + ModelFeatures getAllKnownModelFeatures() { + return ModelFeatures().add(ModelFeature::Arrays).add(ModelFeature::DerivedOperators).add(ModelFeature::Functions).add(ModelFeature::StateExitRewards); + } + } +} diff --git a/src/storm/storage/jani/ModelFeatures.h b/src/storm/storage/jani/ModelFeatures.h new file mode 100644 index 000000000..f07477202 --- /dev/null +++ b/src/storm/storage/jani/ModelFeatures.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +namespace storm { + namespace jani { + + enum class ModelFeature {Arrays, DerivedOperators, Functions, StateExitRewards}; + + std::string toString(ModelFeature const& modelFeature); + + class ModelFeatures { + + public: + std::string toString() const; + + bool hasArrays() const; + bool hasFunctions() const; + bool hasDerivedOperators() const; + bool hasStateExitRewards() const; + + // Returns true, if no model feature is enabled. + bool empty() const; + std::set const& asSet() const; + + ModelFeatures& add(ModelFeature const& modelFeature); + void remove(ModelFeature const& modelFeature); + + private: + std::set features; + }; + + ModelFeatures getAllKnownModelFeatures(); + + } +} diff --git a/src/storm/storage/jani/OrderedAssignments.cpp b/src/storm/storage/jani/OrderedAssignments.cpp index 99eb415a8..747fbcecd 100644 --- a/src/storm/storage/jani/OrderedAssignments.cpp +++ b/src/storm/storage/jani/OrderedAssignments.cpp @@ -16,29 +16,39 @@ namespace storm { OrderedAssignments::OrderedAssignments(Assignment const& assignment) { add(assignment); } + + OrderedAssignments OrderedAssignments::clone() const { + OrderedAssignments result; + for (auto const& assignment : allAssignments) { + result.add(Assignment(*assignment)); + } + return result; + } - bool OrderedAssignments::add(Assignment const& assignment) { + bool OrderedAssignments::add(Assignment const& assignment, bool addToExisting) { // If the element is contained in this set of assignment, nothing needs to be added. - if (this->contains(assignment)) { + if (!addToExisting && this->contains(assignment)) { return false; } // Otherwise, we find the spot to insert it. auto it = lowerBound(assignment, allAssignments); - - if (it != allAssignments.end()) { - STORM_LOG_THROW(assignment.getExpressionVariable() != (*it)->getExpressionVariable(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to variable '" << (*it)->getVariable().getName() << "' already exists."); - } - // Finally, insert the new element in the correct vectors. - auto elementToInsert = std::make_shared(assignment); - allAssignments.emplace(it, elementToInsert); - if (assignment.isTransient()) { - auto transientIt = lowerBound(assignment, transientAssignments); - transientAssignments.emplace(transientIt, elementToInsert); + // Check if an assignment to this variable is already present + if (it != allAssignments.end() && assignment.getLValue() == (*it)->getLValue()) { + STORM_LOG_THROW(addToExisting && assignment.getLValue().isVariable() && assignment.getExpressionVariable().hasNumericalType(), storm::exceptions::InvalidArgumentException, "Cannot add assignment ('" << assignment.getAssignedExpression() << "') as an assignment ('" << (*it)->getAssignedExpression() << "') to LValue '" << (*it)->getLValue() << "' already exists."); + (*it)->setAssignedExpression((*it)->getAssignedExpression() + assignment.getAssignedExpression()); } else { - auto nonTransientIt = lowerBound(assignment, nonTransientAssignments); - nonTransientAssignments.emplace(nonTransientIt, elementToInsert); + // Finally, insert the new element in the correct vectors. + auto elementToInsert = std::make_shared(assignment); + allAssignments.emplace(it, elementToInsert); + if (assignment.isTransient()) { + auto transientIt = lowerBound(assignment, transientAssignments); + transientAssignments.emplace(transientIt, elementToInsert); + } else { + auto nonTransientIt = lowerBound(assignment, nonTransientAssignments); + nonTransientAssignments.emplace(nonTransientIt, elementToInsert); + } } return true; @@ -70,11 +80,11 @@ namespace storm { return true; } - bool OrderedAssignments::hasMultipleLevels() const { - if (allAssignments.empty()) { + bool OrderedAssignments::hasMultipleLevels(bool onlyTransient) const { + if ((onlyTransient ? transientAssignments : allAssignments).empty()) { return false; } - return getLowestLevel() != 0 || getHighestLevel() != 0; + return getLowestLevel(onlyTransient) != 0 || getHighestLevel(onlyTransient) != 0; } bool OrderedAssignments::empty() const { @@ -91,14 +101,16 @@ namespace storm { return allAssignments.size(); } - int_fast64_t OrderedAssignments::getLowestLevel() const { - assert(!allAssignments.empty()); - return allAssignments.front()->getLevel(); + int64_t OrderedAssignments::getLowestLevel(bool onlyTransient) const { + auto const& as = onlyTransient ? transientAssignments : allAssignments; + assert(!as.empty()); + return as.front()->getLevel(); } - int_fast64_t OrderedAssignments::getHighestLevel() const { - assert(!allAssignments.empty()); - return allAssignments.back()->getLevel(); + int64_t OrderedAssignments::getHighestLevel(bool onlyTransient) const { + auto const& as = onlyTransient ? transientAssignments : allAssignments; + assert(!as.empty()); + return as.back()->getLevel(); } bool OrderedAssignments::contains(Assignment const& assignment) const { @@ -115,18 +127,19 @@ namespace storm { if (first) { std::vector newAssignments; for (uint64_t i = 0; i < allAssignments.size(); ++i) { - if (synchronous && !localVars.hasVariable(allAssignments.at(i)->getVariable())) { + auto const& iLValue = allAssignments.at(i)->getLValue(); + if (synchronous && !localVars.hasVariable(iLValue.isVariable() ? iLValue.getVariable() : iLValue.getArray())) { newAssignments.push_back(*(allAssignments.at(i))); continue; } bool readBeforeWrite = true; for (uint64_t j = i + 1; j < allAssignments.size(); ++j) { if (allAssignments.at(j)->getAssignedExpression().containsVariable( - {allAssignments.at(i)->getVariable().getExpressionVariable()})) { + {iLValue.isVariable() ? iLValue.getVariable().getExpressionVariable() : iLValue.getArray().getExpressionVariable()})) { // is read. break; } - if (allAssignments.at(j)->getVariable() == allAssignments.at(i)->getVariable()) { + if (iLValue == allAssignments.at(j)->getLValue()) { // is written, has not been read before readBeforeWrite = false; break; @@ -148,15 +161,18 @@ namespace storm { std::vector newAssignments; for (auto const& assignment : allAssignments) { newAssignments.push_back(*assignment); - if (synchronous && !localVars.hasVariable(assignment->getVariable())) { + if (assignment->isTransient() && !assignment->getAssignedExpression().containsVariables()) { + // Since we do not support + } + if (synchronous && !localVars.hasVariable(assignment->getLValue().isVariable() ? assignment->getLValue().getVariable() : assignment->getLValue().getArray())) { continue; } if (assignment->getLevel() == 0) { continue; } uint64_t assNr = upperBound(assignment->getLevel() - 1); - if (assNr == isWrittenBeforeAssignment(assignment->getVariable(), assNr)) { - if (assNr == isReadBeforeAssignment(assignment->getVariable(), assNr)) { + if (assNr == isWrittenBeforeAssignment(assignment->getLValue(), assNr)) { + if (assNr == isReadBeforeAssignment(assignment->getLValue(), assNr)) { newAssignments.back().setLevel(0); changed = true; } @@ -182,6 +198,27 @@ namespace storm { return detail::ConstAssignments(nonTransientAssignments.begin(), nonTransientAssignments.end()); } + struct AssignmentLevelToLevelComparator { + bool operator()(std::shared_ptr const& left, int64_t const& right) const { + return left->getLevel() < right; + } + bool operator()(int64_t const& left, std::shared_ptr const& right) const { + return left < right->getLevel(); + } + }; + + detail::ConstAssignments OrderedAssignments::getTransientAssignments(int64_t assignmentLevel) const { + auto begin = std::lower_bound(transientAssignments.begin(), transientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + auto end = std::upper_bound(begin, transientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + return detail::ConstAssignments(begin, end); + } + + detail::ConstAssignments OrderedAssignments::getNonTransientAssignments(int64_t assignmentLevel) const { + auto begin = std::lower_bound(nonTransientAssignments.begin(), nonTransientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + auto end = std::upper_bound(begin, nonTransientAssignments.end(), assignmentLevel, AssignmentLevelToLevelComparator()); + return detail::ConstAssignments(begin, end); + } + bool OrderedAssignments::hasTransientAssignment() const { return !transientAssignments.empty(); } @@ -211,16 +248,19 @@ namespace storm { void OrderedAssignments::changeAssignmentVariables(std::map> const& remapping) { std::vector newAssignments; for (auto& assignment : allAssignments) { - newAssignments.emplace_back(remapping.at(&assignment->getVariable()), assignment->getAssignedExpression(), assignment->getLevel()); + newAssignments.emplace_back(assignment->getLValue().changeAssignmentVariables(remapping), assignment->getAssignedExpression(), assignment->getLevel()); } *this = OrderedAssignments(newAssignments); } std::vector>::const_iterator OrderedAssignments::lowerBound(Assignment const& assignment, std::vector> const& assignments) { - return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndVariable()); + return std::lower_bound(assignments.begin(), assignments.end(), assignment, storm::jani::AssignmentPartialOrderByLevelAndLValue()); } - - uint64_t OrderedAssignments::isReadBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start) const { + + uint64_t OrderedAssignments::isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const { + Variable const& var = lValue.isVariable() ? lValue.getVariable() : lValue.getArray(); + // TODO: do this more carefully + STORM_LOG_WARN_COND(lValue.isVariable(), "Called a method that is not optimized for arrays."); for (uint64_t i = start; i < assignmentNumber; i++) { if (allAssignments.at(i)->getAssignedExpression().containsVariable({ var.getExpressionVariable() })) { return i; @@ -229,9 +269,9 @@ namespace storm { return assignmentNumber; } - uint64_t OrderedAssignments::isWrittenBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start) const { + uint64_t OrderedAssignments::isWrittenBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start) const { for (uint64_t i = start; i < assignmentNumber; i++) { - if (allAssignments.at(i)->getVariable() == var) { + if (allAssignments.at(i)->getLValue() == lValue) { return i; } } @@ -257,6 +297,15 @@ namespace storm { return result; } + bool OrderedAssignments::checkOrder() const { + for (std::vector>::const_iterator it = allAssignments.cbegin(); it != allAssignments.cend(); ++it) { + if (it != lowerBound(**it, allAssignments)) { + return false; + } + } + return true; + } + std::ostream& operator<<(std::ostream& stream, OrderedAssignments const& assignments) { stream << "["; for(auto const& e : assignments.allAssignments) { diff --git a/src/storm/storage/jani/OrderedAssignments.h b/src/storm/storage/jani/OrderedAssignments.h index 8e307e6e0..de914b738 100644 --- a/src/storm/storage/jani/OrderedAssignments.h +++ b/src/storm/storage/jani/OrderedAssignments.h @@ -26,9 +26,11 @@ namespace storm { /*! * Adds the given assignment to the set of assignments. * + * @addToExisting If true the value of the assigned expression is added to a (potentially) previous assignment + * to the variable. If false and there is already an assignment, an exception is thrown. * @return True iff the assignment was added. */ - bool add(Assignment const& assignment); + bool add(Assignment const& assignment, bool addToExisting = false); /*! * Removes the given assignment from this set of assignments. @@ -42,7 +44,7 @@ namespace storm { * * @return True if more than one level occurs in the assignment set. */ - bool hasMultipleLevels() const; + bool hasMultipleLevels(bool onlyTransient = false) const; /** * Produces a new OrderedAssignments object with simplified leveling @@ -71,13 +73,13 @@ namespace storm { * Retrieves the lowest level among all assignments. Note that this may only be called if there is at least * one assignment. */ - int_fast64_t getLowestLevel() const; + int64_t getLowestLevel(bool onlyTransient = false) const; /*! * Retrieves the highest level among all assignments. Note that this may only be called if there is at least * one assignment. */ - int_fast64_t getHighestLevel() const; + int64_t getHighestLevel(bool onlyTransient = false) const; /*! * Retrieves whether the given assignment is contained in this set of assignments. @@ -94,10 +96,20 @@ namespace storm { */ detail::ConstAssignments getTransientAssignments() const; + /*! + * Returns all transient assignments in this set of assignments. + */ + detail::ConstAssignments getTransientAssignments(int64_t assignmentLevel) const; + /*! * Returns all non-transient assignments in this set of assignments. */ detail::ConstAssignments getNonTransientAssignments() const; + + /*! + * Returns all non-transient assignments in this set of assignments. + */ + detail::ConstAssignments getNonTransientAssignments(int64_t assignmentLevel) const; /*! * Retrieves whether the set of assignments has at least one transient assignment. @@ -140,10 +152,17 @@ namespace storm { bool areLinear() const; friend std::ostream& operator<<(std::ostream& stream, OrderedAssignments const& assignments); + + OrderedAssignments clone() const; + + /*! + * Checks whether this ordered assignment is in the correct order. + */ + bool checkOrder() const; private: - uint64_t isReadBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start = 0) const; - uint64_t isWrittenBeforeAssignment(Variable const& var, uint64_t assignmentNumber, uint64_t start = 0) const; + uint64_t isReadBeforeAssignment(LValue const& lValue, uint64_t assignmentNumber, uint64_t start = 0) const; + uint64_t isWrittenBeforeAssignment(LValue const& LValue, uint64_t assignmentNumber, uint64_t start = 0) const; /*! * Gets the number of assignments number with an assignment not higher than index. @@ -153,7 +172,7 @@ namespace storm { uint64_t upperBound(int64_t index) const; static std::vector>::const_iterator lowerBound(Assignment const& assignment, std::vector> const& assignments); - + // The vectors to store the assignments. These need to be ordered at all times. std::vector> allAssignments; std::vector> transientAssignments; diff --git a/src/storm/storage/jani/ParallelComposition.cpp b/src/storm/storage/jani/ParallelComposition.cpp index d81db1d91..0d439e0ce 100644 --- a/src/storm/storage/jani/ParallelComposition.cpp +++ b/src/storm/storage/jani/ParallelComposition.cpp @@ -116,7 +116,7 @@ namespace storm { return !(vector1 == vector2); } - bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) { + bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const { STORM_LOG_THROW(vector1.size() == vector2.size(), storm::exceptions::WrongFormatException, "Cannot compare synchronization vectors of different size."); for (uint64_t i = 0; i < vector1.size(); ++i) { if (vector1.getInput(i) < vector2.getInput(i)) { diff --git a/src/storm/storage/jani/ParallelComposition.h b/src/storm/storage/jani/ParallelComposition.h index c3d41717c..381ace5f8 100644 --- a/src/storm/storage/jani/ParallelComposition.h +++ b/src/storm/storage/jani/ParallelComposition.h @@ -62,7 +62,7 @@ namespace storm { bool operator!=(SynchronizationVector const& vector1, SynchronizationVector const& vector2); struct SynchronizationVectorLexicographicalLess { - bool operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2); + bool operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const; }; std::ostream& operator<<(std::ostream& stream, SynchronizationVector const& synchronizationVector); diff --git a/src/storm/storage/jani/Property.cpp b/src/storm/storage/jani/Property.cpp index 73c6d0dec..5a1c50023 100644 --- a/src/storm/storage/jani/Property.cpp +++ b/src/storm/storage/jani/Property.cpp @@ -1,20 +1,19 @@ #include "Property.h" + namespace storm { namespace jani { - - std::ostream& operator<<(std::ostream& os, FilterExpression const& fe) { - return os << "Obtain " << toString(fe.getFilterType()) << " of the '" << fe.getStatesFormula() << "'-states with values described by '" << *fe.getFormula() << "'"; + return os << "Obtain " << toString(fe.getFilterType()) << " of the '" << *fe.getStatesFormula() << "'-states with values described by '" << *fe.getFormula() << "'"; } - Property::Property(std::string const& name, std::shared_ptr const& formula, std::string const& comment) - : name(name), comment(comment), filterExpression(FilterExpression(formula)) { + Property::Property(std::string const& name, std::shared_ptr const& formula, std::set const& undefinedConstants, std::string const& comment) + : name(name), comment(comment), filterExpression(FilterExpression(formula)), undefinedConstants(undefinedConstants) { // Intentionally left empty. } - Property::Property(std::string const& name, FilterExpression const& fe, std::string const& comment) - : name(name), comment(comment), filterExpression(fe) { + Property::Property(std::string const& name, FilterExpression const& fe, std::set const& undefinedConstants, std::string const& comment) + : name(name), comment(comment), filterExpression(fe), undefinedConstants(undefinedConstants) { // Intentionally left empty. } @@ -27,11 +26,33 @@ namespace storm { } Property Property::substitute(std::map const& substitution) const { - return Property(name, filterExpression.substitute(substitution), comment); + std::set remainingUndefinedConstants; + for (auto const& constant : undefinedConstants) { + if (substitution.find(constant) == substitution.end()) { + remainingUndefinedConstants.insert(constant); + } + } + return Property(name, filterExpression.substitute(substitution), remainingUndefinedConstants, comment); + } + + Property Property::substitute(std::function const& substitutionFunction) const { + std::set remainingUndefinedConstants; + for (auto const& constant : undefinedConstants) { + substitutionFunction(constant.getExpression()).getBaseExpression().gatherVariables(remainingUndefinedConstants); + } + return Property(name, filterExpression.substitute(substitutionFunction), remainingUndefinedConstants, comment); } Property Property::substituteLabels(std::map const& substitution) const { - return Property(name, filterExpression.substituteLabels(substitution), comment); + return Property(name, filterExpression.substituteLabels(substitution), undefinedConstants, comment); + } + + Property Property::substituteRewardModelNames(std::map const& rewardModelNameSubstitution) const { + return Property(name, filterExpression.substituteRewardModelNames(rewardModelNameSubstitution), undefinedConstants, comment); + } + + Property Property::clone() const { + return Property(name, filterExpression.clone(), undefinedConstants, comment); } FilterExpression const& Property::getFilter() const { @@ -42,8 +63,16 @@ namespace storm { return this->filterExpression.getFormula(); } + std::set const& Property::getUndefinedConstants() const { + return undefinedConstants; + } + + bool Property::containsUndefinedConstants() const { + return !undefinedConstants.empty(); + } + std::ostream& operator<<(std::ostream& os, Property const& p) { - return os << "(" << p.getName() << ") : " << p.getFilter(); + return os << "(" << p.getName() << "): " << p.getFilter(); } } diff --git a/src/storm/storage/jani/Property.h b/src/storm/storage/jani/Property.h index 74aceab5c..2d1d88d70 100644 --- a/src/storm/storage/jani/Property.h +++ b/src/storm/storage/jani/Property.h @@ -1,8 +1,11 @@ #pragma once +#include + #include "storm/modelchecker/results/FilterType.h" #include "storm/logic/Formulas.h" #include "storm/logic/FragmentSpecification.h" +#include "storm/logic/CloneVisitor.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidArgumentException.h" @@ -54,10 +57,23 @@ namespace storm { return FilterExpression(formula->substitute(substitution), ft, statesFormula->substitute(substitution)); } + FilterExpression substitute(std::function const& substitutionFunction) const { + return FilterExpression(formula->substitute(substitutionFunction), ft, statesFormula->substitute(substitutionFunction)); + } + FilterExpression substituteLabels(std::map const& labelSubstitution) const { return FilterExpression(formula->substitute(labelSubstitution), ft, statesFormula->substitute(labelSubstitution)); } - + + FilterExpression substituteRewardModelNames(std::map const& rewardModelNameSubstitution) const { + return FilterExpression(formula->substituteRewardModelNames(rewardModelNameSubstitution), ft, statesFormula->substituteRewardModelNames(rewardModelNameSubstitution)); + } + + FilterExpression clone() const { + storm::logic::CloneVisitor cv; + return FilterExpression(cv.clone(*formula), ft, cv.clone(*statesFormula)); + } + private: // For now, we assume that the states are always the initial states. std::shared_ptr formula; @@ -78,9 +94,10 @@ namespace storm { * Constructs the property * @param name the name * @param formula the formula representation + * @param undefinedConstants the undefined constants used in the property * @param comment An optional comment */ - Property(std::string const& name, std::shared_ptr const& formula, std::string const& comment = ""); + Property(std::string const& name, std::shared_ptr const& formula, std::set const& undefinedConstants, std::string const& comment = ""); /** * Constructs the property @@ -88,7 +105,7 @@ namespace storm { * @param formula the formula representation * @param comment An optional comment */ - Property(std::string const& name, FilterExpression const& fe, std::string const& comment = ""); + Property(std::string const& name, FilterExpression const& fe, std::set const& undefinedConstants, std::string const& comment = ""); /** * Get the provided name @@ -103,15 +120,22 @@ namespace storm { std::string const& getComment() const; Property substitute(std::map const& substitution) const; + Property substitute(std::function const& substitutionFunction) const; Property substituteLabels(std::map const& labelSubstitution) const; + Property substituteRewardModelNames(std::map const& rewardModelNameSubstitution) const; + Property clone() const; FilterExpression const& getFilter() const; + std::set const& getUndefinedConstants() const; + bool containsUndefinedConstants() const; + std::shared_ptr getRawFormula() const; private: std::string name; std::string comment; FilterExpression filterExpression; + std::set undefinedConstants; }; diff --git a/src/storm/storage/jani/TemplateEdge.cpp b/src/storm/storage/jani/TemplateEdge.cpp index 987e4f6de..50f5b4d8b 100644 --- a/src/storm/storage/jani/TemplateEdge.cpp +++ b/src/storm/storage/jani/TemplateEdge.cpp @@ -1,18 +1,20 @@ #include "storm/storage/jani/TemplateEdge.h" #include "storm/storage/jani/Model.h" +#include "storm/storage/jani/LValue.h" #include "storm/storage/expressions/LinearityCheckVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" namespace storm { namespace jani { - TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard) : guard(guard) { + TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard) : guard(guard), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(std::numeric_limits::min()) { // Intentionally left empty. } TemplateEdge::TemplateEdge(storm::expressions::Expression const& guard, OrderedAssignments const& assignments, std::vector const& destinations) - : guard(guard), destinations(destinations), assignments(assignments) { + : guard(guard), destinations(destinations), assignments(assignments), lowestAssignmentLevel(std::numeric_limits::max()), highestAssignmentLevel(std::numeric_limits::min()) { // Intentionally left empty. } @@ -20,15 +22,22 @@ namespace storm { destinations.emplace_back(destination); } - bool TemplateEdge::addTransientAssignment(Assignment const& assignment) { - return assignments.add(assignment); + bool TemplateEdge::addTransientAssignment(Assignment const& assignment, bool addToExisting) { + return assignments.add(assignment, addToExisting); } void TemplateEdge::finalize(Model const& containingModel) { + lowestAssignmentLevel = std::numeric_limits::max(); + highestAssignmentLevel = std::numeric_limits::min(); for (auto const& destination : getDestinations()) { + if (!destination.getOrderedAssignments().empty()) { + lowestAssignmentLevel = std::min(lowestAssignmentLevel, destination.getOrderedAssignments().getLowestLevel()); + highestAssignmentLevel = std::max(highestAssignmentLevel, destination.getOrderedAssignments().getHighestLevel()); + } for (auto const& assignment : destination.getOrderedAssignments().getAllAssignments()) { - if (containingModel.getGlobalVariables().hasVariable(assignment.getExpressionVariable())) { - writtenGlobalVariables.insert(assignment.getExpressionVariable()); + Variable const& var = assignment.getLValue().isVariable() ? assignment.getLValue().getVariable() : assignment.getLValue().getArray(); + if (containingModel.getGlobalVariables().hasVariable(var.getExpressionVariable())) { + writtenGlobalVariables.insert(var.getExpressionVariable()); } } } @@ -42,6 +51,10 @@ namespace storm { return guard; } + void TemplateEdge::setGuard(storm::expressions::Expression const& newGuard) { + guard = newGuard; + } + std::size_t TemplateEdge::getNumberOfDestinations() const { return destinations.size(); } @@ -50,6 +63,10 @@ namespace storm { return destinations; } + std::vector& TemplateEdge::getDestinations() { + return destinations; + } + TemplateEdgeDestination const& TemplateEdge::getDestination(uint64_t index) const { return destinations[index]; } @@ -57,9 +74,13 @@ namespace storm { OrderedAssignments const& TemplateEdge::getAssignments() const { return assignments; } + + OrderedAssignments& TemplateEdge::getAssignments() { + return assignments; + } void TemplateEdge::substitute(std::map const& substitution) { - guard = guard.substitute(substitution); + guard = substituteJaniExpression(guard, substitution); for (auto& assignment : assignments) { assignment.substitute(substitution); @@ -77,26 +98,36 @@ namespace storm { assignments.changeAssignmentVariables(remapping); } - void TemplateEdge::liftTransientDestinationAssignments() { + void TemplateEdge::liftTransientDestinationAssignments(int64_t maxLevel) { if (!destinations.empty()) { auto const& destination = *destinations.begin(); + std::vector> assignmentsToLift; + for (auto const& assignment : destination.getOrderedAssignments().getTransientAssignments()) { // Check if we can lift the assignment to the edge. - bool canBeLifted = true; - for (auto const& destination : destinations) { - if (!destination.hasAssignment(assignment)) { - canBeLifted = false; - break; + bool canBeLifted = assignment.getLevel() <= maxLevel; + if (canBeLifted) { + for (auto const& destination : destinations) { + if (!destination.hasAssignment(assignment)) { + canBeLifted = false; + break; + } } } - // If so, remove the assignment from all destinations. if (canBeLifted) { - this->addTransientAssignment(assignment); - for (auto& destination : destinations) { - destination.removeAssignment(assignment); - } + // Do not remove the assignment now, as we currently iterate over them. + // Also we need to make a copy of the assignment since we are about to delete it + assignmentsToLift.push_back(std::make_shared(assignment)); + } + } + + // now actually lift the assignments + for (auto const& assignment : assignmentsToLift) { + this->addTransientAssignment(*assignment); + for (auto& destination : destinations) { + destination.removeAssignment(*assignment); } } } @@ -106,7 +137,7 @@ namespace storm { STORM_LOG_ASSERT(!destinations.empty(), "Need non-empty destinations for this transformation."); for (auto const& assignment : this->getAssignments()) { for (auto& destination : destinations) { - destination.addAssignment(assignment); + destination.addAssignment(assignment, true); } } this->assignments.clear(); @@ -132,18 +163,25 @@ namespace storm { return false; } - bool TemplateEdge::usesAssignmentLevels() const { - if (assignments.hasMultipleLevels()) { + bool TemplateEdge::usesAssignmentLevels(bool onlyTransient) const { + if (assignments.hasMultipleLevels(onlyTransient)) { return true; } for (auto const& destination : this->getDestinations()) { - if (destination.usesAssignmentLevels()) { + if (destination.usesAssignmentLevels(onlyTransient)) { return true; } } return false; } - + + int64_t const& TemplateEdge::getLowestAssignmentLevel() const { + return lowestAssignmentLevel; + } + + int64_t const& TemplateEdge::getHighestAssignmentLevel() const { + return highestAssignmentLevel; + } bool TemplateEdge::hasEdgeDestinationAssignments() const { for (auto const& destination : destinations) { diff --git a/src/storm/storage/jani/TemplateEdge.h b/src/storm/storage/jani/TemplateEdge.h index cccc1bb7f..9e8c0e761 100644 --- a/src/storm/storage/jani/TemplateEdge.h +++ b/src/storm/storage/jani/TemplateEdge.h @@ -21,6 +21,7 @@ namespace storm { TemplateEdge(storm::expressions::Expression const& guard, OrderedAssignments const& assignments, std::vector const& destinations); storm::expressions::Expression const& getGuard() const; + void setGuard(storm::expressions::Expression const& newGuard); void addDestination(TemplateEdgeDestination const& destination); @@ -32,17 +33,21 @@ namespace storm { std::size_t getNumberOfDestinations() const; std::vector const& getDestinations() const; + std::vector& getDestinations(); TemplateEdgeDestination const& getDestination(uint64_t index) const; OrderedAssignments const& getAssignments() const; + OrderedAssignments& getAssignments(); /*! * Adds a transient assignment to this edge. * * @param assignment The transient assignment to add. + * @param addToExisting Determines if adding the assigned expression to an already existing assignment is + * allowed (if the assigned variable is quantitative). * @return True if the assignment was added. */ - bool addTransientAssignment(Assignment const& assignment); + bool addTransientAssignment(Assignment const& assignment, bool addToExisting = false); /*! * Retrieves a set of (global) variables that are written by at least one of the edge's destinations. @@ -64,7 +69,7 @@ namespace storm { * assignments are no longer contained in the destination. Note that this may modify the semantics of the * model if assignment levels are being used somewhere in the model. */ - void liftTransientDestinationAssignments(); + void liftTransientDestinationAssignments(int64_t maxLevel = 0); /** * Shifts the assingments from the edges to the destinations. @@ -84,8 +89,20 @@ namespace storm { /*! * Retrieves whether the edge uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; + /*! + * Retrieves the lowest assignment level occurring in a destination assignment. + * If no assignment exists, this value is the highest possible integer + */ + int64_t const& getLowestAssignmentLevel() const; + + /*! + * Retrieves the highest assignment level occurring in a destination assignment + * If no assignment exists, this value is always zero + */ + int64_t const& getHighestAssignmentLevel() const; + /*! * Checks the template edge for linearity. */ @@ -108,6 +125,8 @@ namespace storm { /// The assignments made when taking this edge. OrderedAssignments assignments; + int64_t lowestAssignmentLevel, highestAssignmentLevel; + /// A set of global variables that is written by at least one of the edge's destinations. This set is /// initialized by the call to finalize. boost::container::flat_set writtenGlobalVariables; diff --git a/src/storm/storage/jani/TemplateEdgeContainer.cpp b/src/storm/storage/jani/TemplateEdgeContainer.cpp new file mode 100644 index 000000000..81ce8f874 --- /dev/null +++ b/src/storm/storage/jani/TemplateEdgeContainer.cpp @@ -0,0 +1,12 @@ +#include "storm/storage/jani/TemplateEdgeContainer.h" +#include "storm/storage/jani/TemplateEdge.h" + +namespace storm { + namespace jani { + TemplateEdgeContainer::TemplateEdgeContainer(TemplateEdgeContainer const &other) { + for (auto const& te : other) { + this->insert(std::make_shared(*te)); + } + } + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/TemplateEdgeContainer.h b/src/storm/storage/jani/TemplateEdgeContainer.h new file mode 100644 index 000000000..293302594 --- /dev/null +++ b/src/storm/storage/jani/TemplateEdgeContainer.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace storm { + namespace jani { + + class TemplateEdge; + + struct TemplateEdgeContainer : public std::unordered_set> { + TemplateEdgeContainer() = default; + TemplateEdgeContainer(TemplateEdgeContainer const& other); + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/TemplateEdgeDestination.cpp b/src/storm/storage/jani/TemplateEdgeDestination.cpp index 2d99a1ad1..df0225636 100644 --- a/src/storm/storage/jani/TemplateEdgeDestination.cpp +++ b/src/storm/storage/jani/TemplateEdgeDestination.cpp @@ -27,12 +27,16 @@ namespace storm { return assignments; } + OrderedAssignments& TemplateEdgeDestination::getOrderedAssignments() { + return assignments; + } + bool TemplateEdgeDestination::removeAssignment(Assignment const& assignment) { return assignments.remove(assignment); } - void TemplateEdgeDestination::addAssignment(Assignment const& assignment) { - assignments.add(assignment); + void TemplateEdgeDestination::addAssignment(Assignment const& assignment, bool addToExisting) { + assignments.add(assignment, addToExisting); } bool TemplateEdgeDestination::hasAssignment(Assignment const& assignment) const { @@ -43,8 +47,8 @@ namespace storm { return assignments.hasTransientAssignment(); } - bool TemplateEdgeDestination::usesAssignmentLevels() const { - return assignments.hasMultipleLevels(); + bool TemplateEdgeDestination::usesAssignmentLevels(bool onlyTransient) const { + return assignments.hasMultipleLevels(onlyTransient); } bool TemplateEdgeDestination::isLinear() const { diff --git a/src/storm/storage/jani/TemplateEdgeDestination.h b/src/storm/storage/jani/TemplateEdgeDestination.h index bb94125f9..39e91fbd7 100644 --- a/src/storm/storage/jani/TemplateEdgeDestination.h +++ b/src/storm/storage/jani/TemplateEdgeDestination.h @@ -23,11 +23,12 @@ namespace storm { void changeAssignmentVariables(std::map> const& remapping); OrderedAssignments const& getOrderedAssignments() const; + OrderedAssignments& getOrderedAssignments(); // Convenience methods to access the assignments. bool hasAssignment(Assignment const& assignment) const; bool removeAssignment(Assignment const& assignment); - void addAssignment(Assignment const& assignment); + void addAssignment(Assignment const& assignment, bool addToExisting = false); /*! * Retrieves whether this destination has transient assignments. @@ -37,7 +38,7 @@ namespace storm { /*! * Retrieves whether the edge uses an assignment level other than zero. */ - bool usesAssignmentLevels() const; + bool usesAssignmentLevels(bool onlyTransient = false) const; /*! * Checks whether the templ. edge destination contains one or more assignments diff --git a/src/storm/storage/jani/Variable.cpp b/src/storm/storage/jani/Variable.cpp index 00f867ac2..50fae165b 100644 --- a/src/storm/storage/jani/Variable.cpp +++ b/src/storm/storage/jani/Variable.cpp @@ -4,6 +4,8 @@ #include "storm/storage/jani/BoundedIntegerVariable.h" #include "storm/storage/jani/UnboundedIntegerVariable.h" #include "storm/storage/jani/RealVariable.h" +#include "storm/storage/jani/ArrayVariable.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" namespace storm { namespace jani { @@ -48,6 +50,10 @@ namespace storm { return false; } + bool Variable::isArrayVariable() const { + return false; + } + bool Variable::isTransient() const { return transient; } @@ -96,9 +102,17 @@ namespace storm { return static_cast(*this); } + ArrayVariable& Variable::asArrayVariable() { + return static_cast(*this); + } + + ArrayVariable const& Variable::asArrayVariable() const { + return static_cast(*this); + } + void Variable::substitute(std::map const& substitution) { if (this->hasInitExpression()) { - this->setInitExpression(this->getInitExpression().substitute(substitution)); + this->setInitExpression(substituteJaniExpression(this->getInitExpression(), substitution)); } } diff --git a/src/storm/storage/jani/Variable.h b/src/storm/storage/jani/Variable.h index 010b37449..ab4bf80c1 100644 --- a/src/storm/storage/jani/Variable.h +++ b/src/storm/storage/jani/Variable.h @@ -14,6 +14,7 @@ namespace storm { class BoundedIntegerVariable; class UnboundedIntegerVariable; class RealVariable; + class ArrayVariable; class Variable { public: @@ -72,6 +73,7 @@ namespace storm { virtual bool isBoundedIntegerVariable() const; virtual bool isUnboundedIntegerVariable() const; virtual bool isRealVariable() const; + virtual bool isArrayVariable() const; virtual bool isTransient() const; @@ -84,6 +86,8 @@ namespace storm { UnboundedIntegerVariable const& asUnboundedIntegerVariable() const; RealVariable& asRealVariable(); RealVariable const& asRealVariable() const; + ArrayVariable& asArrayVariable(); + ArrayVariable const& asArrayVariable() const; /*! * Substitutes all variables in all expressions according to the given substitution. diff --git a/src/storm/storage/jani/VariableSet.cpp b/src/storm/storage/jani/VariableSet.cpp index ac692c637..a3af625d5 100644 --- a/src/storm/storage/jani/VariableSet.cpp +++ b/src/storm/storage/jani/VariableSet.cpp @@ -44,6 +44,14 @@ namespace storm { return detail::ConstVariables(realVariables.begin(), realVariables.end()); } + detail::Variables VariableSet::getArrayVariables() { + return detail::Variables(arrayVariables.begin(), arrayVariables.end()); + } + + detail::ConstVariables VariableSet::getArrayVariables() const { + return detail::ConstVariables(arrayVariables.begin(), arrayVariables.end()); + } + Variable const& VariableSet::addVariable(Variable const& variable) { if (variable.isBooleanVariable()) { return addVariable(variable.asBooleanVariable()); @@ -53,6 +61,8 @@ namespace storm { return addVariable(variable.asUnboundedIntegerVariable()); } else if (variable.isRealVariable()) { return addVariable(variable.asRealVariable()); + } else if (variable.isArrayVariable()) { + return addVariable(variable.asArrayVariable()); } STORM_LOG_THROW(false, storm::exceptions::InvalidTypeException, "Cannot add variable of unknown type."); } @@ -109,6 +119,46 @@ namespace storm { return *newVariable; } + ArrayVariable const& VariableSet::addVariable(ArrayVariable const& variable) { + STORM_LOG_THROW(!this->hasVariable(variable.getName()), storm::exceptions::WrongFormatException, "Cannot add variable with name '" << variable.getName() << "', because a variable with that name already exists."); + std::shared_ptr newVariable = std::make_shared(variable); + variables.push_back(newVariable); + arrayVariables.push_back(newVariable); + if (variable.isTransient()) { + transientVariables.push_back(newVariable); + } + nameToVariable.emplace(variable.getName(), variable.getExpressionVariable()); + variableToVariable.emplace(variable.getExpressionVariable(), newVariable); + return *newVariable; + } + + std::vector> VariableSet::dropAllArrayVariables() { + if (!arrayVariables.empty()) { + for (auto const& arrVar : arrayVariables) { + nameToVariable.erase(arrVar->getName()); + variableToVariable.erase(arrVar->getExpressionVariable()); + } + std::vector> newVariables; + for (auto const& v : variables) { + if (!v->isArrayVariable()) { + newVariables.push_back(v); + } + } + variables = std::move(newVariables); + newVariables.clear(); + for (auto const& v : transientVariables) { + if (!v->isArrayVariable()) { + newVariables.push_back(v); + } + } + transientVariables = std::move(newVariables); + } + + std::vector> result = std::move(arrayVariables); + arrayVariables.clear(); + return result; + } + bool VariableSet::hasVariable(std::string const& name) const { return nameToVariable.find(name) != nameToVariable.end(); } @@ -174,6 +224,10 @@ namespace storm { return !realVariables.empty(); } + bool VariableSet::containsArrayVariables() const { + return !arrayVariables.empty(); + } + bool VariableSet::containsNonTransientRealVariables() const { for (auto const& variable : realVariables) { if (!variable->isTransient()) { @@ -193,7 +247,7 @@ namespace storm { } bool VariableSet::empty() const { - return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables()); + return !(containsBooleanVariable() || containsBoundedIntegerVariable() || containsUnboundedIntegerVariables() || containsRealVariables() || containsArrayVariables()); } uint_fast64_t VariableSet::getNumberOfTransientVariables() const { @@ -226,6 +280,16 @@ namespace storm { return result; } + uint_fast64_t VariableSet::getNumberOfNumericalTransientVariables() const { + uint_fast64_t result = 0; + for (auto const& variable : transientVariables) { + if (variable->isRealVariable() || variable->isUnboundedIntegerVariable() || variable->isBoundedIntegerVariable()) { + ++result; + } + } + return result; + } + typename detail::ConstVariables VariableSet::getTransientVariables() const { return detail::ConstVariables(transientVariables.begin(), transientVariables.end()); } @@ -251,6 +315,23 @@ namespace storm { return true; } } + for (auto const& arrayVariable : this->getArrayVariables()) { + if (arrayVariable.hasInitExpression()) { + if (arrayVariable.getInitExpression().containsVariable(variables)) { + return true; + } + } + if (arrayVariable.hasLowerElementTypeBound()) { + if (arrayVariable.getLowerElementTypeBound().containsVariable(variables)) { + return true; + } + } + if (arrayVariable.hasUpperElementTypeBound()) { + if (arrayVariable.getUpperElementTypeBound().containsVariable(variables)) { + return true; + } + } + } return false; } diff --git a/src/storm/storage/jani/VariableSet.h b/src/storm/storage/jani/VariableSet.h index 6d101ad7a..4e4d2d511 100644 --- a/src/storm/storage/jani/VariableSet.h +++ b/src/storm/storage/jani/VariableSet.h @@ -9,6 +9,7 @@ #include "storm/storage/jani/UnboundedIntegerVariable.h" #include "storm/storage/jani/BoundedIntegerVariable.h" #include "storm/storage/jani/RealVariable.h" +#include "storm/storage/jani/ArrayVariable.h" namespace storm { namespace jani { @@ -67,6 +68,16 @@ namespace storm { * Retrieves the real variables in this set. */ detail::ConstVariables getRealVariables() const; + + /*! + * Retrieves the Array variables in this set. + */ + detail::Variables getArrayVariables(); + + /*! + * Retrieves the Array variables in this set. + */ + detail::ConstVariables getArrayVariables() const; /*! * Adds the given variable to this set. @@ -93,6 +104,16 @@ namespace storm { */ RealVariable const& addVariable(RealVariable const& variable); + /*! + * Adds the given real variable to this set. + */ + ArrayVariable const& addVariable(ArrayVariable const& variable); + + /*! + * Removes all array variables in this set + */ + std::vector> dropAllArrayVariables(); + /*! * Retrieves whether this variable set contains a variable with the given name. */ @@ -162,6 +183,11 @@ namespace storm { */ bool containsRealVariables() const; + /*! + * Retrieves whether the set of variables contains a Array variable. + */ + bool containsArrayVariables() const; + /*! * Retrieves whether the set of variables contains a non-transient real variable. */ @@ -192,6 +218,11 @@ namespace storm { */ uint_fast64_t getNumberOfUnboundedIntegerTransientVariables() const; + /*! + * Retrieves the number of numerical (i.e. real, or integer) transient variables in this variable set. + */ + uint_fast64_t getNumberOfNumericalTransientVariables() const; + /*! * Retrieves the transient variables in this variable set. */ @@ -224,6 +255,9 @@ namespace storm { /// The real variables in this set. std::vector> realVariables; + /// The array variables in this set. + std::vector> arrayVariables; + /// The transient variables in this set. std::vector> transientVariables; diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp new file mode 100644 index 000000000..6590845db --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.cpp @@ -0,0 +1,36 @@ +#include "storm/storage/jani/expressions/ArrayAccessExpression.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" + +#include "storm/utility/macros.h" +#include "storm/exceptions/UnexpectedException.h" +namespace storm { + namespace expressions { + + ArrayAccessExpression::ArrayAccessExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& arrayExpression, std::shared_ptr const& indexExpression) : BinaryExpression(manager, type, arrayExpression, indexExpression) { + // Assert correct types + STORM_LOG_ASSERT(getFirstOperand()->getType().isArrayType(), "ArrayAccessExpression for an expression of type " << getFirstOperand()->getType() << "."); + STORM_LOG_ASSERT(type == getFirstOperand()->getType().getElementType(), "The ArrayAccessExpression should have type " << getFirstOperand()->getType().getElementType() << " but has " << type << " instead."); + STORM_LOG_ASSERT(getSecondOperand()->getType().isIntegerType(), "The index expression does not have an integer type."); + } + + std::shared_ptr ArrayAccessExpression::simplify() const { + return std::shared_ptr(new ArrayAccessExpression(getManager(), getType(), getFirstOperand()->simplify(), getSecondOperand()->simplify())); + } + + boost::any ArrayAccessExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_ASSERT(janiVisitor != nullptr, "Visitor of jani expression should be of type JaniVisitor."); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void ArrayAccessExpression::printToStream(std::ostream& stream) const { + if (getFirstOperand()->isVariable()) { + stream << *getFirstOperand(); + } else { + stream << "(" << *getFirstOperand() << ")"; + } + stream << "[" << *getSecondOperand() << "]"; + } + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ArrayAccessExpression.h b/src/storm/storage/jani/expressions/ArrayAccessExpression.h new file mode 100644 index 000000000..a545e123e --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayAccessExpression.h @@ -0,0 +1,32 @@ +#pragma once + +#include "storm/storage/expressions/BinaryExpression.h" + +namespace storm { + namespace expressions { + /*! + * Represents an access to an array. + */ + class ArrayAccessExpression : public BinaryExpression { + public: + + ArrayAccessExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& arrayExpression, std::shared_ptr const& indexExpression); + + // Instantiate constructors and assignments with their default implementations. + ArrayAccessExpression(ArrayAccessExpression const& other) = default; + ArrayAccessExpression& operator=(ArrayAccessExpression const& other) = delete; + ArrayAccessExpression(ArrayAccessExpression&&) = default; + ArrayAccessExpression& operator=(ArrayAccessExpression&&) = delete; + + virtual ~ArrayAccessExpression() = default; + + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + protected: + virtual void printToStream(std::ostream& stream) const override; + + + }; + } +} diff --git a/src/storm/storage/jani/expressions/ArrayExpression.cpp b/src/storm/storage/jani/expressions/ArrayExpression.cpp new file mode 100644 index 000000000..1f6aa0e49 --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayExpression.cpp @@ -0,0 +1,11 @@ +#include "storm/storage/jani/expressions/ArrayExpression.h" + +namespace storm { + namespace expressions { + + ArrayExpression::ArrayExpression(ExpressionManager const& manager, Type const& type) : BaseExpression(manager, type) { + // Intentionally left empty + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ArrayExpression.h b/src/storm/storage/jani/expressions/ArrayExpression.h new file mode 100644 index 000000000..3dbcf480d --- /dev/null +++ b/src/storm/storage/jani/expressions/ArrayExpression.h @@ -0,0 +1,32 @@ +#pragma once + +#include "storm/storage/expressions/BaseExpression.h" + +namespace storm { + namespace expressions { + /*! + * The base class of all array expressions. + */ + class ArrayExpression : public BaseExpression { + public: + + ArrayExpression(ExpressionManager const& manager, Type const& type); + + // Instantiate constructors and assignments with their default implementations. + ArrayExpression(ArrayExpression const& other) = default; + ArrayExpression& operator=(ArrayExpression const& other) = delete; + ArrayExpression(ArrayExpression&&) = default; + ArrayExpression& operator=(ArrayExpression&&) = delete; + + virtual ~ArrayExpression() = default; + + // Returns the size of the array + virtual std::shared_ptr size() const = 0; + + // Returns the element at position i + virtual std::shared_ptr at(uint64_t i) const = 0; + + + }; + } +} diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp new file mode 100644 index 000000000..eb014a70d --- /dev/null +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.cpp @@ -0,0 +1,72 @@ +#include "storm/storage/jani/expressions/ConstructorArrayExpression.h" + +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace expressions { + + ConstructorArrayExpression::ConstructorArrayExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& size, storm::expressions::Variable indexVar, std::shared_ptr const& elementExpression) : ArrayExpression(manager, type), sizeExpression(size), indexVar(indexVar), elementExpression(elementExpression) { + // Intentionally left empty + } + + void ConstructorArrayExpression::gatherVariables(std::set& variables) const { + // The indexVar should not be gathered (unless it is already contained). + bool indexVarContained = variables.find(indexVar) != variables.end(); + sizeExpression->gatherVariables(variables); + elementExpression->gatherVariables(variables); + if (!indexVarContained) { + variables.erase(indexVar); + } + } + + bool ConstructorArrayExpression::containsVariables() const { + if (sizeExpression->containsVariables()) { + return true; + } + // The index variable should not count + std::set variables; + elementExpression->gatherVariables(variables); + variables.erase(indexVar); + return !variables.empty(); + } + + std::shared_ptr ConstructorArrayExpression::simplify() const { + return std::shared_ptr(new ConstructorArrayExpression(getManager(), getType(), sizeExpression->simplify(), indexVar, elementExpression->simplify())); + } + + boost::any ConstructorArrayExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void ConstructorArrayExpression::printToStream(std::ostream& stream) const { + stream << "array[ " << *elementExpression << " | " << indexVar.getExpression() << " < " << *sizeExpression << " ]"; + } + + std::shared_ptr ConstructorArrayExpression::size() const { + return sizeExpression; + } + + std::shared_ptr ConstructorArrayExpression::at(uint64_t i) const { + std::map substitution; + substitution.emplace(indexVar, this->getManager().integer(i)); + + return storm::jani::substituteJaniExpression(elementExpression->toExpression(), substitution).getBaseExpressionPointer(); + } + + std::shared_ptr const& ConstructorArrayExpression::getElementExpression() const { + return elementExpression; + } + + storm::expressions::Variable const& ConstructorArrayExpression::getIndexVar() const { + return indexVar; + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ConstructorArrayExpression.h b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h new file mode 100644 index 000000000..262c6d68e --- /dev/null +++ b/src/storm/storage/jani/expressions/ConstructorArrayExpression.h @@ -0,0 +1,47 @@ +#pragma once + +#include "storm/storage/jani/expressions/ArrayExpression.h" +#include "storm/storage/expressions/Variable.h" + +namespace storm { + namespace expressions { + /*! + * Represents an array of the given size, where the i'th entry is determined by the elementExpression, where occurrences of indexVar will be substituted by i + */ + class ConstructorArrayExpression : public ArrayExpression { + public: + + ConstructorArrayExpression(ExpressionManager const& manager, Type const& type, std::shared_ptr const& size, storm::expressions::Variable indexVar, std::shared_ptr const& elementExpression); + + + // Instantiate constructors and assignments with their default implementations. + ConstructorArrayExpression(ConstructorArrayExpression const& other) = default; + ConstructorArrayExpression& operator=(ConstructorArrayExpression const& other) = delete; + ConstructorArrayExpression(ConstructorArrayExpression&&) = default; + ConstructorArrayExpression& operator=(ConstructorArrayExpression&&) = delete; + + virtual ~ConstructorArrayExpression() = default; + + virtual void gatherVariables(std::set& variables) const override; + virtual bool containsVariables() const override; + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + // Returns the size of the array + virtual std::shared_ptr size() const override; + + // Returns the element at position i + virtual std::shared_ptr at(uint64_t i) const override; + + std::shared_ptr const& getElementExpression() const; + storm::expressions::Variable const& getIndexVar() const; + protected: + virtual void printToStream(std::ostream& stream) const override; + + private: + std::shared_ptr sizeExpression; + storm::expressions::Variable indexVar; + std::shared_ptr elementExpression; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/FunctionCallExpression.cpp b/src/storm/storage/jani/expressions/FunctionCallExpression.cpp new file mode 100644 index 000000000..05004907c --- /dev/null +++ b/src/storm/storage/jani/expressions/FunctionCallExpression.cpp @@ -0,0 +1,80 @@ +#include "storm/storage/jani/expressions/FunctionCallExpression.h" + +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace expressions { + + FunctionCallExpression::FunctionCallExpression(ExpressionManager const& manager, Type const& type, std::string const& functionIdentifier, std::vector> const& arguments) : BaseExpression(manager, type), identifier(functionIdentifier), arguments(arguments) { + // Intentionally left empty + } + + void FunctionCallExpression::gatherVariables(std::set& variables) const { + for (auto const& a : arguments) { + a->gatherVariables(variables); + } + } + + bool FunctionCallExpression::containsVariables() const { + for (auto const& a : arguments) { + if (a->containsVariables()) { + return true; + } + } + return false; + } + + std::shared_ptr FunctionCallExpression::simplify() const { + std::vector> simplifiedArguments; + simplifiedArguments.reserve(arguments.size()); + for (auto const& a : arguments) { + simplifiedArguments.push_back(a->simplify()); + } + return std::shared_ptr(new FunctionCallExpression(getManager(), getType(), identifier, simplifiedArguments)); + } + + boost::any FunctionCallExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void FunctionCallExpression::printToStream(std::ostream& stream) const { + stream << identifier; + if (getNumberOfArguments() > 0) { + stream << "("; + bool first = true; + for (auto const& a : arguments) { + if (!first) { + stream << ", "; + } + first = false; + stream << *a; + } + stream << ")"; + } + } + + std::string const& FunctionCallExpression::getFunctionIdentifier() const { + return identifier; + } + + uint64_t FunctionCallExpression::getNumberOfArguments() const { + return arguments.size(); + } + + std::shared_ptr FunctionCallExpression::getArgument(uint64_t i) const { + STORM_LOG_THROW(i < arguments.size(), storm::exceptions::InvalidArgumentException, "Tried to access the argument with index " << i << " of a function call with " << arguments.size() << " arguments."); + return arguments[i]; + } + + std::vector> const& FunctionCallExpression::getArguments() const { + return arguments; + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/FunctionCallExpression.h b/src/storm/storage/jani/expressions/FunctionCallExpression.h new file mode 100644 index 000000000..66ab8dacd --- /dev/null +++ b/src/storm/storage/jani/expressions/FunctionCallExpression.h @@ -0,0 +1,43 @@ +#pragma once + +#include "storm/storage/expressions/BaseExpression.h" + +namespace storm { + namespace expressions { + /*! + * Represents an array with a given list of elements. + */ + class FunctionCallExpression : public BaseExpression { + public: + + FunctionCallExpression(ExpressionManager const& manager, Type const& type, std::string const& functionIdentifier, std::vector> const& arguments); + + + // Instantiate constructors and assignments with their default implementations. + FunctionCallExpression(FunctionCallExpression const& other) = default; + FunctionCallExpression& operator=(FunctionCallExpression const& other) = delete; + FunctionCallExpression(FunctionCallExpression&&) = default; + FunctionCallExpression& operator=(FunctionCallExpression&&) = delete; + + virtual ~FunctionCallExpression() = default; + + virtual void gatherVariables(std::set& variables) const override; + virtual bool containsVariables() const override; + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + std::string const& getFunctionIdentifier() const; + uint64_t getNumberOfArguments() const; + std::shared_ptr getArgument(uint64_t i) const; + std::vector> const& getArguments() const; + + + protected: + virtual void printToStream(std::ostream& stream) const override; + + private: + std::string identifier; + std::vector> arguments; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp new file mode 100644 index 000000000..168ea960b --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.cpp @@ -0,0 +1,77 @@ +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + + namespace jani { + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::map const& identifierToExpressionMap) { + return storm::expressions::JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); + } + + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::unordered_map const& identifierToExpressionMap) { + return storm::expressions::JaniExpressionSubstitutionVisitor>(identifierToExpressionMap).substitute(expression); + } + } + + namespace expressions { + + template + JaniExpressionSubstitutionVisitor::JaniExpressionSubstitutionVisitor(MapType const& variableToExpressionMapping) : SubstitutionVisitor(variableToExpressionMapping) { + // Intentionally left empty. + } + + template + boost::any JaniExpressionSubstitutionVisitor::visit(ValueArrayExpression const& expression, boost::any const& data) { + uint64_t size = expression.size()->evaluateAsInt(); + std::vector> newElements; + newElements.reserve(size); + for (uint64_t i = 0; i < size; ++i) { + newElements.push_back(boost::any_cast>(expression.at(i)->accept(*this, data))); + } + return std::const_pointer_cast(std::shared_ptr(new ValueArrayExpression(expression.getManager(), expression.getType(), newElements))); + } + + template + boost::any JaniExpressionSubstitutionVisitor::visit(ConstructorArrayExpression const& expression, boost::any const& data) { + std::shared_ptr newSize = boost::any_cast>(expression.size()->accept(*this, data)); + std::shared_ptr elementExpression = boost::any_cast>(expression.getElementExpression()->accept(*this, data)); + STORM_LOG_THROW(this->variableToExpressionMapping.find(expression.getIndexVar()) == this->variableToExpressionMapping.end(), storm::exceptions::InvalidArgumentException, "substitution of the index variable of a constructorArrayExpression is not possible."); + + // If the arguments did not change, we simply push the expression itself. + if (newSize.get() == expression.size().get() && elementExpression.get() == expression.getElementExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new ConstructorArrayExpression(expression.getManager(), expression.getType(), newSize, expression.getIndexVar(), elementExpression))); + } + } + + template + boost::any JaniExpressionSubstitutionVisitor::visit(ArrayAccessExpression const& expression, boost::any const& data) { + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new ArrayAccessExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression))); + } + } + + template + boost::any JaniExpressionSubstitutionVisitor::visit(FunctionCallExpression const& expression, boost::any const& data) { + std::vector> newArguments; + newArguments.reserve(expression.getNumberOfArguments()); + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + newArguments.push_back(boost::any_cast>(expression.getArgument(i)->accept(*this, data))); + } + return std::const_pointer_cast(std::shared_ptr(new FunctionCallExpression(expression.getManager(), expression.getType(), expression.getFunctionIdentifier(), newArguments))); + } + + // Explicitly instantiate the class with map and unordered_map. + template class JaniExpressionSubstitutionVisitor>; + template class JaniExpressionSubstitutionVisitor>; + + } +} diff --git a/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h new file mode 100644 index 000000000..6ae1c80fa --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h @@ -0,0 +1,32 @@ +#pragma once + +#include "storm/storage/expressions/SubstitutionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" + +namespace storm { + + namespace jani { + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::map const& identifierToExpressionMap); + storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const& expression, std::unordered_map const& identifierToExpressionMap); + } + + namespace expressions { + template + class JaniExpressionSubstitutionVisitor : public SubstitutionVisitor, public JaniExpressionVisitor { + public: + /*! + * Creates a new substitution visitor that uses the given map to replace variables. + * + * @param variableToExpressionMapping A mapping from variables to expressions. + */ + JaniExpressionSubstitutionVisitor(MapType const& variableToExpressionMapping); + using SubstitutionVisitor::visit; + + virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) override; + virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) override; + virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override; + virtual boost::any visit(FunctionCallExpression const& expression, boost::any const& data) override; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/JaniExpressionVisitor.h b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h new file mode 100644 index 000000000..99a45f2c5 --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressionVisitor.h @@ -0,0 +1,17 @@ +#pragma once + +#include "storm/storage/expressions/ExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" + + +namespace storm { + namespace expressions { + class JaniExpressionVisitor { + public: + virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) = 0; + virtual boost::any visit(FunctionCallExpression const& expression, boost::any const& data) = 0; + }; + } +} diff --git a/src/storm/storage/jani/expressions/JaniExpressions.h b/src/storm/storage/jani/expressions/JaniExpressions.h new file mode 100644 index 000000000..209d6edd7 --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniExpressions.h @@ -0,0 +1,5 @@ +#include "storm/storage/expressions/Expressions.h" +#include "storm/storage/jani/expressions/ArrayAccessExpression.h" +#include "storm/storage/jani/expressions/ConstructorArrayExpression.h" +#include "storm/storage/jani/expressions/ValueArrayExpression.h" +#include "storm/storage/jani/expressions/FunctionCallExpression.h" diff --git a/src/storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.cpp b/src/storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.cpp new file mode 100644 index 000000000..cdee6e967 --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.cpp @@ -0,0 +1,62 @@ +#include "storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.h" + +#include "storm/exceptions/InvalidArgumentException.h" + +namespace storm { + + namespace jani { + storm::expressions::Expression reduceNestingInJaniExpression(storm::expressions::Expression const& expression) { + return storm::expressions::JaniReduceNestingExpressionVisitor().reduceNesting(expression); + } + } + + namespace expressions { + + JaniReduceNestingExpressionVisitor::JaniReduceNestingExpressionVisitor() : ReduceNestingVisitor() { + // Intentionally left empty. + } + + boost::any JaniReduceNestingExpressionVisitor::visit(ValueArrayExpression const& expression, boost::any const& data) { + uint64_t size = expression.size()->evaluateAsInt(); + std::vector> newElements; + newElements.reserve(size); + for (uint64_t i = 0; i < size; ++i) { + newElements.push_back(boost::any_cast>(expression.at(i)->accept(*this, data))); + } + return std::const_pointer_cast(std::shared_ptr(new ValueArrayExpression(expression.getManager(), expression.getType(), newElements))); + } + + boost::any JaniReduceNestingExpressionVisitor::visit(ConstructorArrayExpression const& expression, boost::any const& data) { + std::shared_ptr newSize = boost::any_cast>(expression.size()->accept(*this, data)); + std::shared_ptr elementExpression = boost::any_cast>(expression.getElementExpression()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (newSize.get() == expression.size().get() && elementExpression.get() == expression.getElementExpression().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new ConstructorArrayExpression(expression.getManager(), expression.getType(), newSize, expression.getIndexVar(), elementExpression))); + } + } + + boost::any JaniReduceNestingExpressionVisitor::visit(ArrayAccessExpression const& expression, boost::any const& data) { + std::shared_ptr firstExpression = boost::any_cast>(expression.getFirstOperand()->accept(*this, data)); + std::shared_ptr secondExpression = boost::any_cast>(expression.getSecondOperand()->accept(*this, data)); + + // If the arguments did not change, we simply push the expression itself. + if (firstExpression.get() == expression.getFirstOperand().get() && secondExpression.get() == expression.getSecondOperand().get()) { + return expression.getSharedPointer(); + } else { + return std::const_pointer_cast(std::shared_ptr(new ArrayAccessExpression(expression.getManager(), expression.getType(), firstExpression, secondExpression))); + } + } + + boost::any JaniReduceNestingExpressionVisitor::visit(FunctionCallExpression const& expression, boost::any const& data) { + std::vector> newArguments; + newArguments.reserve(expression.getNumberOfArguments()); + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + newArguments.push_back(boost::any_cast>(expression.getArgument(i)->accept(*this, data))); + } + return std::const_pointer_cast(std::shared_ptr(new FunctionCallExpression(expression.getManager(), expression.getType(), expression.getFunctionIdentifier(), newArguments))); + } + } +} diff --git a/src/storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.h b/src/storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.h new file mode 100644 index 000000000..c45c1ac6e --- /dev/null +++ b/src/storm/storage/jani/expressions/JaniReduceNestingExpressionVisitor.h @@ -0,0 +1,25 @@ +#pragma once + +#include "storm/storage/expressions/ReduceNestingVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" + +namespace storm { + namespace jani { + storm::expressions::Expression reduceNestingInJaniExpression(storm::expressions::Expression const& expression); + } + + namespace expressions { + + + class JaniReduceNestingExpressionVisitor : public ReduceNestingVisitor, public JaniExpressionVisitor { + public: + JaniReduceNestingExpressionVisitor(); + + virtual boost::any visit(ValueArrayExpression const& expression, boost::any const& data) override; + virtual boost::any visit(ConstructorArrayExpression const& expression, boost::any const& data) override; + virtual boost::any visit(ArrayAccessExpression const& expression, boost::any const& data) override; + virtual boost::any visit(FunctionCallExpression const& expression, boost::any const& data) override; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ValueArrayExpression.cpp b/src/storm/storage/jani/expressions/ValueArrayExpression.cpp new file mode 100644 index 000000000..23c543c80 --- /dev/null +++ b/src/storm/storage/jani/expressions/ValueArrayExpression.cpp @@ -0,0 +1,69 @@ +#include "storm/storage/jani/expressions/ValueArrayExpression.h" + +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/expressions/ExpressionManager.h" + +#include "storm/exceptions/InvalidArgumentException.h" +#include "storm/exceptions/UnexpectedException.h" + +namespace storm { + namespace expressions { + + ValueArrayExpression::ValueArrayExpression(ExpressionManager const& manager, Type const& type, std::vector> const& elements) : ArrayExpression(manager, type), elements(elements) { + // Intentionally left empty + } + + void ValueArrayExpression::gatherVariables(std::set& variables) const { + for (auto const& e : elements) { + e->gatherVariables(variables); + } + } + + bool ValueArrayExpression::containsVariables() const { + for (auto const& e : elements) { + if (e->containsVariables()) { + return true; + } + } + return false; + } + + std::shared_ptr ValueArrayExpression::simplify() const { + std::vector> simplifiedElements; + simplifiedElements.reserve(elements.size()); + for (auto const& e : elements) { + simplifiedElements.push_back(e->simplify()); + } + return std::shared_ptr(new ValueArrayExpression(getManager(), getType(), simplifiedElements)); + } + + boost::any ValueArrayExpression::accept(ExpressionVisitor& visitor, boost::any const& data) const { + auto janiVisitor = dynamic_cast(&visitor); + STORM_LOG_THROW(janiVisitor != nullptr, storm::exceptions::UnexpectedException, "Visitor of jani expression should be of type JaniVisitor."); + return janiVisitor->visit(*this, data); + } + + void ValueArrayExpression::printToStream(std::ostream& stream) const { + stream << "array[ "; + bool first = true; + for (auto const& e : elements) { + stream << *e; + if (!first) { + stream << " , "; + } + first = false; + } + stream << " ]"; + } + + std::shared_ptr ValueArrayExpression::size() const { + return getManager().integer(elements.size()).getBaseExpressionPointer(); + } + + std::shared_ptr ValueArrayExpression::at(uint64_t i) const { + STORM_LOG_THROW(i < elements.size(), storm::exceptions::InvalidArgumentException, "Tried to access the element with index " << i << " of an array of size " << elements.size() << "."); + return elements[i]; + } + + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/expressions/ValueArrayExpression.h b/src/storm/storage/jani/expressions/ValueArrayExpression.h new file mode 100644 index 000000000..770b36db7 --- /dev/null +++ b/src/storm/storage/jani/expressions/ValueArrayExpression.h @@ -0,0 +1,42 @@ +#pragma once + +#include "storm/storage/jani/expressions/ArrayExpression.h" + +namespace storm { + namespace expressions { + /*! + * Represents an array with a given list of elements. + */ + class ValueArrayExpression : public ArrayExpression { + public: + + ValueArrayExpression(ExpressionManager const& manager, Type const& type, std::vector> const& elements); + + + // Instantiate constructors and assignments with their default implementations. + ValueArrayExpression(ValueArrayExpression const& other) = default; + ValueArrayExpression& operator=(ValueArrayExpression const& other) = delete; + ValueArrayExpression(ValueArrayExpression&&) = default; + ValueArrayExpression& operator=(ValueArrayExpression&&) = delete; + + virtual ~ValueArrayExpression() = default; + + virtual void gatherVariables(std::set& variables) const override; + virtual bool containsVariables() const override; + virtual std::shared_ptr simplify() const override; + virtual boost::any accept(ExpressionVisitor& visitor, boost::any const& data) const override; + + // Returns the size of the array + virtual std::shared_ptr size() const override; + + // Returns the element at position i + virtual std::shared_ptr at(uint64_t i) const override; + + protected: + virtual void printToStream(std::ostream& stream) const override; + + private: + std::vector> elements; + }; + } +} \ No newline at end of file diff --git a/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp b/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp new file mode 100644 index 000000000..ffd5ec641 --- /dev/null +++ b/src/storm/storage/jani/traverser/ArrayExpressionFinder.cpp @@ -0,0 +1,111 @@ +#include "storm/storage/jani/traverser/ArrayExpressionFinder.h" + +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/Model.h" + +namespace storm { + namespace jani { + + namespace detail { + class ArrayExpressionFinderExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getCondition()->accept(*this, data)) || + boost::any_cast(expression.getThenExpression()->accept(*this, data)) || + boost::any_cast(expression.getElseExpression()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getFirstOperand()->accept(*this, data)) || + boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getFirstOperand()->accept(*this, data)) || + boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + return + boost::any_cast(expression.getFirstOperand()->accept(*this, data)) || + boost::any_cast(expression.getSecondOperand()->accept(*this, data)); + } + + virtual boost::any visit(storm::expressions::VariableExpression const&, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + return expression.getOperand()->accept(*this, data); + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + return expression.getOperand()->accept(*this, data); + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const&, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const&, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const&, boost::any const&) override { + return false; + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const&, boost::any const&) override { + return true; + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const&, boost::any const&) override { + return true; + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const&, boost::any const&) override { + return true; + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + if (boost::any_cast(expression.getArgument(i)->accept(*this, data))) { + return true; + } + } + return false; + } + }; + + class ArrayExpressionFinderTraverser : public ConstJaniTraverser { + public: + virtual void traverse(Model const& model, boost::any const& data) override { + ConstJaniTraverser::traverse(model, data); + } + + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) override { + auto& res = *boost::any_cast(data); + res = res || containsArrayExpression(expression); + } + }; + } + + + bool containsArrayExpression(Model const& model) { + bool result = false; + detail::ArrayExpressionFinderTraverser().traverse(model, &result); + return result; + } + + bool containsArrayExpression(storm::expressions::Expression const& expression) { + detail::ArrayExpressionFinderExpressionVisitor v; + return boost::any_cast(expression.accept(v, boost::any())); + } + } +} + diff --git a/src/storm/storage/jani/traverser/ArrayExpressionFinder.h b/src/storm/storage/jani/traverser/ArrayExpressionFinder.h new file mode 100644 index 000000000..c924472cd --- /dev/null +++ b/src/storm/storage/jani/traverser/ArrayExpressionFinder.h @@ -0,0 +1,18 @@ +#pragma once + + +namespace storm { + + namespace expressions { + class Expression; + } + + namespace jani { + + class Model; + + bool containsArrayExpression(Model const& model); + bool containsArrayExpression(storm::expressions::Expression const& expr); + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp b/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp new file mode 100644 index 000000000..0872c1f4f --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentLevelFinder.cpp @@ -0,0 +1,19 @@ +#include "storm/storage/jani/traverser/AssignmentLevelFinder.h" + + +namespace storm { + namespace jani { + + int64_t AssignmentLevelFinder::getLowestAssignmentLevel(Model const& model) { + int64_t res = std::numeric_limits::max(); + ConstJaniTraverser::traverse(model, &res); + return res; + } + + void AssignmentLevelFinder::traverse(Assignment const& assignment, boost::any const& data) { + auto& res = *boost::any_cast(data); + res = std::min(res, assignment.getLevel()); + } + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentLevelFinder.h b/src/storm/storage/jani/traverser/AssignmentLevelFinder.h new file mode 100644 index 000000000..c8887df7a --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentLevelFinder.h @@ -0,0 +1,19 @@ +#pragma once + +#include "storm/storage/jani/traverser/JaniTraverser.h" + +namespace storm { + namespace jani { + class AssignmentLevelFinder : public ConstJaniTraverser { + public: + + AssignmentLevelFinder() = default; + virtual ~AssignmentLevelFinder() = default; + + int64_t getLowestAssignmentLevel(Model const& model); + + virtual void traverse(Assignment const& assignment, boost::any const& data) override; + }; + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.cpp b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp new file mode 100644 index 000000000..c232cddd8 --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.cpp @@ -0,0 +1,65 @@ +#include "storm/storage/jani/traverser/AssignmentsFinder.h" + +#include "storm/storage/expressions/Variable.h" + +namespace storm { + namespace jani { + + AssignmentsFinder::ResultType AssignmentsFinder::find(Model const& model, storm::jani::Variable const& variable) { + return find(model, variable.getExpressionVariable()); + } + + AssignmentsFinder::ResultType AssignmentsFinder::find(Model const& model, storm::expressions::Variable const& variable) { + ResultType res; + res.hasLocationAssignment = false; + res.hasEdgeAssignment = false; + res.hasEdgeDestinationAssignment = false; + ConstJaniTraverser::traverse(model, std::make_pair(&variable, &res)); + return res; + } + + void AssignmentsFinder::traverse(Location const& location, boost::any const& data) { + auto resVar = boost::any_cast>(data); + if (!resVar.second->hasLocationAssignment) { + for (auto const& assignment : location.getAssignments()) { + storm::jani::Variable const& assignedVariable = assignment.lValueIsArrayAccess() ? assignment.getLValue().getArray() : assignment.getVariable(); + if (assignedVariable.getExpressionVariable() == *resVar.first) { + resVar.second->hasLocationAssignment = true; + break; + } + } + } + } + + void AssignmentsFinder::traverse(TemplateEdge const& templateEdge, boost::any const& data) { + auto resVar = boost::any_cast>(data); + if (!resVar.second->hasEdgeAssignment) { + for (auto const& assignment : templateEdge.getAssignments()) { + storm::jani::Variable const& assignedVariable = assignment.lValueIsArrayAccess() ? assignment.getLValue().getArray() : assignment.getVariable(); + if (assignedVariable.getExpressionVariable() == *resVar.first) { + resVar.second->hasEdgeAssignment = true; + break; + } + + } + } + for (auto const& dest : templateEdge.getDestinations()) { + traverse(dest, data); + } + } + + void AssignmentsFinder::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) { + auto resVar = boost::any_cast>(data); + if (!resVar.second->hasEdgeDestinationAssignment) { + for (auto const& assignment : templateEdgeDestination.getOrderedAssignments()) { + storm::jani::Variable const& assignedVariable = assignment.lValueIsArrayAccess() ? assignment.getLValue().getArray() : assignment.getVariable(); + if (assignedVariable.getExpressionVariable() == *resVar.first) { + resVar.second->hasEdgeDestinationAssignment = true; + break; + } + } + } + } + } +} + diff --git a/src/storm/storage/jani/traverser/AssignmentsFinder.h b/src/storm/storage/jani/traverser/AssignmentsFinder.h new file mode 100644 index 000000000..5a2f1598f --- /dev/null +++ b/src/storm/storage/jani/traverser/AssignmentsFinder.h @@ -0,0 +1,35 @@ +#pragma once + + +#include + +#include "storm/storage/jani/traverser/JaniTraverser.h" + +namespace storm { + + namespace expressions { + class Variable; + } + + namespace jani { + class AssignmentsFinder : public ConstJaniTraverser { + public: + + struct ResultType { + bool hasLocationAssignment, hasEdgeAssignment, hasEdgeDestinationAssignment; + }; + + AssignmentsFinder() = default; + + ResultType find(Model const& model, storm::jani::Variable const& variable); + ResultType find(Model const& model, storm::expressions::Variable const& variable); + + virtual ~AssignmentsFinder() = default; + + virtual void traverse(Location const& location, boost::any const& data) override; + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data) override; + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) override; + }; + } +} + diff --git a/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp new file mode 100644 index 000000000..b2e373dbd --- /dev/null +++ b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.cpp @@ -0,0 +1,124 @@ +#include "storm/storage/jani/traverser/FunctionCallExpressionFinder.h" + +#include "storm/storage/jani/traverser/JaniTraverser.h" +#include "storm/storage/jani/expressions/JaniExpressionVisitor.h" +#include "storm/storage/jani/expressions/JaniExpressions.h" +#include "storm/storage/jani/Model.h" + +namespace storm { + namespace jani { + + namespace detail { + class FunctionCallExpressionFinderExpressionVisitor : public storm::expressions::ExpressionVisitor, public storm::expressions::JaniExpressionVisitor { + public: + virtual boost::any visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) override { + expression.getCondition()->accept(*this, data); + expression.getThenExpression()->accept(*this, data); + expression.getElseExpression()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BinaryBooleanFunctionExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BinaryNumericalFunctionExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BinaryRelationExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::VariableExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::UnaryBooleanFunctionExpression const& expression, boost::any const& data) override { + expression.getOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::UnaryNumericalFunctionExpression const& expression, boost::any const& data) override { + expression.getOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::BooleanLiteralExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::IntegerLiteralExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::RationalLiteralExpression const&, boost::any const&) override { + return boost::any(); + } + + virtual boost::any visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) override { + STORM_LOG_ASSERT(expression.size()->isIntegerLiteralExpression(), "unexpected kind of size expression of ValueArrayExpression (" << expression.size()->toExpression() << ")."); + uint64_t size = expression.size()->evaluateAsInt(); + for (uint64_t i = 0; i < size; ++i) { + expression.at(i)->accept(*this, data); + } + return boost::any(); + } + + virtual boost::any visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) override { + expression.getElementExpression()->accept(*this, data); + expression.size()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) override { + expression.getFirstOperand()->accept(*this, data); + expression.getSecondOperand()->accept(*this, data); + return boost::any(); + } + + virtual boost::any visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) override { + auto& set = *boost::any_cast*>(data); + set.insert(expression.getFunctionIdentifier()); + for (uint64_t i = 0; i < expression.getNumberOfArguments(); ++i) { + expression.getArgument(i)->accept(*this, data); + } + return boost::any(); + } + }; + + class FunctionCallExpressionFinderTraverser : public ConstJaniTraverser { + public: + virtual void traverse(Model const& model, boost::any const& data) override { + ConstJaniTraverser::traverse(model, data); + } + + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data) override { + auto& res = *boost::any_cast(data); + res = res || !getOccurringFunctionCalls(expression).empty(); + } + }; + } + + + bool containsFunctionCallExpression(Model const& model) { + bool result = false; + detail::FunctionCallExpressionFinderTraverser().traverse(model, &result); + return result; + } + + std::unordered_set getOccurringFunctionCalls(storm::expressions::Expression const& expression) { + detail::FunctionCallExpressionFinderExpressionVisitor v; + std::unordered_set result; + expression.accept(v, &result); + return result; + } + } +} + diff --git a/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h new file mode 100644 index 000000000..e191eee4a --- /dev/null +++ b/src/storm/storage/jani/traverser/FunctionCallExpressionFinder.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace storm { + + namespace expressions { + class Expression; + } + + namespace jani { + + class Model; + + bool containsFunctionCallExpression(Model const& model); + std::unordered_set getOccurringFunctionCalls(storm::expressions::Expression const& expr); + } +} + diff --git a/src/storm/storage/jani/traverser/JaniTraverser.cpp b/src/storm/storage/jani/traverser/JaniTraverser.cpp new file mode 100644 index 000000000..e77377a15 --- /dev/null +++ b/src/storm/storage/jani/traverser/JaniTraverser.cpp @@ -0,0 +1,340 @@ +#include "storm/storage/jani/traverser/JaniTraverser.h" + + +namespace storm { + namespace jani { + + void JaniTraverser::traverse(Model& model, boost::any const& data) { + for (auto& act : model.getActions()) { + traverse(act, data); + } + for (auto& c : model.getConstants()) { + traverse(c, data); + } + for (auto& f : model.getGlobalFunctionDefinitions()) { + traverse(f.second, data); + } + traverse(model.getGlobalVariables(), data); + for (auto& aut : model.getAutomata()) { + traverse(aut, data); + } + if (model.hasInitialStatesRestriction()) { + traverse(model.getInitialStatesRestriction(), data); + } + for (auto& nonTrivRew : model.getNonTrivialRewardExpressions()) { + traverse(nonTrivRew.second, data); + } + } + + void JaniTraverser::traverse(Action const&, boost::any const&) { + // Intentionally left empty. + } + + void JaniTraverser::traverse(Automaton& automaton, boost::any const& data) { + traverse(automaton.getVariables(), data); + for (auto& f : automaton.getFunctionDefinitions()) { + traverse(f.second, data); + } + for (auto& loc : automaton.getLocations()) { + traverse(loc, data); + } + traverse(automaton.getEdgeContainer(), data); + if (automaton.hasInitialStatesRestriction()) { + traverse(automaton.getInitialStatesRestriction(), data); + } + } + + void JaniTraverser::traverse(Constant& constant, boost::any const& data) { + if (constant.isDefined()) { + traverse(constant.getExpression(), data); + } + } + + void JaniTraverser::traverse(FunctionDefinition& functionDefinition, boost::any const& data) { + traverse(functionDefinition.getFunctionBody(), data); + } + + void JaniTraverser::traverse(VariableSet& variableSet, boost::any const& data) { + for (auto& v : variableSet.getBooleanVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getBoundedIntegerVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getUnboundedIntegerVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getRealVariables()) { + traverse(v, data); + } + for (auto& v : variableSet.getArrayVariables()) { + traverse(v, data); + } + } + + void JaniTraverser::traverse(Location& location, boost::any const& data) { + traverse(location.getAssignments(), data); + } + + void JaniTraverser::traverse(BooleanVariable& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void JaniTraverser::traverse(BoundedIntegerVariable& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + traverse(variable.getLowerBound(), data); + traverse(variable.getUpperBound(), data); + } + + void JaniTraverser::traverse(UnboundedIntegerVariable& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void JaniTraverser::traverse(RealVariable& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void JaniTraverser::traverse(ArrayVariable& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + if (variable.hasLowerElementTypeBound()) { + traverse(variable.getLowerElementTypeBound(), data); + } + if (variable.hasUpperElementTypeBound()) { + traverse(variable.getUpperElementTypeBound(), data); + } + } + + void JaniTraverser::traverse(EdgeContainer& edgeContainer, boost::any const& data) { + for (auto& templateEdge : edgeContainer.getTemplateEdges()) { + traverse(*templateEdge, data); + } + for (auto& concreteEdge : edgeContainer.getConcreteEdges()) { + traverse(concreteEdge, data); + } + } + + void JaniTraverser::traverse(TemplateEdge& templateEdge, boost::any const& data) { + traverse(templateEdge.getGuard(), data); + for (auto& dest : templateEdge.getDestinations()) { + traverse(dest, data); + } + traverse(templateEdge.getAssignments(), data); + } + + void JaniTraverser::traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data) { + traverse(templateEdgeDestination.getOrderedAssignments(), data); + } + + void JaniTraverser::traverse(Edge& edge, boost::any const& data) { + if (edge.hasRate()) { + traverse(edge.getRate(), data); + } + for (auto& dest : edge.getDestinations()) { + traverse(dest, data); + } + } + + void JaniTraverser::traverse(EdgeDestination& edgeDestination, boost::any const& data) { + traverse(edgeDestination.getProbability(), data); + } + + void JaniTraverser::traverse(OrderedAssignments& orderedAssignments, boost::any const& data) { + for (auto& assignment : orderedAssignments) { + traverse(assignment, data); + } + STORM_LOG_ASSERT(orderedAssignments.checkOrder(), "Order of ordered assignment has been violated."); + } + + void JaniTraverser::traverse(Assignment& assignment, boost::any const& data) { + traverse(assignment.getAssignedExpression(), data); + traverse(assignment.getLValue(), data); + } + + void JaniTraverser::traverse(LValue& lValue, boost::any const& data) { + if (lValue.isArrayAccess()) { + traverse(lValue.getArrayIndex(), data); + } + } + + void JaniTraverser::traverse(storm::expressions::Expression const&, boost::any const&) { + // intentionally left empty. + } + + void ConstJaniTraverser::traverse(Model const& model, boost::any const& data) { + for (auto const& act : model.getActions()) { + traverse(act, data); + } + for (auto const& c : model.getConstants()) { + traverse(c, data); + } + for (auto const& f : model.getGlobalFunctionDefinitions()) { + traverse(f.second, data); + } + traverse(model.getGlobalVariables(), data); + for (auto const& aut : model.getAutomata()) { + traverse(aut, data); + } + if (model.hasInitialStatesRestriction()) { + traverse(model.getInitialStatesRestriction(), data); + } + for (auto const& nonTrivRew : model.getNonTrivialRewardExpressions()) { + traverse(nonTrivRew.second, data); + } + } + + void ConstJaniTraverser::traverse(Action const&, boost::any const&) { + // Intentionally left empty. + } + + void ConstJaniTraverser::traverse(Automaton const& automaton, boost::any const& data) { + traverse(automaton.getVariables(), data); + for (auto const& f : automaton.getFunctionDefinitions()) { + traverse(f.second, data); + } + for (auto const& loc : automaton.getLocations()) { + traverse(loc, data); + } + traverse(automaton.getEdgeContainer(), data); + if (automaton.hasInitialStatesRestriction()) { + traverse(automaton.getInitialStatesRestriction(), data); + } + } + + void ConstJaniTraverser::traverse(Constant const& constant, boost::any const& data) { + if (constant.isDefined()) { + traverse(constant.getExpression(), data); + } + } + + void ConstJaniTraverser::traverse(FunctionDefinition const& functionDefinition, boost::any const& data) { + traverse(functionDefinition.getFunctionBody(), data); + } + + void ConstJaniTraverser::traverse(VariableSet const& variableSet, boost::any const& data) { + for (auto const& v : variableSet.getBooleanVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getBoundedIntegerVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getUnboundedIntegerVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getRealVariables()) { + traverse(v, data); + } + for (auto const& v : variableSet.getArrayVariables()) { + traverse(v, data); + } + } + + void ConstJaniTraverser::traverse(Location const& location, boost::any const& data) { + traverse(location.getAssignments(), data); + } + + void ConstJaniTraverser::traverse(BooleanVariable const& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void ConstJaniTraverser::traverse(BoundedIntegerVariable const& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + traverse(variable.getLowerBound(), data); + traverse(variable.getUpperBound(), data); + } + + void ConstJaniTraverser::traverse(UnboundedIntegerVariable const& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void ConstJaniTraverser::traverse(RealVariable const& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + } + + void ConstJaniTraverser::traverse(ArrayVariable const& variable, boost::any const& data) { + if (variable.hasInitExpression()) { + traverse(variable.getInitExpression(), data); + } + if (variable.hasLowerElementTypeBound()) { + traverse(variable.getLowerElementTypeBound(), data); + } + if (variable.hasUpperElementTypeBound()) { + traverse(variable.getUpperElementTypeBound(), data); + } + } + + void ConstJaniTraverser::traverse(EdgeContainer const& edgeContainer, boost::any const& data) { + for (auto const& templateEdge : edgeContainer.getTemplateEdges()) { + traverse(*templateEdge, data); + } + for (auto const& concreteEdge : edgeContainer.getConcreteEdges()) { + traverse(concreteEdge, data); + } + } + + void ConstJaniTraverser::traverse(TemplateEdge const& templateEdge, boost::any const& data) { + traverse(templateEdge.getGuard(), data); + for (auto const& dest : templateEdge.getDestinations()) { + traverse(dest, data); + } + traverse(templateEdge.getAssignments(), data); + } + + void ConstJaniTraverser::traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data) { + traverse(templateEdgeDestination.getOrderedAssignments(), data); + } + + void ConstJaniTraverser::traverse(Edge const& edge, boost::any const& data) { + if (edge.hasRate()) { + traverse(edge.getRate(), data); + } + for (auto const& dest : edge.getDestinations()) { + traverse(dest, data); + } + } + + void ConstJaniTraverser::traverse(EdgeDestination const& edgeDestination, boost::any const& data) { + traverse(edgeDestination.getProbability(), data); + } + + void ConstJaniTraverser::traverse(OrderedAssignments const& orderedAssignments, boost::any const& data) { + for (auto const& assignment : orderedAssignments) { + traverse(assignment, data); + } + } + + void ConstJaniTraverser::traverse(Assignment const& assignment, boost::any const& data) { + traverse(assignment.getAssignedExpression(), data); + traverse(assignment.getLValue(), data); + } + + void ConstJaniTraverser::traverse(LValue const& lValue, boost::any const& data) { + if (lValue.isArrayAccess()) { + traverse(lValue.getArrayIndex(), data); + } + } + + void ConstJaniTraverser::traverse(storm::expressions::Expression const&, boost::any const&) { + // intentionally left empty. + } + + } +} + diff --git a/src/storm/storage/jani/traverser/JaniTraverser.h b/src/storm/storage/jani/traverser/JaniTraverser.h new file mode 100644 index 000000000..a7da8bc6f --- /dev/null +++ b/src/storm/storage/jani/traverser/JaniTraverser.h @@ -0,0 +1,67 @@ +#pragma once + + +#include + +#include "storm/storage/jani/Model.h" + +namespace storm { + namespace jani { + class JaniTraverser { + public: + virtual ~JaniTraverser() = default; + + virtual void traverse(Model& model, boost::any const& data); + + virtual void traverse(Action const& action, boost::any const& data); + virtual void traverse(Automaton& automaton, boost::any const& data); + virtual void traverse(Constant& constant, boost::any const& data); + virtual void traverse(FunctionDefinition& functionDefinition, boost::any const& data); + virtual void traverse(VariableSet& variableSet, boost::any const& data); + virtual void traverse(Location& location, boost::any const& data); + virtual void traverse(BooleanVariable& variable, boost::any const& data); + virtual void traverse(BoundedIntegerVariable& variable, boost::any const& data); + virtual void traverse(UnboundedIntegerVariable& variable, boost::any const& data); + virtual void traverse(RealVariable& variable, boost::any const& data); + virtual void traverse(ArrayVariable& variable, boost::any const& data); + virtual void traverse(EdgeContainer& edgeContainer, boost::any const& data); + virtual void traverse(TemplateEdge& templateEdge, boost::any const& data); + virtual void traverse(TemplateEdgeDestination& templateEdgeDestination, boost::any const& data); + virtual void traverse(Edge& edge, boost::any const& data); + virtual void traverse(EdgeDestination& edgeDestination, boost::any const& data); + virtual void traverse(OrderedAssignments& orderedAssignments, boost::any const& data); + virtual void traverse(Assignment& assignment, boost::any const& data); + virtual void traverse(LValue& lValue, boost::any const& data); + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data); + }; + + class ConstJaniTraverser { + public: + virtual ~ConstJaniTraverser() = default; + + virtual void traverse(Model const& model, boost::any const& data); + + virtual void traverse(Action const& action, boost::any const& data); + virtual void traverse(Automaton const& automaton, boost::any const& data); + virtual void traverse(Constant const& constant, boost::any const& data); + virtual void traverse(FunctionDefinition const& functionDefinition, boost::any const& data); + virtual void traverse(VariableSet const& variableSet, boost::any const& data); + virtual void traverse(Location const& location, boost::any const& data); + virtual void traverse(BooleanVariable const& variable, boost::any const& data); + virtual void traverse(BoundedIntegerVariable const& variable, boost::any const& data); + virtual void traverse(UnboundedIntegerVariable const& variable, boost::any const& data); + virtual void traverse(RealVariable const& variable, boost::any const& data); + virtual void traverse(ArrayVariable const& variable, boost::any const& data); + virtual void traverse(EdgeContainer const& edgeContainer, boost::any const& data); + virtual void traverse(TemplateEdge const& templateEdge, boost::any const& data); + virtual void traverse(TemplateEdgeDestination const& templateEdgeDestination, boost::any const& data); + virtual void traverse(Edge const& edge, boost::any const& data); + virtual void traverse(EdgeDestination const& edgeDestination, boost::any const& data); + virtual void traverse(OrderedAssignments const& orderedAssignments, boost::any const& data); + virtual void traverse(Assignment const& assignment, boost::any const& data); + virtual void traverse(LValue const& lValue, boost::any const& data); + virtual void traverse(storm::expressions::Expression const& expression, boost::any const& data); + }; + } +} + diff --git a/src/storm/storage/prism/Formula.cpp b/src/storm/storage/prism/Formula.cpp index 3134bc033..3930779da 100644 --- a/src/storm/storage/prism/Formula.cpp +++ b/src/storm/storage/prism/Formula.cpp @@ -2,6 +2,10 @@ namespace storm { namespace prism { + Formula::Formula(storm::expressions::Variable const& variable, storm::expressions::Expression const& expression, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), name(variable.getName()), variable(variable), expression(expression) { + // Intentionally left empty. + } + Formula::Formula(std::string const& name, storm::expressions::Expression const& expression, std::string const& filename, uint_fast64_t lineNumber) : LocatedInformation(filename, lineNumber), name(name), expression(expression) { // Intentionally left empty. } @@ -10,16 +14,29 @@ namespace storm { return this->name; } + bool Formula::hasExpressionVariable() const { + return this->variable.is_initialized(); + } + + storm::expressions::Variable const& Formula::getExpressionVariable() const { + return this->variable.get(); + } + storm::expressions::Expression const& Formula::getExpression() const { return this->expression; } storm::expressions::Type const& Formula::getType() const { - return this->getExpression().getType(); + assert(!hasExpressionVariable() || this->getExpressionVariable().getType() == this->getExpression().getType()); + return this->getExpressionVariable().getType(); } Formula Formula::substitute(std::map const& substitution) const { - return Formula(this->getName(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); + if (hasExpressionVariable()) { + return Formula(this->getExpressionVariable(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); + } else { + return Formula(this->getName(), this->getExpression().substitute(substitution), this->getFilename(), this->getLineNumber()); + } } std::ostream& operator<<(std::ostream& stream, Formula const& formula) { diff --git a/src/storm/storage/prism/Formula.h b/src/storm/storage/prism/Formula.h index 17d2f0cbd..d823b8da4 100644 --- a/src/storm/storage/prism/Formula.h +++ b/src/storm/storage/prism/Formula.h @@ -2,6 +2,7 @@ #define STORM_STORAGE_PRISM_FORMULA_H_ #include +#include #include "storm/storage/prism/LocatedInformation.h" #include "storm/storage/expressions/Expression.h" @@ -13,9 +14,19 @@ namespace storm { class Formula : public LocatedInformation { public: /*! - * Creates a formula with the given name and expression. + * Creates a formula with the given placeholder variable and expression. * - * @param name The name of the formula. + * @param variable The placeholder variable that is used in expressions to represent this formula. + * @param expression The expression associated with this formula. + * @param filename The filename in which the transition reward is defined. + * @param lineNumber The line number in which the transition reward is defined. + */ + Formula(storm::expressions::Variable const& variable, storm::expressions::Expression const& expression, std::string const& filename = "", uint_fast64_t lineNumber = 0); + + /*! + * Creates a formula with the given name + * + * @param name the name of the formula. * @param expression The expression associated with this formula. * @param filename The filename in which the transition reward is defined. * @param lineNumber The line number in which the transition reward is defined. @@ -36,6 +47,19 @@ namespace storm { */ std::string const& getName() const; + /*! + * Retrieves wheter a placeholder variable is used in expressions to represent this formula. + * + */ + bool hasExpressionVariable() const; + + /*! + * Retrieves the placeholder variable that is used in expressions to represent this formula. + * + * @return The placeholder variable that is used in expressions to represent this formula. + */ + storm::expressions::Variable const& getExpressionVariable() const; + /*! * Retrieves the expression that is associated with this formula. * @@ -64,6 +88,9 @@ namespace storm { // The name of the formula. std::string name; + // Expression variable that is used as a placeholder for this formula + boost::optional variable; + // A predicate that needs to be satisfied by states for the label to be attached. storm::expressions::Expression expression; }; diff --git a/src/storm/storage/prism/InitialConstruct.cpp b/src/storm/storage/prism/InitialConstruct.cpp index a2bce30e9..715b76752 100644 --- a/src/storm/storage/prism/InitialConstruct.cpp +++ b/src/storm/storage/prism/InitialConstruct.cpp @@ -16,9 +16,9 @@ namespace storm { } std::ostream& operator<<(std::ostream& stream, InitialConstruct const& initialConstruct) { - stream << "initial " << std::endl; + stream << "init " << std::endl; stream << "\t" << initialConstruct.getInitialStatesExpression() << std::endl; - stream << "endinitial" << std::endl; + stream << "endinit" << std::endl; return stream; } } // namespace prism diff --git a/src/storm/storage/prism/Program.cpp b/src/storm/storage/prism/Program.cpp index 92e4a18dc..332bef0fd 100644 --- a/src/storm/storage/prism/Program.cpp +++ b/src/storm/storage/prism/Program.cpp @@ -17,6 +17,7 @@ #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/InvalidOperationException.h" #include "storm/solver/SmtSolver.h" +#include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/prism/CompositionVisitor.h" #include "storm/storage/prism/Compositions.h" @@ -193,10 +194,19 @@ namespace storm { return modelType == ModelType::DTMC || modelType == ModelType::CTMC; } + bool Program::isPartiallyObservable() const { return modelType == ModelType::POMDP; } + size_t Program::getNumberOfCommands() const { + size_t res = 0; + for (auto const& module : this->getModules()) { + res += module.getNumberOfCommands(); + } + return res; + } + bool Program::hasUndefinedConstants() const { for (auto const& constant : this->getConstants()) { if (!constant.isDefined()) { @@ -320,14 +330,76 @@ namespace storm { } std::map Program::getConstantsSubstitution() const { - std::map constantsSubstitution; - for (auto const& constant : this->getConstants()) { - if (constant.isDefined()) { - constantsSubstitution.emplace(constant.getExpressionVariable(), constant.getExpression()); + return getConstantsFormulasSubstitution(true, false); + } + + std::map Program::getFormulasSubstitution() const { + return getConstantsFormulasSubstitution(false, true); + } + + std::map Program::getConstantsFormulasSubstitution(bool getConstantsSubstitution, bool getFormulasSubstitution) const { + std::map result; + if (getConstantsSubstitution) { + for (auto const& constant : this->getConstants()) { + if (constant.isDefined()) { + result.emplace(constant.getExpressionVariable(), constant.getExpression().substitute(result)); + } + } + } + if (getFormulasSubstitution) { + for (auto const& formula : this->getFormulas()) { + result.emplace(formula.getExpressionVariable(), formula.getExpression().substitute(result)); + } + } + return result; + } + + std::map Program::getSubstitutionForRenamedModule(Module const& renamedModule, std::map const& substitution) const { + auto renaming = getFinalRenamingOfModule(renamedModule); + std::map renamingAsSubstitution; + for (auto const& renamingPair : renaming) { + if (getManager().hasVariable(renamingPair.first)) { + assert(getManager().hasVariable(renamingPair.second)); + renamingAsSubstitution.emplace(getManager().getVariable(renamingPair.first), getManager().getVariableExpression(renamingPair.second)); + } + } + + std::map newSubstitution; + for (auto const& substVarExpr : substitution) { + newSubstitution.emplace(substVarExpr.first, storm::jani::substituteJaniExpression(substVarExpr.second, renamingAsSubstitution)); + } + return newSubstitution; + } + + std::map Program::getFinalRenamingOfModule(Module const& renamedModule) const { + std::vector moduleStack = {&renamedModule}; + while (moduleStack.back()->isRenamedFromModule()) { + moduleStack.push_back(&getModule(moduleStack.back()->getBaseModule())); + } + + assert(!moduleStack.back()->isRenamedFromModule()); + moduleStack.pop_back(); + assert(moduleStack.empty() || moduleStack.back()->isRenamedFromModule()); + std::map currentRenaming; + while (!moduleStack.empty()) { + Module const& currentModule = *moduleStack.back(); + moduleStack.pop_back(); + assert(currentModule.isRenamedFromModule()); + std::map newRenaming = currentModule.getRenaming(); + for (auto const& renaimingPair : newRenaming) { + auto findRes = currentRenaming.find(renaimingPair.second); + if (findRes != currentRenaming.end()) { + newRenaming[renaimingPair.second] = findRes->second; + currentRenaming.erase(findRes); + } } + newRenaming.insert(currentRenaming.begin(), currentRenaming.end()); + currentRenaming = std::move(newRenaming); } - return constantsSubstitution; + return currentRenaming; } + + std::size_t Program::getNumberOfConstants() const { return this->getConstants().size(); @@ -783,63 +855,73 @@ namespace storm { } Program Program::substituteConstants() const { + return substituteConstantsFormulas(true, false); + } + + Program Program::substituteFormulas() const { + return substituteConstantsFormulas(false, true); + } + + Program Program::substituteConstantsFormulas(bool substituteConstants, bool substituteFormulas) const { + // Formulas need to be substituted first. otherwise, constants appearing in formula expressions can not be handled properly + if (substituteConstants && substituteFormulas) { + return this->substituteFormulas().substituteConstants(); + } + // We start by creating the appropriate substitution. - std::map constantSubstitution; - std::vector newConstants(this->getConstants()); - for (uint_fast64_t constantIndex = 0; constantIndex < newConstants.size(); ++constantIndex) { - auto const& constant = newConstants[constantIndex]; - - // Put the corresponding expression in the substitution. - if (constant.isDefined()) { - constantSubstitution.emplace(constant.getExpressionVariable(), constant.getExpression().simplify()); - - // If there is at least one more constant to come, we substitute the constants we have so far. - if (constantIndex + 1 < newConstants.size()) { - newConstants[constantIndex + 1] = newConstants[constantIndex + 1].substitute(constantSubstitution); - } - } + std::map substitution = getConstantsFormulasSubstitution(substituteConstants, substituteFormulas); + + std::vector newConstants; + newConstants.reserve(this->getNumberOfConstants()); + for (auto const& oldConstant : this->getConstants()) { + newConstants.push_back(oldConstant.substitute(substitution)); + } + + std::vector newFormulas; + newFormulas.reserve(this->getNumberOfFormulas()); + for (auto const& oldFormula : this->getFormulas()) { + newFormulas.emplace_back(oldFormula.substitute(substitution)); } - // Now we can substitute the constants in all expressions appearing in the program. std::vector newBooleanVariables; newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables()); for (auto const& booleanVariable : this->getGlobalBooleanVariables()) { - newBooleanVariables.emplace_back(booleanVariable.substitute(constantSubstitution)); + newBooleanVariables.emplace_back(booleanVariable.substitute(substitution)); } std::vector newIntegerVariables; newBooleanVariables.reserve(this->getNumberOfGlobalIntegerVariables()); for (auto const& integerVariable : this->getGlobalIntegerVariables()) { - newIntegerVariables.emplace_back(integerVariable.substitute(constantSubstitution)); - } - - std::vector newFormulas; - newFormulas.reserve(this->getNumberOfFormulas()); - for (auto const& formula : this->getFormulas()) { - newFormulas.emplace_back(formula.substitute(constantSubstitution)); + newIntegerVariables.emplace_back(integerVariable.substitute(substitution)); } std::vector newModules; newModules.reserve(this->getNumberOfModules()); for (auto const& module : this->getModules()) { - newModules.emplace_back(module.substitute(constantSubstitution)); + if (module.isRenamedFromModule()) { + // The renaming needs to be applied to the substitution as well. + auto renamedSubstitution = getSubstitutionForRenamedModule(module, substitution); + newModules.emplace_back(module.substitute(renamedSubstitution)); + } else { + newModules.emplace_back(module.substitute(substitution)); + } } std::vector newRewardModels; newRewardModels.reserve(this->getNumberOfRewardModels()); for (auto const& rewardModel : this->getRewardModels()) { - newRewardModels.emplace_back(rewardModel.substitute(constantSubstitution)); + newRewardModels.emplace_back(rewardModel.substitute(substitution)); } boost::optional newInitialConstruct; if (this->hasInitialConstruct()) { - newInitialConstruct = this->getInitialConstruct().substitute(constantSubstitution); + newInitialConstruct = this->getInitialConstruct().substitute(substitution); } std::vector