Browse Source

Merge remote-tracking branch 'origin/master' into reward-bounded-multi-objective

main
TimQu 8 years ago
parent
commit
3beaf6cd64
  1. 7
      CHANGELOG.md
  2. 4
      CMakeLists.txt
  3. 212
      resources/3rdparty/CMakeLists.txt
  4. 3
      resources/3rdparty/cudd-3.0.0/cudd/cudd.h
  5. 16
      resources/3rdparty/cudd-3.0.0/cudd/cuddAddAbs.c
  6. 4
      resources/3rdparty/cudd-3.0.0/cudd/cuddAddApply.c
  7. 9
      resources/3rdparty/cudd-3.0.0/cudd/cuddBddAbs.c
  8. 60
      resources/3rdparty/cudd-3.0.0/cudd/cuddExport.c
  9. 9
      resources/3rdparty/include_cudd.cmake
  10. 47
      resources/3rdparty/sparsepp/.gitignore
  11. 14
      resources/3rdparty/sparsepp/.travis.yml
  12. 16
      resources/3rdparty/sparsepp/CHANGELOG.md
  13. 0
      resources/3rdparty/sparsepp/LICENSE
  14. 41
      resources/3rdparty/sparsepp/README.md
  15. 0
      resources/3rdparty/sparsepp/bench.md
  16. 0
      resources/3rdparty/sparsepp/docs/.gitignore
  17. 128
      resources/3rdparty/sparsepp/examples/emplace.cc
  18. 47
      resources/3rdparty/sparsepp/examples/hash_std.cc
  19. 18
      resources/3rdparty/sparsepp/examples/makefile
  20. 82
      resources/3rdparty/sparsepp/examples/serialize_file.cc
  21. 97
      resources/3rdparty/sparsepp/examples/serialize_large.cc
  22. 64
      resources/3rdparty/sparsepp/examples/serialize_stream.cc
  23. 172
      resources/3rdparty/sparsepp/examples/vsprojects/serialize_stream.vcxproj
  24. 13
      resources/3rdparty/sparsepp/examples/vsprojects/serialize_stream.vcxproj.filters
  25. 28
      resources/3rdparty/sparsepp/examples/vsprojects/spp_examples.sln
  26. 17
      resources/3rdparty/sparsepp/makefile
  27. 2483
      resources/3rdparty/sparsepp/sparsepp/spp.h
  28. 781
      resources/3rdparty/sparsepp/sparsepp/spp_config.h
  29. 4023
      resources/3rdparty/sparsepp/sparsepp/spp_dlalloc.h
  30. 121
      resources/3rdparty/sparsepp/sparsepp/spp_memory.h
  31. 76
      resources/3rdparty/sparsepp/sparsepp/spp_smartptr.h
  32. 16
      resources/3rdparty/sparsepp/sparsepp/spp_stdint.h
  33. 58
      resources/3rdparty/sparsepp/sparsepp/spp_timer.h
  34. 122
      resources/3rdparty/sparsepp/sparsepp/spp_traits.h
  35. 215
      resources/3rdparty/sparsepp/sparsepp/spp_utils.h
  36. 41
      resources/3rdparty/sparsepp/spp.natvis
  37. 27
      resources/3rdparty/sparsepp/tests/makefile
  38. 162
      resources/3rdparty/sparsepp/tests/perftest1.cc
  39. 189
      resources/3rdparty/sparsepp/tests/spp_alloc_test.cc
  40. 284
      resources/3rdparty/sparsepp/tests/spp_bitset_test.cc
  41. 86
      resources/3rdparty/sparsepp/tests/spp_test.cc
  42. 38
      resources/3rdparty/sparsepp/tests/vsprojects/spp.sln
  43. 176
      resources/3rdparty/sparsepp/tests/vsprojects/spp_alloc_test.vcxproj
  44. 28
      resources/3rdparty/sparsepp/tests/vsprojects/spp_alloc_test.vcxproj.filters
  45. 175
      resources/3rdparty/sparsepp/tests/vsprojects/spp_test.vcxproj
  46. 32
      resources/3rdparty/sparsepp/tests/vsprojects/spp_test.vcxproj.filters
  47. 6
      resources/3rdparty/sylvan/.travis.yml
  48. 48
      resources/3rdparty/sylvan/CHANGELOG.md
  49. 13
      resources/3rdparty/sylvan/CMakeLists.txt
  50. 7
      resources/3rdparty/sylvan/cmake/FindGMP.cmake
  51. 268
      resources/3rdparty/sylvan/docs/index.rst
  52. 328
      resources/3rdparty/sylvan/examples/ldd2bdd.c
  53. 834
      resources/3rdparty/sylvan/examples/lddmc.c
  54. 558
      resources/3rdparty/sylvan/examples/mc.c
  55. BIN
      resources/3rdparty/sylvan/models/anderson.4.bdd
  56. BIN
      resources/3rdparty/sylvan/models/anderson.4.ldd
  57. BIN
      resources/3rdparty/sylvan/models/anderson.6.ldd
  58. BIN
      resources/3rdparty/sylvan/models/anderson.8.ldd
  59. BIN
      resources/3rdparty/sylvan/models/at.5.8-rgs.bdd
  60. BIN
      resources/3rdparty/sylvan/models/at.6.8-rgs.bdd
  61. BIN
      resources/3rdparty/sylvan/models/at.7.8-rgs.bdd
  62. BIN
      resources/3rdparty/sylvan/models/bakery.4.bdd
  63. BIN
      resources/3rdparty/sylvan/models/bakery.4.ldd
  64. BIN
      resources/3rdparty/sylvan/models/bakery.5.ldd
  65. BIN
      resources/3rdparty/sylvan/models/bakery.6.ldd
  66. BIN
      resources/3rdparty/sylvan/models/bakery.7.ldd
  67. BIN
      resources/3rdparty/sylvan/models/blocks.2.ldd
  68. BIN
      resources/3rdparty/sylvan/models/blocks.3.ldd
  69. BIN
      resources/3rdparty/sylvan/models/blocks.4.ldd
  70. BIN
      resources/3rdparty/sylvan/models/collision.4.9-rgs.bdd
  71. BIN
      resources/3rdparty/sylvan/models/collision.4.bdd
  72. BIN
      resources/3rdparty/sylvan/models/collision.4.ldd
  73. BIN
      resources/3rdparty/sylvan/models/collision.5.9-rgs.bdd
  74. BIN
      resources/3rdparty/sylvan/models/collision.5.bdd
  75. BIN
      resources/3rdparty/sylvan/models/collision.5.ldd
  76. BIN
      resources/3rdparty/sylvan/models/collision.6.bdd
  77. BIN
      resources/3rdparty/sylvan/models/collision.6.ldd
  78. BIN
      resources/3rdparty/sylvan/models/lifts.6.bdd
  79. BIN
      resources/3rdparty/sylvan/models/lifts.6.ldd
  80. BIN
      resources/3rdparty/sylvan/models/lifts.7.bdd
  81. BIN
      resources/3rdparty/sylvan/models/lifts.7.ldd
  82. BIN
      resources/3rdparty/sylvan/models/schedule_world.2.8-rgs.bdd
  83. BIN
      resources/3rdparty/sylvan/models/schedule_world.2.bdd
  84. BIN
      resources/3rdparty/sylvan/models/schedule_world.2.ldd
  85. BIN
      resources/3rdparty/sylvan/models/schedule_world.3.8-rgs.bdd
  86. BIN
      resources/3rdparty/sylvan/models/schedule_world.3.bdd
  87. BIN
      resources/3rdparty/sylvan/models/schedule_world.3.ldd
  88. 9
      resources/3rdparty/sylvan/src/CMakeLists.txt
  89. 2
      resources/3rdparty/sylvan/src/avl.h
  90. 406
      resources/3rdparty/sylvan/src/lace.c
  91. 424
      resources/3rdparty/sylvan/src/lace.h
  92. 4
      resources/3rdparty/sylvan/src/storm_wrapper.cpp
  93. 37
      resources/3rdparty/sylvan/src/sylvan.h
  94. 22
      resources/3rdparty/sylvan/src/sylvan_bdd.c
  95. 41
      resources/3rdparty/sylvan/src/sylvan_bdd.h
  96. 27
      resources/3rdparty/sylvan/src/sylvan_bdd_storm.c
  97. 8
      resources/3rdparty/sylvan/src/sylvan_bdd_storm.h
  98. 13
      resources/3rdparty/sylvan/src/sylvan_cache.c
  99. 14
      resources/3rdparty/sylvan/src/sylvan_cache.h
  100. 2
      resources/3rdparty/sylvan/src/sylvan_common.c

7
CHANGELOG.md

@ -6,6 +6,13 @@ The releases of major and minor versions contain an overview of changes since th
Version 1.1.x
-------------
Long run average computation via ValueIteration, LP based MDP model checking, parametric model checking has an own binary
### Version 1.1.1
- c++ api changes: Building model takes BuilderOptions instead of extended list of Booleans, does not depend on settings anymore.
- storm-cli-utilities now contains cli related stuff, instead of storm-lib
- storm-pars: support for welldefinedness constraints in mdps.
- symbolic (MT/BDD) bisimulation
### Version 1.1.0 (2017/8)

4
CMakeLists.txt

@ -33,7 +33,7 @@ MARK_AS_ADVANCED(STORM_FORCE_POPCNT)
option(USE_BOOST_STATIC_LIBRARIES "Sets whether the Boost libraries should be linked statically." OFF)
option(STORM_USE_INTELTBB "Sets whether the Intel TBB libraries should be used." OFF)
option(STORM_USE_GUROBI "Sets whether Gurobi should be used." OFF)
set(USE_CARL ON)
set(STORM_CARL_DIR_HINT "" CACHE STRING "A hint where the preferred CArL version can be found. If CArL cannot be found there, it is searched in the OS's default paths.")
option(STORM_FORCE_SHIPPED_CARL "Sets whether the shipped version of carl is to be used no matter whether carl is found or not." OFF)
MARK_AS_ADVANCED(STORM_FORCE_SHIPPED_CARL)
option(USE_SMTRAT "Sets whether SMT-RAT should be included." OFF)
@ -49,6 +49,8 @@ export_option(STORM_USE_CLN_EA)
option(STORM_USE_CLN_RF "Sets whether CLN instead of GMP numbers should be used for rational functions." ON)
export_option(STORM_USE_CLN_RF)
option(BUILD_SHARED_LIBS "Build the Storm library dynamically" OFF)
option(STORM_DEBUG_CUDD "Build CUDD in debug mode." OFF)
MARK_AS_ADVANCED(STORM_DEBUG_CUDD)
set(BOOST_ROOT "" CACHE STRING "A hint to the root directory of Boost (optional).")
set(GUROBI_ROOT "" CACHE STRING "A hint to the root directory of Gurobi (optional).")
set(Z3_ROOT "" CACHE STRING "A hint to the root directory of Z3 (optional).")

212
resources/3rdparty/CMakeLists.txt

@ -99,16 +99,24 @@ list(APPEND STORM_DEP_TARGETS ExprTk)
# Use the shipped version of Sparsepp
message (STATUS "Storm - Including Sparsepp.")
include_directories("${PROJECT_SOURCE_DIR}/resources/3rdparty/sparsepp")
# Add sparsepp.h to the headers that are copied to the include directory in thebuild directory.
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp/sparsepp.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/resources/3rdparty/sparsepp/sparsepp.h ${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp/sparsepp.h
DEPENDS ${PROJECT_SOURCE_DIR}/resources/3rdparty/sparsepp/sparsepp.h
)
list(APPEND STORM_RESOURCES_HEADERS "${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp/sparsepp.h")
set(SPARSEPP_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/resources/3rdparty/sparsepp/sparsepp")
file(GLOB SPARSEPP_HEADERS "${SPARSEPP_INCLUDE_DIR}/*.h")
# Add the sparsepp headers to the headers that are copied to the include directory in the build directory.
set(SPARSEPP_BINDIR_DIR ${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp)
include_directories("${SPARSEPP_BINDIR_DIR}")
foreach(HEADER ${SPARSEPP_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 ${SPARSEPP_BINDIR_DIR}/sparsepp/${HEADER_FILENAME}
COMMAND ${CMAKE_COMMAND} -E make_directory ${SPARSEPP_BINDIR_DIR}/sparsepp
COMMAND ${CMAKE_COMMAND} -E copy ${HEADER} ${SPARSEPP_BINDIR_DIR}/sparsepp/${HEADER_FILENAME}
DEPENDS ${SPARSEPP_INCLUDE_DIR}/${HEADER_FILENAME}
)
list(APPEND SPARSEPP_BINDIR_HEADERS ${SPARSEPP_BINDIR_DIR}/sparsepp/${HEADER_FILENAME})
endforeach()
#############################################################
##
@ -202,109 +210,107 @@ set(STORM_HAVE_CARL OFF)
set(CARL_MINYEAR 17)
set(CARL_MINMONTH 08)
set(CARL_MINPATCH 0)
if(USE_CARL)
if (NOT STORM_FORCE_SHIPPED_CARL)
find_package(carl QUIET)
endif()
if(carl_FOUND AND NOT STORM_FORCE_SHIPPED_CARL)
get_target_property(carlLOCATION lib_carl LOCATION)
if(${carlLOCATION} STREQUAL "carlLOCATION-NOTFOUND")
message(SEND_ERROR "Library location for carl is not found, did you build carl?")
elseif(EXISTS ${carlLOCATION})
#empty on purpose
else()
message(SEND_ERROR "File ${carlLOCATION} does not exist, did you build carl?")
endif()
if(${carl_MINORYEARVERSION} LESS ${CARL_MINYEAR})
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)
endif()
if (NOT carl_FOUND)
find_package(carl QUIET)
endif()
endif()
if(carl_FOUND AND NOT STORM_FORCE_SHIPPED_CARL)
get_target_property(carlLOCATION lib_carl LOCATION)
if(${carlLOCATION} STREQUAL "carlLOCATION-NOTFOUND")
message(SEND_ERROR "Library location for carl is not found, did you build carl?")
elseif(EXISTS ${carlLOCATION})
#empty on purpose
else()
message(SEND_ERROR "File ${carlLOCATION} does not exist, did you build carl?")
endif()
if(${carl_MINORYEARVERSION} LESS ${CARL_MINYEAR})
message(SEND_ERROR "Carl outdated, require ${CARL_MINYEAR}.${CARL_MINMONTH}.${CARL_MINPATCH}, have ${carl_VERSION}")
elseif(${carl_MINORYEARVERSION} EQUAL ${CARL_MINYEAR})
if(${carl_MINORMONTHVERSION} LESS ${CARL_MINMONTH})
message(SEND_ERROR "Carl outdated, require ${CARL_MINYEAR}.${CARL_MINMONTH}.${CARL_MINPATCH}, have ${carl_VERSION}")
elseif(${carl_MINORYEARVERSION} EQUAL ${CARL_MINYEAR})
if(${carl_MINORMONTHVERSION} LESS ${CARL_MINMONTH})
elseif(${carl_MINORMONTHVERSION} EQUAL ${CARL_MINMONTH})
if(${carl_MAINTENANCEVERSION} LESS ${CARL_MINPATCH})
message(SEND_ERROR "Carl outdated, require ${CARL_MINYEAR}.${CARL_MINMONTH}.${CARL_MINPATCH}, have ${carl_VERSION}")
elseif(${carl_MINORMONTHVERSION} EQUAL ${CARL_MINMONTH})
if(${carl_MAINTENANCEVERSION} LESS ${CARL_MINPATCH})
message(SEND_ERROR "Carl outdated, require ${CARL_MINYEAR}.${CARL_MINMONTH}.${CARL_MINPATCH}, have ${carl_VERSION}")
endif()
endif()
endif()
endif()
set(STORM_SHIPPED_CARL OFF)
set(STORM_HAVE_CARL ON)
message(STATUS "Storm - Use system version of carl.")
message(STATUS "Storm - Linking with preinstalled carl ${carl_VERSION} (include: ${carl_INCLUDE_DIR}, library ${carl_LIBRARIES}, CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}, CARL_USE_GINAC: ${CARL_USE_GINAC}).")
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
set(STORM_HAVE_GINAC ${CARL_USE_GINAC})
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)
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}"
set(STORM_SHIPPED_CARL OFF)
set(STORM_HAVE_CARL ON)
message(STATUS "Storm - Use system version of carl.")
message(STATUS "Storm - Linking with preinstalled carl ${carl_VERSION} (include: ${carl_INCLUDE_DIR}, library ${carl_LIBRARIES}, CARL_USE_CLN_NUMBERS: ${CARL_USE_CLN_NUMBERS}, CARL_USE_GINAC: ${CARL_USE_GINAC}).")
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
set(STORM_HAVE_GINAC ${CARL_USE_GINAC})
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)
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}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} --build . --target carl-config
WORKING_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download
OUTPUT_VARIABLE carlconfig_out
RESULT_VARIABLE carlconfig_result)
RESULT_VARIABLE carlconfig_result
)
if(NOT carlconfig_result)
message("${carlconfig_out}")
endif()
execute_process(
COMMAND ${CMAKE_COMMAND} --build . --target carl-config
WORKING_DIRECTORY ${STORM_3RDPARTY_BINARY_DIR}/carl_download
OUTPUT_VARIABLE carlconfig_out
RESULT_VARIABLE carlconfig_result
)
if(NOT carlconfig_result)
message("${carlconfig_out}")
endif()
message("END CARL CONFIG PROCESS")
message("${carlconfig_out}")
endif()
message("END CARL CONFIG PROCESS")
message(STATUS "Storm - Using shipped version of carl.")
ExternalProject_Add(
carl
SOURCE_DIR ${STORM_3RDPARTY_BINARY_DIR}/carl
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make lib_carl
INSTALL_COMMAND make install
LOG_BUILD ON
LOG_INSTALL ON
BUILD_BYPRODUCTS ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT}
)
include(${STORM_3RDPARTY_BINARY_DIR}/carl/carlConfig.cmake)
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
set(STORM_HAVE_GINAC ${CARL_USE_GINAC})
add_dependencies(resources carl)
set(carl_INCLUDE_DIR "${STORM_3RDPARTY_BINARY_DIR}/carl/include/")
set(carl_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT})
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 build it
install(FILES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl.${carl_VERSION}${DYNAMIC_EXT} DESTINATION lib)
endif()
message(STATUS "Storm - Using shipped version of carl.")
ExternalProject_Add(
carl
SOURCE_DIR ${STORM_3RDPARTY_BINARY_DIR}/carl
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make lib_carl
INSTALL_COMMAND make install
LOG_BUILD ON
LOG_INSTALL ON
BUILD_BYPRODUCTS ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT}
)
include(${STORM_3RDPARTY_BINARY_DIR}/carl/carlConfig.cmake)
if(STORM_USE_CLN_RF AND NOT STORM_HAVE_CLN)
message(FATAL_ERROR "Cannot use CLN numbers if carl is build without.")
endif()
if(STORM_USE_CLN_RF AND NOT STORM_HAVE_GINAC)
message(FATAL_ERROR "Cannot use CLN numbers if carl is build without ginac.")
endif()
set(STORM_HAVE_CLN ${CARL_USE_CLN_NUMBERS})
set(STORM_HAVE_GINAC ${CARL_USE_GINAC})
add_dependencies(resources carl)
set(carl_INCLUDE_DIR "${STORM_3RDPARTY_BINARY_DIR}/carl/include/")
set(carl_LIBRARIES ${STORM_3RDPARTY_BINARY_DIR}/carl/lib/libcarl${DYNAMIC_EXT})
set(STORM_HAVE_CARL ON)
#The library that needs symbols must be first, then the library that resolves the symbol.
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()
list(APPEND STORM_DEP_IMP_TARGETS lib_carl)
if(STORM_USE_CLN_EA OR STORM_USE_CLN_RF)
list(APPEND STORM_DEP_IMP_TARGETS GINAC_SHARED CLN_SHARED)
endif()
list(APPEND STORM_DEP_IMP_TARGETS GMPXX_SHARED GMP_SHARED)
if(STORM_USE_CLN_RF AND NOT STORM_HAVE_CLN)
message(FATAL_ERROR "Cannot use CLN numbers if carl is build without.")
endif()
if(STORM_USE_CLN_RF AND NOT STORM_HAVE_GINAC)
message(FATAL_ERROR "Cannot use CLN numbers if carl is build without ginac.")
endif()
# The library that needs symbols must be first, then the library that resolves the symbol.
list(APPEND STORM_DEP_IMP_TARGETS lib_carl)
if(STORM_USE_CLN_EA OR STORM_USE_CLN_RF)
list(APPEND STORM_DEP_IMP_TARGETS GINAC_SHARED CLN_SHARED)
endif()
list(APPEND STORM_DEP_IMP_TARGETS GMPXX_SHARED GMP_SHARED)
#############################################################
@ -410,12 +416,18 @@ else()
set(sylvan_dep lib_carl)
endif()
if (STORM_DEBUG_SYLVAN)
set(SYLVAN_BUILD_TYPE "Debug")
else()
set(SYLVAN_BUILD_TYPE "Release")
endif()
ExternalProject_Add(
sylvan
DOWNLOAD_COMMAND ""
PREFIX "sylvan"
SOURCE_DIR ${STORM_3RDPARTY_SOURCE_DIR}/sylvan
CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DGMP_LOCATION=${GMP_LIB_LOCATION} -DGMP_INCLUDE=${GMP_INCLUDE_DIR} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DSYLVAN_BUILD_DOCS=OFF -DSYLVAN_BUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DUSE_CARL=ON -Dcarl_INCLUDE_DIR=${carl_INCLUDE_DIR} -DSYLVAN_PORTABLE=${STORM_PORTABLE} -Dcarl_LIBRARIES=${carl_LIBRARIES} -DBUILD_SHARED_LIBS=OFF -DSYLVAN_BUILD_TESTS=OFF
CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DGMP_LOCATION=${GMP_LIB_LOCATION} -DGMP_INCLUDE=${GMP_INCLUDE_DIR} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DSYLVAN_BUILD_DOCS=OFF -DSYLVAN_BUILD_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=${SYLVAN_BUILD_TYPE} -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DUSE_CARL=ON -Dcarl_INCLUDE_DIR=${carl_INCLUDE_DIR} -DSYLVAN_PORTABLE=${STORM_PORTABLE} -Dcarl_LIBRARIES=${carl_LIBRARIES} -DBUILD_SHARED_LIBS=OFF -DSYLVAN_BUILD_TESTS=OFF
BINARY_DIR ${STORM_3RDPARTY_BINARY_DIR}/sylvan
BUILD_IN_SOURCE 0
INSTALL_COMMAND ""
@ -668,4 +680,4 @@ if(ENABLE_CUDA)
include_directories("${PROJECT_SOURCE_DIR}/cuda/kernels/")
endif()
add_custom_target(copy_resources_headers DEPENDS ${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp/sparsepp.h ${CMAKE_BINARY_DIR}/include/resources/3rdparty/sparsepp/sparsepp.h)
add_custom_target(copy_resources_headers DEPENDS ${SPARSEPP_BINDIR_HEADERS})

3
resources/3rdparty/cudd-3.0.0/cudd/cudd.h

@ -503,6 +503,9 @@ typedef void (*DD_TOHFP)(DdManager *, void *);
extern "C" {
#endif
// Make this visible to the outside.
extern DdNode * cuddUniqueInter(DdManager *unique, int index, DdNode *T, DdNode *E);
extern DdNode * Cudd_addNewVar(DdManager *dd);
extern DdNode * Cudd_addNewVarAtLevel(DdManager *dd, int level);
extern DdNode * Cudd_bddNewVar(DdManager *dd);

16
resources/3rdparty/cudd-3.0.0/cudd/cuddAddAbs.c

@ -1024,6 +1024,10 @@ cuddAddMinAbstractRepresentativeRecur(
return(res1);
}
if ((res = cuddCacheLookup2(manager, Cudd_addMinAbstractRepresentative, f, cube)) != NULL) {
return(res);
}
/* Abstract a variable that does not appear in f. */
if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
res = cuddAddMinAbstractRepresentativeRecur(manager, f, cuddT(cube));
@ -1044,10 +1048,6 @@ cuddAddMinAbstractRepresentativeRecur(
return(res1);
}
if ((res = cuddCacheLookup2(manager, Cudd_addMinAbstractRepresentative, f, cube)) != NULL) {
return(res);
}
E = cuddE(f);
T = cuddT(f);
@ -1211,6 +1211,10 @@ cuddAddMaxAbstractRepresentativeRecur(
}
if ((res = cuddCacheLookup2(manager, Cudd_addMaxAbstractRepresentative, f, cube)) != NULL) {
return(res);
}
/* Abstract a variable that does not appear in f. */
if (cuddI(manager,f->index) > cuddI(manager,cube->index)) {
res = cuddAddMaxAbstractRepresentativeRecur(manager, f, cuddT(cube));
@ -1231,10 +1235,6 @@ cuddAddMaxAbstractRepresentativeRecur(
return(res1);
}
if ((res = cuddCacheLookup2(manager, Cudd_addMaxAbstractRepresentative, f, cube)) != NULL) {
return(res);
}
E = cuddE(f);
T = cuddT(f);

4
resources/3rdparty/cudd-3.0.0/cudd/cuddAddApply.c

@ -350,7 +350,9 @@ Cudd_addMinus(
F = *f; G = *g;
if (F == G) return(DD_ZERO(dd));
if (F == DD_ZERO(dd)) return(cuddAddNegateRecur(dd,G));
// CHANGED BY CHRISTIAN DEHNERT.
// Commented out this case to avoid issues with dynamic reordering (fix suggested by Fabio Somenzi).
// if (F == DD_ZERO(dd)) return(cuddAddNegateRecur(dd,G));
if (G == DD_ZERO(dd)) return(F);
if (cuddIsConstant(F) && cuddIsConstant(G)) {
value = cuddV(F)-cuddV(G);

9
resources/3rdparty/cudd-3.0.0/cudd/cuddBddAbs.c

@ -563,6 +563,10 @@ cuddBddExistAbstractRepresentativeRecur(
}
/* From now on, cube and f are non-constant. */
/* Check the cache. */
if (F->ref != 1 && (res = cuddCacheLookup2(manager, Cudd_bddExistAbstractRepresentative, f, cube)) != NULL) {
return(res);
}
/* Abstract a variable that does not appear in f. */
if (manager->perm[F->index] > manager->perm[cube->index]) {
@ -586,11 +590,6 @@ cuddBddExistAbstractRepresentativeRecur(
return(res1);
}
/* Check the cache. */
if (F->ref != 1 && (res = cuddCacheLookup2(manager, Cudd_bddExistAbstractRepresentative, f, cube)) != NULL) {
return(res);
}
/* Compute the cofactors of f. */
T = cuddT(F); E = cuddE(F);
if (f != F) {

60
resources/3rdparty/cudd-3.0.0/cudd/cuddExport.c

@ -448,8 +448,9 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,scan)) {
retval = fprintf(fp,"\"%#" PRIxPTR "\";\n",
((mask & (ptruint) scan) / sizeof(DdNode)));
// retval = fprintf(fp,"\"%#" PRIxPTR "\";\n",
// ((mask & (ptruint) scan) / sizeof(DdNode)));
retval = fprintf(fp,"\"%p\";\n", (ptruint) scan);
if (retval == EOF) goto failure;
}
scan = scan->next;
@ -470,8 +471,9 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,scan)) {
retval = fprintf(fp,"\"%#" PRIxPTR "\";\n",
((mask & (ptruint) scan) / sizeof(DdNode)));
// retval = fprintf(fp,"\"%#" PRIxPTR "\";\n",
// ((mask & (ptruint) scan) / sizeof(DdNode)));
retval = fprintf(fp,"\"%p\";\n", Cudd_Regular(scan));
if (retval == EOF) goto failure;
}
scan = scan->next;
@ -491,11 +493,13 @@ Cudd_DumpDot(
if (retval == EOF) goto failure;
/* Account for the possible complement on the root. */
if (Cudd_IsComplement(f[i])) {
retval = fprintf(fp," -> \"%#" PRIxPTR "\" [style = dotted];\n",
((mask & (ptruint) f[i]) / sizeof(DdNode)));
// retval = fprintf(fp," -> \"%#" PRIxPTR "\" [style = dotted];\n",
// ((mask & (ptruint) f[i]) / sizeof(DdNode)));
retval = fprintf(fp," -> \"%p\" [style = dotted];\n", (ptruint)Cudd_Regular(f[i]));
} else {
retval = fprintf(fp," -> \"%#" PRIxPTR "\" [style = solid];\n",
((mask & (ptruint) f[i]) / sizeof(DdNode)));
// retval = fprintf(fp," -> \"%p#" PRIxPTR "\" [style = solid];\n",
// ((mask & (ptruint) f[i]) / sizeof(DdNode)));
retval = fprintf(fp," -> \"%p\" [style = solid];\n", (ptruint)Cudd_Regular(f[i]));
}
if (retval == EOF) goto failure;
}
@ -509,25 +513,28 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,scan)) {
retval = fprintf(fp,
"\"%#" PRIxPTR "\" -> \"%#" PRIxPTR "\";\n",
((mask & (ptruint) scan) / sizeof(DdNode)),
((mask & (ptruint) cuddT(scan)) / sizeof(DdNode)));
// retval = fprintf(fp,
// "\"%#" PRIxPTR "\" -> \"%#" PRIxPTR "\";\n",
// ((mask & (ptruint) scan) / sizeof(DdNode)),
// ((mask & (ptruint) cuddT(scan)) / sizeof(DdNode)));
retval = fprintf(fp, "\"%p\" -> \"%p\";\n", (ptruint)Cudd_Regular(scan), (ptruint)Cudd_Regular(cuddT(scan)));
if (retval == EOF) goto failure;
if (Cudd_IsComplement(cuddE(scan))) {
retval = fprintf(fp,
"\"%#" PRIxPTR "\" -> \"%#" PRIxPTR
"\" [style = dotted];\n",
((mask & (ptruint) scan) / sizeof(DdNode)),
((mask & (ptruint) cuddE(scan)) /
sizeof(DdNode)));
// retval = fprintf(fp,
// "\"%#" PRIxPTR "\" -> \"%#" PRIxPTR
// "\" [style = dotted];\n",
// ((mask & (ptruint) scan) / sizeof(DdNode)),
// ((mask & (ptruint) cuddE(scan)) /
// sizeof(DdNode)));
retval = fprintf(fp, "\"%p\" -> \"%p\" [style = dotted];\n", (ptruint)Cudd_Regular(scan), (ptruint)Cudd_Regular(cuddE(scan)));
} else {
retval = fprintf(fp,
"\"%#" PRIxPTR "\" -> \"%#" PRIxPTR
"\" [style = dashed];\n",
((mask & (ptruint) scan) / sizeof(DdNode)),
((mask & (ptruint) cuddE(scan)) /
sizeof(DdNode)));
// retval = fprintf(fp,
// "\"%#" PRIxPTR "\" -> \"%#" PRIxPTR
// "\" [style = dashed];\n",
// ((mask & (ptruint) scan) / sizeof(DdNode)),
// ((mask & (ptruint) cuddE(scan)) /
// sizeof(DdNode)));
retval = fprintf(fp, "\"%p\" -> \"%p\" [style = dashed];\n", (ptruint)Cudd_Regular(scan), (ptruint)Cudd_Regular(cuddE(scan)));
}
if (retval == EOF) goto failure;
}
@ -544,8 +551,9 @@ Cudd_DumpDot(
scan = nodelist[j];
while (scan != NULL) {
if (st_is_member(visited,scan)) {
retval = fprintf(fp,"\"%#" PRIxPTR "\" [label = \"%g\"];\n",
((mask & (ptruint) scan) / sizeof(DdNode)), cuddV(scan));
// retval = fprintf(fp,"\"%#" PRIxPTR "\" [label = \"%g\"];\n",
// ((mask & (ptruint) scan) / sizeof(DdNode)), cuddV(scan));
retval = fprintf(fp,"\"%p\" [label = \"%g\"];\n", (ptruint)Cudd_Regular(scan), cuddV(scan));
if (retval == EOF) goto failure;
}
scan = scan->next;

9
resources/3rdparty/include_cudd.cmake

@ -16,7 +16,14 @@ endif()
set(CUDD_LIB_DIR ${STORM_3RDPARTY_BINARY_DIR}/cudd-3.0.0/lib)
set(STORM_CUDD_FLAGS "CFLAGS=-O3 -w -DPIC -DHAVE_IEEE_754 -fno-common -ffast-math -fno-finite-math-only")
# create CUDD compilation flags
if (NOT STORM_DEBUG_CUDD)
set(STORM_CUDD_FLAGS "-O3")
else()
message(WARNING "Building CUDD in DEBUG mode.")
set(STORM_CUDD_FLAGS "-O0 -g")
endif()
set(STORM_CUDD_FLAGS "CFLAGS=${STORM_CUDD_FLAGS} -w -DPIC -DHAVE_IEEE_754 -fno-common -ffast-math -fno-finite-math-only")
if (NOT STORM_PORTABLE)
set(STORM_CUDD_FLAGS "${STORM_CUDD_FLAGS} -march=native")
endif()

47
resources/3rdparty/sparsepp/.gitignore

@ -0,0 +1,47 @@
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

14
resources/3rdparty/sparsepp/.travis.yml

@ -0,0 +1,14 @@
language: cpp
os:
- linux
- osx
compiler:
- clang
- gcc
dist: trusty
sudo: false
script: cd tests && make && make test

16
resources/3rdparty/sparsepp/CHANGELOG.md

@ -0,0 +1,16 @@
# 0.95
* not single header anymore (this was just too much of a hassle).
* custom allocator not quite ready yet. Checked in, but still using old allocator (easy to toggle - line 15 of spp_config.h)
# 0.90
* stable release (single header)
* known issues:
- memory usage can be excessive in Windows
sparsepp has a very simple default allocator based on the system malloc/realloc/free implementation,
and the default Windows realloc() appears to fragment the memory, causing significantly higher
memory usage than on linux. To solve this issue, I am working on a new allocator which will
remedy the problem.

0
resources/3rdparty/sparsepp/LICENSE

41
resources/3rdparty/sparsepp/README.md

@ -8,7 +8,7 @@ Sparsepp is derived from Google's excellent [sparsehash](https://github.com/spar
- **Extremely low memory usage** (typically about one byte overhead per entry).
- **Very efficient**, typically faster than your compiler's unordered map/set or Boost's.
- **C++11 support** (if supported by compiler).
- **Single header** implementation - just copy `sparsepp.h` to your project and include it.
- ~~Single header~~ not anymore
- **Tested** on Windows (vs2010-2015, g++), linux (g++, clang++) and MacOS (clang++).
We believe Sparsepp provides an unparalleled combination of performance and memory usage, and will outperform your compiler's unordered_map on both counts. Only Google's `dense_hash_map` is consistently faster, at the cost of much greater memory usage (especially when the final size of the map is not known in advance).
@ -20,7 +20,7 @@ For a detailed comparison of various hash implementations, including Sparsepp, p
```c++
#include <iostream>
#include <string>
#include <sparsepp.h>
#include <sparsepp/spp.h>
using spp::sparse_hash_map;
@ -50,9 +50,7 @@ int main()
## Installation
Since the full Sparsepp implementation is contained in a single header file `sparsepp.h`, the installation consist in copying this header file wherever it will be convenient to include in your project(s).
Optionally, a second header file `spp_utils.h` is provided, which implements only the spp::hash_combine() functionality. This is useful when we want to specify a hash function for a user-defined class in an header file, without including the full `sparsepp.h` header (this is demonstrated in [example 2](#example-2---providing-a-hash-function-for-a-user-defined-class) below).
No compilation is needed, as this is a header-only library. The installation consist in copying the sparsepp directory wherever it will be convenient to include in your project(s). Also make the path to this directory is provided to the compiler with the `-I` option.
## Warning - iterator invalidation on erase/insert
@ -62,7 +60,7 @@ Optionally, a second header file `spp_utils.h` is provided, which implements onl
## Usage
As shown in the example above, you need to include the header file: `#include <sparsepp.h>`
As shown in the example above, you need to include the header file: `#include <sparsepp/spp.h>`
This provides the implementation for the following classes:
@ -100,6 +98,16 @@ These classes provide the same interface as std::unordered_map and std::unordere
- Since items are not grouped into buckets, Bucket APIs have been adapted: `max_bucket_count` is equivalent to `max_size`, and `bucket_count` returns the sparsetable size, which is normally at least twice the number of items inserted into the hash_map.
## Memory allocator on Windows (when building with Visual Studio)
When building with the Microsoft compiler, we provide a custom allocator because the default one (from the Visual C++ runtime) fragments memory when reallocating.
This is desirable *only* when creating large sparsepp hash maps. If you create lots of small hash_maps, memory usage may increase instead of decreasing as expected. The reason is that, for each instance of a hash_map, the custom memory allocator creates a new memory space to allocate from, which is typically 4K, so it may be a big waste if just a few items are allocated.
In order to use the custom spp allocator, define the following preprocessor variable before including `<spp/spp.h>`:
`#define SPP_USE_SPP_ALLOC 1`
## Integer keys, and other hash function considerations.
1. For basic integer types, sparsepp provides a default hash function which does some mixing of the bits of the keys (see [Integer Hashing](http://burtleburtle.net/bob/hash/integer.html)). This prevents a pathological case where inserted keys are sequential (1, 2, 3, 4, ...), and the lookup on non-present keys becomes very slow.
@ -107,7 +115,7 @@ These classes provide the same interface as std::unordered_map and std::unordere
Of course, the user of sparsepp may provide its own hash function, as shown below:
```c++
#include <sparsepp.h>
#include <sparsepp/spp.h>
struct Hash64 {
size_t operator()(uint64_t k) const { return (k ^ 14695981039346656037ULL) * 1099511628211ULL; }
@ -125,7 +133,7 @@ These classes provide the same interface as std::unordered_map and std::unordere
```
2. When the user provides its own hash function, for example when inserting custom classes into a hash map, sometimes the resulting hash keys have similar low order bits and cause many collisions, decreasing the efficiency of the hash map. To address this use case, sparsepp provides an optional 'mixing' of the hash key (see [Integer Hash Function](https://gist.github.com/badboy/6267743) which can be enabled by defining the proprocessor macro: SPP_HASH_MIX.
2. When the user provides its own hash function, for example when inserting custom classes into a hash map, sometimes the resulting hash keys have similar low order bits and cause many collisions, decreasing the efficiency of the hash map. To address this use case, sparsepp provides an optional 'mixing' of the hash key (see [Integer Hash Function](https://gist.github.com/badboy/6267743) which can be enabled by defining the proprocessor macro: SPP_MIX_HASH.
## Example 2 - providing a hash function for a user-defined class
@ -135,7 +143,7 @@ In order to use a sparse_hash_set or sparse_hash_map, a hash function should be
#include <iostream>
#include <functional>
#include <string>
#include "sparsepp.h"
#include <sparsepp/spp.h>
using std::string;
@ -179,11 +187,11 @@ int main()
The `std::hash` specialization for `Person` combines the hash values for both first and last name using the convenient spp::hash_combine function, and returns the combined hash value.
spp::hash_combine is provided by the header `sparsepp.h`. However, class definitions often appear in header files, and it is desirable to limit the size of headers included in such header files, so we provide the very small header `spp_utils.h` for that purpose:
spp::hash_combine is provided by the header `sparsepp/spp.h`. However, class definitions often appear in header files, and it is desirable to limit the size of headers included in such header files, so we provide the very small header `sparsepp/spp_utils.h` for that purpose:
```c++
#include <string>
#include "spp_utils.h"
#include <sparsepp/spp_utils.h>
using std::string;
@ -231,12 +239,12 @@ This support is implemented in the following APIs:
bool unserialize(Serializer serializer, INPUT *stream);
```
The following example demontrates how a simple sparse_hash_map can be written to a file, and then read back. The serializer we use read and writes to a file using the stdio APIs, but it would be equally simple to write a serialized using the stream APIS:
The following example demonstrates how a simple sparse_hash_map can be written to a file, and then read back. The serializer we use read and writes to a file using the stdio APIs, but it would be equally simple to write a serialized using the stream APIS:
```c++
#include <cstdio>
#include "sparsepp.h"
#include <sparsepp/spp.h>
using spp::sparse_hash_map;
using namespace std;
@ -319,5 +327,12 @@ int main(int argc, char* argv[])
}
```
## Thread safety
Sparsepp follows the thread safety rules of the Standard C++ library. In Particular:
- A single sparsepp hash table is thread safe for reading from multiple threads. For example, given a hash table A, it is safe to read A from thread 1 and from thread 2 simultaneously.
- If a single hash table is being written to by one thread, then all reads and writes to that hash table on the same or other threads must be protected. For example, given a hash table A, if thread 1 is writing to A, then thread 2 must be prevented from reading from or writing to A.
- It is safe to read and write to one instance of a type even if another thread is reading or writing to a different instance of the same type. For example, given hash tables A and B of the same type, it is safe if A is being written in thread 1 and B is being read in thread 2.

0
resources/3rdparty/sparsepp/bench.md

0
resources/3rdparty/sparsepp/docs/.gitignore

128
resources/3rdparty/sparsepp/examples/emplace.cc

@ -0,0 +1,128 @@
#include <map>
#include <unordered_map>
#include <string>
#include <iostream>
#include <chrono>
#include <vector>
#include <sparsepp/spp.h>
#include <sstream>
namespace patch
{
template <typename T> std::string to_string(const T& n)
{
std::ostringstream stm;
stm << n;
return stm.str();
}
}
#if defined(SPP_NO_CXX11_RVALUE_REFERENCES)
#warning "problem: we expect spp will detect we have rvalue support"
#endif
template <typename T>
using milliseconds = std::chrono::duration<T, std::milli>;
class custom_type
{
std::string one = "one";
std::string two = "two";
std::uint32_t three = 3;
std::uint64_t four = 4;
std::uint64_t five = 5;
public:
custom_type() = default;
// Make object movable and non-copyable
custom_type(custom_type &&) = default;
custom_type& operator=(custom_type &&) = default;
// should be automatically deleted per http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014
//custom_type(custom_type const&) = delete;
//custom_type& operator=(custom_type const&) = delete;
};
void test(std::size_t iterations, std::size_t container_size)
{
std::clog << "bench: iterations: " << iterations << " / container_size: " << container_size << "\n";
{
std::size_t count = 0;
auto t1 = std::chrono::high_resolution_clock::now();
for (std::size_t i=0; i<iterations; ++i)
{
std::unordered_map<std::string,custom_type> m;
m.reserve(container_size);
for (std::size_t j=0; j<container_size; ++j)
m.emplace(patch::to_string(j),custom_type());
count += m.size();
}
auto t2 = std::chrono::high_resolution_clock::now();
auto elapsed = milliseconds<double>(t2 - t1).count();
if (count != iterations*container_size)
std::clog << " invalid count: " << count << "\n";
std::clog << " std::unordered_map: " << std::fixed << int(elapsed) << " ms\n";
}
{
std::size_t count = 0;
auto t1 = std::chrono::high_resolution_clock::now();
for (std::size_t i=0; i<iterations; ++i)
{
std::map<std::string,custom_type> m;
for (std::size_t j=0; j<container_size; ++j)
m.emplace(patch::to_string(j),custom_type());
count += m.size();
}
auto t2 = std::chrono::high_resolution_clock::now();
auto elapsed = milliseconds<double>(t2 - t1).count();
if (count != iterations*container_size)
std::clog << " invalid count: " << count << "\n";
std::clog << " std::map: " << std::fixed << int(elapsed) << " ms\n";
}
{
std::size_t count = 0;
auto t1 = std::chrono::high_resolution_clock::now();
for (std::size_t i=0; i<iterations; ++i)
{
std::vector<std::pair<std::string,custom_type>> m;
m.reserve(container_size);
for (std::size_t j=0; j<container_size; ++j)
m.emplace_back(patch::to_string(j),custom_type());
count += m.size();
}
auto t2 = std::chrono::high_resolution_clock::now();
auto elapsed = milliseconds<double>(t2 - t1).count();
if (count != iterations*container_size)
std::clog << " invalid count: " << count << "\n";
std::clog << " std::vector<std::pair>: " << std::fixed << int(elapsed) << " ms\n";
}
{
std::size_t count = 0;
auto t1 = std::chrono::high_resolution_clock::now();
for (std::size_t i=0; i<iterations; ++i)
{
spp::sparse_hash_map<std::string,custom_type> m;
m.reserve(container_size);
for (std::size_t j=0; j<container_size; ++j)
m.emplace(patch::to_string(j),custom_type());
count += m.size();
}
auto t2 = std::chrono::high_resolution_clock::now();
auto elapsed = milliseconds<double>(t2 - t1).count();
if (count != iterations*container_size)
std::clog << " invalid count: " << count << "\n";
std::clog << " spp::sparse_hash_map: " << std::fixed << int(elapsed) << " ms\n";
}
}
int main()
{
std::size_t iterations = 100000;
test(iterations,1);
test(iterations,10);
test(iterations,50);
}

47
resources/3rdparty/sparsepp/examples/hash_std.cc

@ -0,0 +1,47 @@
#include <iostream>
#include <string>
#include <sparsepp/spp.h>
using std::string;
struct Person
{
bool operator==(const Person &o) const
{
return _first == o._first && _last == o._last;
}
string _first;
string _last;
};
namespace std
{
// inject specialization of std::hash for Person into namespace std
// ----------------------------------------------------------------
template<>
struct hash<Person>
{
std::size_t operator()(Person const &p) const
{
std::size_t seed = 0;
spp::hash_combine(seed, p._first);
spp::hash_combine(seed, p._last);
return seed;
}
};
}
int main()
{
// As we have defined a specialization of std::hash() for Person,
// we can now create sparse_hash_set or sparse_hash_map of Persons
// ----------------------------------------------------------------
spp::sparse_hash_set<Person> persons =
{ { "John", "Galt" },
{ "Jane", "Doe" }
};
for (auto& p: persons)
std::cout << p._first << ' ' << p._last << '\n';
}

18
resources/3rdparty/sparsepp/examples/makefile

@ -0,0 +1,18 @@
CXXFLAGS = -O2 -std=c++11 -I..
CXXFLAGS += -Wall -pedantic -Wextra -D_XOPEN_SOURCE=700
SPP_DEPS_1 = spp.h spp_utils.h spp_dlalloc.h spp_traits.h spp_config.h
SPP_DEPS = $(addprefix ../sparsepp/,$(SPP_DEPS_1))
TARGETS = emplace hash_std serialize_file serialize_stream serialize_large
ifeq ($(OS),Windows_NT)
LDFLAGS = -lpsapi
endif
all: $(TARGETS)
clean:
rm -f $(TARGETS) ages.dmp data.dat vsprojects/x64/* vsprojects/x86/*
%: %.cc $(SPP_DEPS) makefile
$(CXX) $(CXXFLAGS) -DNDEBUG $< -o $@ $(LDFLAGS)

82
resources/3rdparty/sparsepp/examples/serialize_file.cc

@ -0,0 +1,82 @@
#include <cstdio>
#include <sparsepp/spp.h>
using spp::sparse_hash_map;
using namespace std;
class FileSerializer
{
public:
// serialize basic types to FILE
// -----------------------------
template <class T>
bool operator()(FILE *fp, const T& value)
{
return fwrite((const void *)&value, sizeof(value), 1, fp) == 1;
}
template <class T>
bool operator()(FILE *fp, T* value)
{
return fread((void *)value, sizeof(*value), 1, fp) == 1;
}
// serialize std::string to FILE
// -----------------------------
bool operator()(FILE *fp, const string& value)
{
const size_t size = value.size();
return (*this)(fp, size) && fwrite(value.c_str(), size, 1, fp) == 1;
}
bool operator()(FILE *fp, string* value)
{
size_t size;
if (!(*this)(fp, &size))
return false;
char* buf = new char[size];
if (fread(buf, size, 1, fp) != 1)
{
delete [] buf;
return false;
}
new (value) string(buf, (size_t)size);
delete[] buf;
return true;
}
// serialize std::pair<const A, B> to FILE - needed for maps
// ---------------------------------------------------------
template <class A, class B>
bool operator()(FILE *fp, const std::pair<const A, B>& value)
{
return (*this)(fp, value.first) && (*this)(fp, value.second);
}
template <class A, class B>
bool operator()(FILE *fp, std::pair<const A, B> *value)
{
return (*this)(fp, (A *)&value->first) && (*this)(fp, &value->second);
}
};
int main(int, char* [])
{
sparse_hash_map<string, int> age{ { "John", 12 }, {"Jane", 13 }, { "Fred", 8 } };
// serialize age hash_map to "ages.dmp" file
FILE *out = fopen("ages.dmp", "wb");
age.serialize(FileSerializer(), out);
fclose(out);
sparse_hash_map<string, int> age_read;
// read from "ages.dmp" file into age_read hash_map
FILE *input = fopen("ages.dmp", "rb");
age_read.unserialize(FileSerializer(), input);
fclose(input);
// print out contents of age_read to verify correct serialization
for (auto& v : age_read)
printf("age_read: %s -> %d\n", v.first.c_str(), v.second);
}

97
resources/3rdparty/sparsepp/examples/serialize_large.cc

@ -0,0 +1,97 @@
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <sparsepp/spp_timer.h>
#include <sparsepp/spp_memory.h>
#include <sparsepp/spp.h>
using spp::sparse_hash_map;
using namespace std;
class FileSerializer
{
public:
// serialize basic types to FILE
// -----------------------------
template <class T>
bool operator()(FILE *fp, const T& value)
{
return fwrite((const void *)&value, sizeof(value), 1, fp) == 1;
}
template <class T>
bool operator()(FILE *fp, T* value)
{
return fread((void *)value, sizeof(*value), 1, fp) == 1;
}
// serialize std::string to FILE
// -----------------------------
bool operator()(FILE *fp, const string& value)
{
const size_t size = value.size();
return (*this)(fp, size) && fwrite(value.c_str(), size, 1, fp) == 1;
}
bool operator()(FILE *fp, string* value)
{
size_t size;
if (!(*this)(fp, &size))
return false;
char* buf = new char[size];
if (fread(buf, size, 1, fp) != 1)
{
delete [] buf;
return false;
}
new (value) string(buf, (size_t)size);
delete[] buf;
return true;
}
// serialize std::pair<const A, B> to FILE - needed for maps
// ---------------------------------------------------------
template <class A, class B>
bool operator()(FILE *fp, const std::pair<const A, B>& value)
{
return (*this)(fp, value.first) && (*this)(fp, value.second);
}
template <class A, class B>
bool operator()(FILE *fp, std::pair<const A, B> *value)
{
return (*this)(fp, (A *)&value->first) && (*this)(fp, &value->second);
}
};
float _to_gb(uint64_t m) { return (float)((double)m / (1024 * 1024 * 1024)); }
int main(int, char* [])
{
sparse_hash_map<string, int> age;
for (size_t i=0; i<10000000; ++i)
{
char buff[20];
sprintf(buff, "%zu", i);
age.insert(std::make_pair(std::string(buff), i));
}
printf("before serialize(): mem_usage %4.1f GB\n", _to_gb(spp::GetProcessMemoryUsed()));
// serialize age hash_map to "ages.dmp" file
FILE *out = fopen("ages.dmp", "wb");
age.serialize(FileSerializer(), out);
fclose(out);
printf("before clear(): mem_usage %4.1f GB\n", _to_gb(spp::GetProcessMemoryUsed()));
age.clear();
printf("after clear(): mem_usage %4.1f GB\n", _to_gb(spp::GetProcessMemoryUsed()));
// read from "ages.dmp" file into age_read hash_map
FILE *input = fopen("ages.dmp", "rb");
age.unserialize(FileSerializer(), input);
fclose(input);
printf("after unserialize(): mem_usage %4.1f GB\n", _to_gb(spp::GetProcessMemoryUsed()));
}

64
resources/3rdparty/sparsepp/examples/serialize_stream.cc

@ -0,0 +1,64 @@
#include <iostream>
#include <algorithm>
#include <fstream>
#include <sparsepp/spp.h>
using spp::sparse_hash_map;
using namespace std;
struct StringToIntSerializer
{
bool operator()(std::ofstream* stream, const std::pair<const std::string, int>& value) const
{
size_t sizeSecond = sizeof(value.second);
size_t sizeFirst = value.first.size();
stream->write((char*)&sizeFirst, sizeof(sizeFirst));
stream->write(value.first.c_str(), sizeFirst);
stream->write((char*)&value.second, sizeSecond);
return true;
}
bool operator()(std::ifstream* istream, std::pair<const std::string, int>* value) const
{
// Read key
size_t size = 0;
istream->read((char*)&size, sizeof(size));
char * first = new char[size];
istream->read(first, size);
new (const_cast<string *>(&value->first)) string(first, size);
// Read value
istream->read((char *)&value->second, sizeof(value->second));
return true;
}
};
int main(int , char* [])
{
sparse_hash_map<string, int> users;
users["John"] = 12345;
users["Bob"] = 553;
users["Alice"] = 82200;
// Write users to file "data.dat"
// ------------------------------
std::ofstream* stream = new std::ofstream("data.dat",
std::ios::out | std::ios::trunc | std::ios::binary);
users.serialize(StringToIntSerializer(), stream);
stream->close();
delete stream;
// Read from file "data.dat" into users2
// -------------------------------------
sparse_hash_map<string, int> users2;
std::ifstream* istream = new std::ifstream("data.dat");
users2.unserialize(StringToIntSerializer(), istream);
istream->close();
delete istream;
for (sparse_hash_map<string, int>::iterator it = users2.begin(); it != users2.end(); ++it)
printf("users2: %s -> %d\n", it->first.c_str(), it->second);
}

172
resources/3rdparty/sparsepp/examples/vsprojects/serialize_stream.vcxproj

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\serialize_stream.cc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\sparsepp\spp.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{19BC4240-15ED-4C76-BC57-34BB70FE163B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<ProjectName>serialize_stream</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup>
<IntDirSharingDetected>None</IntDirSharingDetected>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)spp_alloc_test.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)spp_alloc_test.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<Profile>true</Profile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<Profile>true</Profile>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

13
resources/3rdparty/sparsepp/examples/vsprojects/serialize_stream.vcxproj.filters

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{ba5fa1b8-1783-4b3b-9a41-31d363b52841}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\sparsepp\spp.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

28
resources/3rdparty/sparsepp/examples/vsprojects/spp_examples.sln

@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "serialize_stream", "serialize_stream.vcxproj", "{19BC4240-15ED-4C76-BC57-34BB70FE163B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x64.ActiveCfg = Debug|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x64.Build.0 = Debug|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x86.ActiveCfg = Debug|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x86.Build.0 = Debug|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x64.ActiveCfg = Release|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x64.Build.0 = Release|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x86.ActiveCfg = Release|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

17
resources/3rdparty/sparsepp/makefile

@ -1,17 +0,0 @@
all: spp_test
clean:
/bin/rm spp_test
test:
./spp_test
spp_test: spp_test.cc sparsepp.h makefile
$(CXX) -O2 -std=c++0x -Wall -pedantic -Wextra -D_XOPEN_SOURCE=700 -D_CRT_SECURE_NO_WARNINGS spp_test.cc -o spp_test
spp_alloc_test: spp_alloc_test.cc spp_alloc.h spp_bitset.h sparsepp.h makefile
$(CXX) -O2 -DNDEBUG -std=c++11 spp_alloc_test.cc -o spp_alloc_test
perftest1: perftest1.cc sparsepp.h makefile
$(CXX) -O2 -DNDEBUG -std=c++11 perftest1.cc -o perftest1

2483
resources/3rdparty/sparsepp/sparsepp/spp.h
File diff suppressed because it is too large
View File

781
resources/3rdparty/sparsepp/sparsepp/spp_config.h

@ -0,0 +1,781 @@
#if !defined(spp_config_h_guard)
#define spp_config_h_guard
// --------------------------------------------------
// Sparsepp config macros
// some can be overriden on the command line
// --------------------------------------------------
#ifndef SPP_NAMESPACE
#define SPP_NAMESPACE spp
#endif
#ifndef spp_
#define spp_ SPP_NAMESPACE
#endif
#ifndef SPP_DEFAULT_ALLOCATOR
#if (defined(SPP_USE_SPP_ALLOC) && SPP_USE_SPP_ALLOC) && defined(_MSC_VER)
// -----------------------------------------------------------------------------
// When building with the Microsoft compiler, we use a custom allocator because
// the default one fragments memory when reallocating. This is desirable only
// when creating large sparsepp hash maps. If you create lots of small hash_maps,
// define the following before including spp.h:
// #define SPP_DEFAULT_ALLOCATOR spp::libc_allocator
// -----------------------------------------------------------------------------
#define SPP_DEFAULT_ALLOCATOR spp_::spp_allocator
#define SPP_INCLUDE_SPP_ALLOC
#else
#define SPP_DEFAULT_ALLOCATOR spp_::libc_allocator
#endif
#endif
#ifndef SPP_GROUP_SIZE
// must be 32 or 64
#define SPP_GROUP_SIZE 32
#endif
#ifndef SPP_ALLOC_SZ
// must be power of 2 (0 = agressive alloc, 1 = smallest memory usage, 2 = good compromise)
#define SPP_ALLOC_SZ 0
#endif
#ifndef SPP_STORE_NUM_ITEMS
// 1 uses a little bit more memory, but faster!!
#define SPP_STORE_NUM_ITEMS 1
#endif
// ---------------------------------------------------------------------------
// Compiler detection code (SPP_ proprocessor macros) derived from Boost
// libraries. Therefore Boost software licence reproduced below.
// ---------------------------------------------------------------------------
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// ---------------------------------------------------------------------------
// Boost like configuration
// ------------------------
#if defined __clang__
#if defined(i386)
#include <cpuid.h>
inline void spp_cpuid(int info[4], int InfoType) {
__cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]);
}
#endif
#define SPP_POPCNT __builtin_popcount
#define SPP_POPCNT64 __builtin_popcountll
#define SPP_HAS_CSTDINT
#ifndef __has_extension
#define __has_extension __has_feature
#endif
#if !__has_feature(cxx_exceptions) && !defined(SPP_NO_EXCEPTIONS)
#define SPP_NO_EXCEPTIONS
#endif
#if !__has_feature(cxx_rtti) && !defined(SPP_NO_RTTI)
#define SPP_NO_RTTI
#endif
#if !__has_feature(cxx_rtti) && !defined(SPP_NO_TYPEID)
#define SPP_NO_TYPEID
#endif
#if defined(__int64) && !defined(__GNUC__)
#define SPP_HAS_MS_INT64
#endif
#define SPP_HAS_NRVO
// Branch prediction hints
#if defined(__has_builtin)
#if __has_builtin(__builtin_expect)
#define SPP_LIKELY(x) __builtin_expect(x, 1)
#define SPP_UNLIKELY(x) __builtin_expect(x, 0)
#endif
#endif
// Clang supports "long long" in all compilation modes.
#define SPP_HAS_LONG_LONG
#if !__has_feature(cxx_constexpr)
#define SPP_NO_CXX11_CONSTEXPR
#endif
#if !__has_feature(cxx_decltype)
#define SPP_NO_CXX11_DECLTYPE
#endif
#if !__has_feature(cxx_decltype_incomplete_return_types)
#define SPP_NO_CXX11_DECLTYPE_N3276
#endif
#if !__has_feature(cxx_defaulted_functions)
#define SPP_NO_CXX11_DEFAULTED_FUNCTIONS
#endif
#if !__has_feature(cxx_deleted_functions)
#define SPP_NO_CXX11_DELETED_FUNCTIONS
#endif
#if !__has_feature(cxx_explicit_conversions)
#define SPP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
#endif
#if !__has_feature(cxx_default_function_template_args)
#define SPP_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
#endif
#if !__has_feature(cxx_generalized_initializers)
#define SPP_NO_CXX11_HDR_INITIALIZER_LIST
#endif
#if !__has_feature(cxx_lambdas)
#define SPP_NO_CXX11_LAMBDAS
#endif
#if !__has_feature(cxx_local_type_template_args)
#define SPP_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS
#endif
#if !__has_feature(cxx_raw_string_literals)
#define SPP_NO_CXX11_RAW_LITERALS
#endif
#if !__has_feature(cxx_reference_qualified_functions)
#define SPP_NO_CXX11_REF_QUALIFIERS
#endif
#if !__has_feature(cxx_generalized_initializers)
#define SPP_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
#endif
#if !__has_feature(cxx_rvalue_references)
#define SPP_NO_CXX11_RVALUE_REFERENCES
#endif
#if !__has_feature(cxx_static_assert)
#define SPP_NO_CXX11_STATIC_ASSERT
#endif
#if !__has_feature(cxx_alias_templates)
#define SPP_NO_CXX11_TEMPLATE_ALIASES
#endif
#if !__has_feature(cxx_variadic_templates)
#define SPP_NO_CXX11_VARIADIC_TEMPLATES
#endif
#if !__has_feature(cxx_user_literals)
#define SPP_NO_CXX11_USER_DEFINED_LITERALS
#endif
#if !__has_feature(cxx_alignas)
#define SPP_NO_CXX11_ALIGNAS
#endif
#if !__has_feature(cxx_trailing_return)
#define SPP_NO_CXX11_TRAILING_RESULT_TYPES
#endif
#if !__has_feature(cxx_inline_namespaces)
#define SPP_NO_CXX11_INLINE_NAMESPACES
#endif
#if !__has_feature(cxx_override_control)
#define SPP_NO_CXX11_FINAL
#endif
#if !(__has_feature(__cxx_binary_literals__) || __has_extension(__cxx_binary_literals__))
#define SPP_NO_CXX14_BINARY_LITERALS
#endif
#if !__has_feature(__cxx_decltype_auto__)
#define SPP_NO_CXX14_DECLTYPE_AUTO
#endif
#if !__has_feature(__cxx_init_captures__)
#define SPP_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES
#endif
#if !__has_feature(__cxx_generic_lambdas__)
#define SPP_NO_CXX14_GENERIC_LAMBDAS
#endif
#if !__has_feature(__cxx_generic_lambdas__) || !__has_feature(__cxx_relaxed_constexpr__)
#define SPP_NO_CXX14_CONSTEXPR
#endif
#if !__has_feature(__cxx_return_type_deduction__)
#define SPP_NO_CXX14_RETURN_TYPE_DEDUCTION
#endif
#if !__has_feature(__cxx_variable_templates__)
#define SPP_NO_CXX14_VARIABLE_TEMPLATES
#endif
#if __cplusplus < 201400
#define SPP_NO_CXX14_DIGIT_SEPARATORS
#endif
#if defined(__has_builtin) && __has_builtin(__builtin_unreachable)
#define SPP_UNREACHABLE_RETURN(x) __builtin_unreachable();
#endif
#define SPP_ATTRIBUTE_UNUSED __attribute__((__unused__))
#ifndef SPP_COMPILER
#define SPP_COMPILER "Clang version " __clang_version__
#endif
#define SPP_CLANG 1
#elif defined __GNUC__
#define SPP_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
// definition to expand macro then apply to pragma message
// #define VALUE_TO_STRING(x) #x
// #define VALUE(x) VALUE_TO_STRING(x)
// #define VAR_NAME_VALUE(var) #var "=" VALUE(var)
// #pragma message(VAR_NAME_VALUE(SPP_GCC_VERSION))
#if defined(i386)
#include <cpuid.h>
inline void spp_cpuid(int info[4], int InfoType) {
__cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]);
}
#endif
// __POPCNT__ defined when the compiled with popcount support
// (-mpopcnt compiler option is given for example)
#ifdef __POPCNT__
// slower unless compiled iwith -mpopcnt
#define SPP_POPCNT __builtin_popcount
#define SPP_POPCNT64 __builtin_popcountll
#endif
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#define SPP_GCC_CXX11
#endif
#if __GNUC__ == 3
#if defined (__PATHSCALE__)
#define SPP_NO_TWO_PHASE_NAME_LOOKUP
#define SPP_NO_IS_ABSTRACT
#endif
#if __GNUC_MINOR__ < 4
#define SPP_NO_IS_ABSTRACT
#endif
#define SPP_NO_CXX11_EXTERN_TEMPLATE
#endif
#if __GNUC__ < 4
//
// All problems to gcc-3.x and earlier here:
//
#define SPP_NO_TWO_PHASE_NAME_LOOKUP
#ifdef __OPEN64__
#define SPP_NO_IS_ABSTRACT
#endif
#endif
// GCC prior to 3.4 had #pragma once too but it didn't work well with filesystem links
#if SPP_GCC_VERSION >= 30400
#define SPP_HAS_PRAGMA_ONCE
#endif
#if SPP_GCC_VERSION < 40400
// Previous versions of GCC did not completely implement value-initialization:
// GCC Bug 30111, "Value-initialization of POD base class doesn't initialize
// members", reported by Jonathan Wakely in 2006,
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111 (fixed for GCC 4.4)
// GCC Bug 33916, "Default constructor fails to initialize array members",
// reported by Michael Elizabeth Chastain in 2007,
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916 (fixed for GCC 4.2.4)
// See also: http://www.boost.org/libs/utility/value_init.htm #compiler_issues
#define SPP_NO_COMPLETE_VALUE_INITIALIZATION
#endif
#if !defined(__EXCEPTIONS) && !defined(SPP_NO_EXCEPTIONS)
#define SPP_NO_EXCEPTIONS
#endif
//
// Threading support: Turn this on unconditionally here (except for
// those platforms where we can know for sure). It will get turned off again
// later if no threading API is detected.
//
#if !defined(__MINGW32__) && !defined(linux) && !defined(__linux) && !defined(__linux__)
#define SPP_HAS_THREADS
#endif
//
// gcc has "long long"
// Except on Darwin with standard compliance enabled (-pedantic)
// Apple gcc helpfully defines this macro we can query
//
#if !defined(__DARWIN_NO_LONG_LONG)
#define SPP_HAS_LONG_LONG
#endif
//
// gcc implements the named return value optimization since version 3.1
//
#define SPP_HAS_NRVO
// Branch prediction hints
#define SPP_LIKELY(x) __builtin_expect(x, 1)
#define SPP_UNLIKELY(x) __builtin_expect(x, 0)
//
// Dynamic shared object (DSO) and dynamic-link library (DLL) support
//
#if __GNUC__ >= 4
#if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(__CYGWIN__)
// All Win32 development environments, including 64-bit Windows and MinGW, define
// _WIN32 or one of its variant spellings. Note that Cygwin is a POSIX environment,
// so does not define _WIN32 or its variants.
#define SPP_HAS_DECLSPEC
#define SPP_SYMBOL_EXPORT __attribute__((__dllexport__))
#define SPP_SYMBOL_IMPORT __attribute__((__dllimport__))
#else
#define SPP_SYMBOL_EXPORT __attribute__((__visibility__("default")))
#define SPP_SYMBOL_IMPORT
#endif
#define SPP_SYMBOL_VISIBLE __attribute__((__visibility__("default")))
#else
// config/platform/win32.hpp will define SPP_SYMBOL_EXPORT, etc., unless already defined
#define SPP_SYMBOL_EXPORT
#endif
//
// RTTI and typeinfo detection is possible post gcc-4.3:
//
#if SPP_GCC_VERSION > 40300
#ifndef __GXX_RTTI
#ifndef SPP_NO_TYPEID
#define SPP_NO_TYPEID
#endif
#ifndef SPP_NO_RTTI
#define SPP_NO_RTTI
#endif
#endif
#endif
//
// Recent GCC versions have __int128 when in 64-bit mode.
//
// We disable this if the compiler is really nvcc with C++03 as it
// doesn't actually support __int128 as of CUDA_VERSION=7500
// even though it defines __SIZEOF_INT128__.
// See https://svn.boost.org/trac/boost/ticket/8048
// https://svn.boost.org/trac/boost/ticket/11852
// Only re-enable this for nvcc if you're absolutely sure
// of the circumstances under which it's supported:
//
#if defined(__CUDACC__)
#if defined(SPP_GCC_CXX11)
#define SPP_NVCC_CXX11
#else
#define SPP_NVCC_CXX03
#endif
#endif
#if defined(__SIZEOF_INT128__) && !defined(SPP_NVCC_CXX03)
#define SPP_HAS_INT128
#endif
//
// Recent GCC versions have a __float128 native type, we need to
// include a std lib header to detect this - not ideal, but we'll
// be including <cstddef> later anyway when we select the std lib.
//
// Nevertheless, as of CUDA 7.5, using __float128 with the host
// compiler in pre-C++11 mode is still not supported.
// See https://svn.boost.org/trac/boost/ticket/11852
//
#ifdef __cplusplus
#include <cstddef>
#else
#include <stddef.h>
#endif
#if defined(_GLIBCXX_USE_FLOAT128) && !defined(__STRICT_ANSI__) && !defined(SPP_NVCC_CXX03)
#define SPP_HAS_FLOAT128
#endif
// C++0x features in 4.3.n and later
//
#if (SPP_GCC_VERSION >= 40300) && defined(SPP_GCC_CXX11)
// C++0x features are only enabled when -std=c++0x or -std=gnu++0x are
// passed on the command line, which in turn defines
// __GXX_EXPERIMENTAL_CXX0X__.
#define SPP_HAS_DECLTYPE
#define SPP_HAS_RVALUE_REFS
#define SPP_HAS_STATIC_ASSERT
#define SPP_HAS_VARIADIC_TMPL
#define SPP_HAS_CSTDINT
#else
#define SPP_NO_CXX11_DECLTYPE
#define SPP_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
#define SPP_NO_CXX11_RVALUE_REFERENCES
#define SPP_NO_CXX11_STATIC_ASSERT
#endif
// C++0x features in 4.4.n and later
//
#if (SPP_GCC_VERSION < 40400) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_AUTO_DECLARATIONS
#define SPP_NO_CXX11_AUTO_MULTIDECLARATIONS
#define SPP_NO_CXX11_CHAR16_T
#define SPP_NO_CXX11_CHAR32_T
#define SPP_NO_CXX11_HDR_INITIALIZER_LIST
#define SPP_NO_CXX11_DEFAULTED_FUNCTIONS
#define SPP_NO_CXX11_DELETED_FUNCTIONS
#define SPP_NO_CXX11_TRAILING_RESULT_TYPES
#define SPP_NO_CXX11_INLINE_NAMESPACES
#define SPP_NO_CXX11_VARIADIC_TEMPLATES
#endif
#if SPP_GCC_VERSION < 40500
#define SPP_NO_SFINAE_EXPR
#endif
// GCC 4.5 forbids declaration of defaulted functions in private or protected sections
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 5) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS
#endif
// C++0x features in 4.5.0 and later
//
#if (SPP_GCC_VERSION < 40500) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
#define SPP_NO_CXX11_LAMBDAS
#define SPP_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS
#define SPP_NO_CXX11_RAW_LITERALS
#endif
// C++0x features in 4.6.n and later
//
#if (SPP_GCC_VERSION < 40600) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_CONSTEXPR
#define SPP_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
#endif
// C++0x features in 4.7.n and later
//
#if (SPP_GCC_VERSION < 40700) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_FINAL
#define SPP_NO_CXX11_TEMPLATE_ALIASES
#define SPP_NO_CXX11_USER_DEFINED_LITERALS
#define SPP_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS
#endif
// C++0x features in 4.8.n and later
//
#if (SPP_GCC_VERSION < 40800) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_ALIGNAS
#endif
// C++0x features in 4.8.1 and later
//
#if (SPP_GCC_VERSION < 40801) || !defined(SPP_GCC_CXX11)
#define SPP_NO_CXX11_DECLTYPE_N3276
#define SPP_NO_CXX11_REF_QUALIFIERS
#define SPP_NO_CXX14_BINARY_LITERALS
#endif
// C++14 features in 4.9.0 and later
//
#if (SPP_GCC_VERSION < 40900) || (__cplusplus < 201300)
#define SPP_NO_CXX14_RETURN_TYPE_DEDUCTION
#define SPP_NO_CXX14_GENERIC_LAMBDAS
#define SPP_NO_CXX14_DIGIT_SEPARATORS
#define SPP_NO_CXX14_DECLTYPE_AUTO
#if !((SPP_GCC_VERSION >= 40801) && (SPP_GCC_VERSION < 40900) && defined(SPP_GCC_CXX11))
#define SPP_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES
#endif
#endif
// C++ 14:
#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304)
#define SPP_NO_CXX14_CONSTEXPR
#endif
#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304)
#define SPP_NO_CXX14_VARIABLE_TEMPLATES
#endif
//
// Unused attribute:
#if __GNUC__ >= 4
#define SPP_ATTRIBUTE_UNUSED __attribute__((__unused__))
#endif
//
// __builtin_unreachable:
#if SPP_GCC_VERSION >= 40800
#define SPP_UNREACHABLE_RETURN(x) __builtin_unreachable();
#endif
#ifndef SPP_COMPILER
#define SPP_COMPILER "GNU C++ version " __VERSION__
#endif
// ConceptGCC compiler:
// http://www.generic-programming.org/software/ConceptGCC/
#ifdef __GXX_CONCEPTS__
#define SPP_HAS_CONCEPTS
#define SPP_COMPILER "ConceptGCC version " __VERSION__
#endif
#elif defined _MSC_VER
#include <intrin.h> // for __popcnt()
#define SPP_POPCNT_CHECK // slower when defined, but we have to check!
#define spp_cpuid(info, x) __cpuid(info, x)
#define SPP_POPCNT __popcnt
#if (SPP_GROUP_SIZE == 64 && INTPTR_MAX == INT64_MAX)
#define SPP_POPCNT64 __popcnt64
#endif
// Attempt to suppress VC6 warnings about the length of decorated names (obsolete):
#pragma warning( disable : 4503 ) // warning: decorated name length exceeded
#define SPP_HAS_PRAGMA_ONCE
#define SPP_HAS_CSTDINT
//
// versions check:
// we don't support Visual C++ prior to version 7.1:
#if _MSC_VER < 1310
#error "Antique compiler not supported"
#endif
#if _MSC_FULL_VER < 180020827
#define SPP_NO_FENV_H
#endif
#if _MSC_VER < 1400
// although a conforming signature for swprint exists in VC7.1
// it appears not to actually work:
#define SPP_NO_SWPRINTF
// Our extern template tests also fail for this compiler:
#define SPP_NO_CXX11_EXTERN_TEMPLATE
// Variadic macros do not exist for VC7.1 and lower
#define SPP_NO_CXX11_VARIADIC_MACROS
#endif
#if _MSC_VER < 1500 // 140X == VC++ 8.0
#undef SPP_HAS_CSTDINT
#define SPP_NO_MEMBER_TEMPLATE_FRIENDS
#endif
#if _MSC_VER < 1600 // 150X == VC++ 9.0
// A bug in VC9:
#define SPP_NO_ADL_BARRIER
#endif
// MSVC (including the latest checked version) has not yet completely
// implemented value-initialization, as is reported:
// "VC++ does not value-initialize members of derived classes without
// user-declared constructor", reported in 2009 by Sylvester Hesp:
// https: //connect.microsoft.com/VisualStudio/feedback/details/484295
// "Presence of copy constructor breaks member class initialization",
// reported in 2009 by Alex Vakulenko:
// https: //connect.microsoft.com/VisualStudio/feedback/details/499606
// "Value-initialization in new-expression", reported in 2005 by
// Pavel Kuznetsov (MetaCommunications Engineering):
// https: //connect.microsoft.com/VisualStudio/feedback/details/100744
// See also: http: //www.boost.org/libs/utility/value_init.htm #compiler_issues
// (Niels Dekker, LKEB, May 2010)
#define SPP_NO_COMPLETE_VALUE_INITIALIZATION
#ifndef _NATIVE_WCHAR_T_DEFINED
#define SPP_NO_INTRINSIC_WCHAR_T
#endif
//
// check for exception handling support:
#if !defined(_CPPUNWIND) && !defined(SPP_NO_EXCEPTIONS)
#define SPP_NO_EXCEPTIONS
#endif
//
// __int64 support:
//
#define SPP_HAS_MS_INT64
#if defined(_MSC_EXTENSIONS) || (_MSC_VER >= 1400)
#define SPP_HAS_LONG_LONG
#else
#define SPP_NO_LONG_LONG
#endif
#if (_MSC_VER >= 1400) && !defined(_DEBUG)
#define SPP_HAS_NRVO
#endif
#if _MSC_VER >= 1500 // 150X == VC++ 9.0
#define SPP_HAS_PRAGMA_DETECT_MISMATCH
#endif
//
// disable Win32 API's if compiler extensions are
// turned off:
//
#if !defined(_MSC_EXTENSIONS) && !defined(SPP_DISABLE_WIN32)
#define SPP_DISABLE_WIN32
#endif
#if !defined(_CPPRTTI) && !defined(SPP_NO_RTTI)
#define SPP_NO_RTTI
#endif
//
// TR1 features:
//
#if _MSC_VER >= 1700
// #define SPP_HAS_TR1_HASH // don't know if this is true yet.
// #define SPP_HAS_TR1_TYPE_TRAITS // don't know if this is true yet.
#define SPP_HAS_TR1_UNORDERED_MAP
#define SPP_HAS_TR1_UNORDERED_SET
#endif
//
// C++0x features
//
// See above for SPP_NO_LONG_LONG
// C++ features supported by VC++ 10 (aka 2010)
//
#if _MSC_VER < 1600
#define SPP_NO_CXX11_AUTO_DECLARATIONS
#define SPP_NO_CXX11_AUTO_MULTIDECLARATIONS
#define SPP_NO_CXX11_LAMBDAS
#define SPP_NO_CXX11_RVALUE_REFERENCES
#define SPP_NO_CXX11_STATIC_ASSERT
#define SPP_NO_CXX11_DECLTYPE
#endif // _MSC_VER < 1600
#if _MSC_VER >= 1600
#define SPP_HAS_STDINT_H
#endif
// C++11 features supported by VC++ 11 (aka 2012)
//
#if _MSC_VER < 1700
#define SPP_NO_CXX11_FINAL
#endif // _MSC_VER < 1700
// C++11 features supported by VC++ 12 (aka 2013).
//
#if _MSC_FULL_VER < 180020827
#define SPP_NO_CXX11_DEFAULTED_FUNCTIONS
#define SPP_NO_CXX11_DELETED_FUNCTIONS
#define SPP_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS
#define SPP_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS
#define SPP_NO_CXX11_RAW_LITERALS
#define SPP_NO_CXX11_TEMPLATE_ALIASES
#define SPP_NO_CXX11_TRAILING_RESULT_TYPES
#define SPP_NO_CXX11_VARIADIC_TEMPLATES
#define SPP_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX
#define SPP_NO_CXX11_DECLTYPE_N3276
#endif
// C++11 features supported by VC++ 14 (aka 2014) CTP1
#if (_MSC_FULL_VER < 190021730)
#define SPP_NO_CXX11_REF_QUALIFIERS
#define SPP_NO_CXX11_USER_DEFINED_LITERALS
#define SPP_NO_CXX11_ALIGNAS
#define SPP_NO_CXX11_INLINE_NAMESPACES
#define SPP_NO_CXX14_DECLTYPE_AUTO
#define SPP_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES
#define SPP_NO_CXX14_RETURN_TYPE_DEDUCTION
#define SPP_NO_CXX11_HDR_INITIALIZER_LIST
#endif
// C++11 features not supported by any versions
#define SPP_NO_CXX11_CHAR16_T
#define SPP_NO_CXX11_CHAR32_T
#define SPP_NO_CXX11_CONSTEXPR
#define SPP_NO_SFINAE_EXPR
#define SPP_NO_TWO_PHASE_NAME_LOOKUP
// C++ 14:
#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304)
#define SPP_NO_CXX14_BINARY_LITERALS
#endif
#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304)
#define SPP_NO_CXX14_CONSTEXPR
#endif
#if (__cplusplus < 201304) // There's no SD6 check for this....
#define SPP_NO_CXX14_DIGIT_SEPARATORS
#endif
#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304)
#define SPP_NO_CXX14_GENERIC_LAMBDAS
#endif
#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304)
#define SPP_NO_CXX14_VARIABLE_TEMPLATES
#endif
#endif
// from boost/config/suffix.hpp
// ----------------------------
#ifndef SPP_ATTRIBUTE_UNUSED
#define SPP_ATTRIBUTE_UNUSED
#endif
/*
Try to persuade compilers to inline.
*/
#ifndef SPP_FORCEINLINE
#if defined(__GNUC__)
#define SPP_FORCEINLINE __inline __attribute__ ((always_inline))
#elif defined(_MSC_VER)
#define SPP_FORCEINLINE __forceinline
#else
#define SPP_FORCEINLINE inline
#endif
#endif
#endif // spp_config_h_guard

4023
resources/3rdparty/sparsepp/sparsepp/spp_dlalloc.h
File diff suppressed because it is too large
View File

121
resources/3rdparty/sparsepp/sparsepp/spp_memory.h

@ -0,0 +1,121 @@
#if !defined(spp_memory_h_guard)
#define spp_memory_h_guard
#include <cstdint>
#include <cstring>
#include <cstdlib>
#if defined(_WIN32) || defined( __CYGWIN__)
#define SPP_WIN
#endif
#ifdef SPP_WIN
#include <windows.h>
#include <Psapi.h>
#undef min
#undef max
#else
#include <sys/types.h>
#include <sys/sysinfo.h>
#endif
namespace spp
{
uint64_t GetSystemMemory()
{
#ifdef SPP_WIN
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return static_cast<uint64_t>(memInfo.ullTotalPageFile);
#else
struct sysinfo memInfo;
sysinfo (&memInfo);
auto totalVirtualMem = memInfo.totalram;
totalVirtualMem += memInfo.totalswap;
totalVirtualMem *= memInfo.mem_unit;
return static_cast<uint64_t>(totalVirtualMem);
#endif
}
uint64_t GetTotalMemoryUsed()
{
#ifdef SPP_WIN
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return static_cast<uint64_t>(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile);
#else
struct sysinfo memInfo;
sysinfo(&memInfo);
auto virtualMemUsed = memInfo.totalram - memInfo.freeram;
virtualMemUsed += memInfo.totalswap - memInfo.freeswap;
virtualMemUsed *= memInfo.mem_unit;
return static_cast<uint64_t>(virtualMemUsed);
#endif
}
uint64_t GetProcessMemoryUsed()
{
#ifdef SPP_WIN
PROCESS_MEMORY_COUNTERS_EX pmc;
GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
return static_cast<uint64_t>(pmc.PrivateUsage);
#else
auto parseLine =
[](char* line)->int
{
auto i = strlen(line);
while(*line < '0' || *line > '9')
{
line++;
}
line[i-3] = '\0';
i = atoi(line);
return i;
};
auto file = fopen("/proc/self/status", "r");
auto result = -1;
char line[128];
while(fgets(line, 128, file) != nullptr)
{
if(strncmp(line, "VmSize:", 7) == 0)
{
result = parseLine(line);
break;
}
}
fclose(file);
return static_cast<uint64_t>(result) * 1024;
#endif
}
uint64_t GetPhysicalMemory()
{
#ifdef SPP_WIN
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return static_cast<uint64_t>(memInfo.ullTotalPhys);
#else
struct sysinfo memInfo;
sysinfo(&memInfo);
auto totalPhysMem = memInfo.totalram;
totalPhysMem *= memInfo.mem_unit;
return static_cast<uint64_t>(totalPhysMem);
#endif
}
}
#endif // spp_memory_h_guard

76
resources/3rdparty/sparsepp/sparsepp/spp_smartptr.h

@ -0,0 +1,76 @@
#if !defined(spp_smartptr_h_guard)
#define spp_smartptr_h_guard
/* -----------------------------------------------------------------------------------------------
* quick version of intrusive_ptr
* -----------------------------------------------------------------------------------------------
*/
#include <cassert>
#include <sparsepp/spp_config.h>
// ------------------------------------------------------------------------
class spp_rc
{
public:
spp_rc() : _cnt(0) {}
spp_rc(const spp_rc &) : _cnt(0) {}
void increment() const { ++_cnt; }
void decrement() const { assert(_cnt); if (--_cnt == 0) delete this; }
unsigned count() const { return _cnt; }
protected:
virtual ~spp_rc() {}
private:
mutable unsigned _cnt;
};
// ------------------------------------------------------------------------
template <class T>
class spp_sptr
{
public:
spp_sptr() : _p(0) {}
spp_sptr(T *p) : _p(p) { if (_p) _p->increment(); }
spp_sptr(const spp_sptr &o) : _p(o._p) { if (_p) _p->increment(); }
#ifndef SPP_NO_CXX11_RVALUE_REFERENCES
spp_sptr(spp_sptr &&o) : _p(o._p) { o._p = (T *)0; }
spp_sptr& operator=(spp_sptr &&o)
{
if (_p) _p->decrement();
_p = o._p;
o._p = (T *)0;
}
#endif
~spp_sptr() { if (_p) _p->decrement(); }
spp_sptr& operator=(const spp_sptr &o) { reset(o._p); return *this; }
T* get() const { return _p; }
void swap(spp_sptr &o) { T *tmp = _p; _p = o._p; o._p = tmp; }
void reset(const T *p = 0)
{
if (p == _p)
return;
if (_p) _p->decrement();
_p = (T *)p;
if (_p) _p->increment();
}
T* operator->() const { return const_cast<T *>(_p); }
bool operator!() const { return _p == 0; }
private:
T *_p;
};
// ------------------------------------------------------------------------
namespace std
{
template <class T>
inline void swap(spp_sptr<T> &a, spp_sptr<T> &b)
{
a.swap(b);
}
}
#endif // spp_smartptr_h_guard

16
resources/3rdparty/sparsepp/sparsepp/spp_stdint.h

@ -0,0 +1,16 @@
#if !defined(spp_stdint_h_guard)
#define spp_stdint_h_guard
#include <sparsepp/spp_config.h>
#if defined(SPP_HAS_CSTDINT) && (__cplusplus >= 201103)
#include <cstdint>
#else
#if defined(__FreeBSD__) || defined(__IBMCPP__) || defined(_AIX)
#include <inttypes.h>
#else
#include <stdint.h>
#endif
#endif
#endif // spp_stdint_h_guard

58
resources/3rdparty/sparsepp/sparsepp/spp_timer.h

@ -0,0 +1,58 @@
/**
Copyright (c) 2016 Mariano Gonzalez
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef spp_timer_h_guard
#define spp_timer_h_guard
#include <chrono>
namespace spp
{
template<typename time_unit = std::milli>
class Timer
{
public:
Timer() { reset(); }
void reset() { _start = _snap = clock::now(); }
void snap() { _snap = clock::now(); }
float get_total() const { return get_diff<float>(_start, clock::now()); }
float get_delta() const { return get_diff<float>(_snap, clock::now()); }
private:
using clock = std::chrono::high_resolution_clock;
using point = std::chrono::time_point<clock>;
template<typename T>
static T get_diff(const point& start, const point& end)
{
using duration_t = std::chrono::duration<T, time_unit>;
return std::chrono::duration_cast<duration_t>(end - start).count();
}
point _start;
point _snap;
};
}
#endif // spp_timer_h_guard

122
resources/3rdparty/sparsepp/sparsepp/spp_traits.h

@ -0,0 +1,122 @@
#if !defined(spp_traits_h_guard)
#define spp_traits_h_guard
#include <sparsepp/spp_config.h>
template<int S, int H> class HashObject; // for Google's benchmark, not in spp namespace!
namespace spp_
{
// ---------------------------------------------------------------------------
// type_traits we need
// ---------------------------------------------------------------------------
template<class T, T v>
struct integral_constant { static const T value = v; };
template <class T, T v> const T integral_constant<T, v>::value;
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
typedef integral_constant<int, 0> zero_type;
typedef integral_constant<int, 1> one_type;
typedef integral_constant<int, 2> two_type;
typedef integral_constant<int, 3> three_type;
template<typename T, typename U> struct is_same : public false_type { };
template<typename T> struct is_same<T, T> : public true_type { };
template<typename T> struct remove_const { typedef T type; };
template<typename T> struct remove_const<T const> { typedef T type; };
template<typename T> struct remove_volatile { typedef T type; };
template<typename T> struct remove_volatile<T volatile> { typedef T type; };
template<typename T> struct remove_cv
{
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
};
// ---------------- is_integral ----------------------------------------
template <class T> struct is_integral;
template <class T> struct is_integral : false_type { };
template<> struct is_integral<bool> : true_type { };
template<> struct is_integral<char> : true_type { };
template<> struct is_integral<unsigned char> : true_type { };
template<> struct is_integral<signed char> : true_type { };
template<> struct is_integral<short> : true_type { };
template<> struct is_integral<unsigned short> : true_type { };
template<> struct is_integral<int> : true_type { };
template<> struct is_integral<unsigned int> : true_type { };
template<> struct is_integral<long> : true_type { };
template<> struct is_integral<unsigned long> : true_type { };
#ifdef SPP_HAS_LONG_LONG
template<> struct is_integral<long long> : true_type { };
template<> struct is_integral<unsigned long long> : true_type { };
#endif
template <class T> struct is_integral<const T> : is_integral<T> { };
template <class T> struct is_integral<volatile T> : is_integral<T> { };
template <class T> struct is_integral<const volatile T> : is_integral<T> { };
// ---------------- is_floating_point ----------------------------------------
template <class T> struct is_floating_point;
template <class T> struct is_floating_point : false_type { };
template<> struct is_floating_point<float> : true_type { };
template<> struct is_floating_point<double> : true_type { };
template<> struct is_floating_point<long double> : true_type { };
template <class T> struct is_floating_point<const T> : is_floating_point<T> { };
template <class T> struct is_floating_point<volatile T> : is_floating_point<T> { };
template <class T> struct is_floating_point<const volatile T> : is_floating_point<T> { };
// ---------------- is_pointer ----------------------------------------
template <class T> struct is_pointer;
template <class T> struct is_pointer : false_type { };
template <class T> struct is_pointer<T*> : true_type { };
template <class T> struct is_pointer<const T> : is_pointer<T> { };
template <class T> struct is_pointer<volatile T> : is_pointer<T> { };
template <class T> struct is_pointer<const volatile T> : is_pointer<T> { };
// ---------------- is_reference ----------------------------------------
template <class T> struct is_reference;
template<typename T> struct is_reference : false_type {};
template<typename T> struct is_reference<T&> : true_type {};
// ---------------- is_relocatable ----------------------------------------
// relocatable values can be moved around in memory using memcpy and remain
// correct. Most types are relocatable, an example of a type who is not would
// be a struct which contains a pointer to a buffer inside itself - this is the
// case for std::string in gcc 5.
// ------------------------------------------------------------------------
template <class T> struct is_relocatable;
template <class T> struct is_relocatable :
integral_constant<bool, (is_integral<T>::value || is_floating_point<T>::value)>
{ };
template<int S, int H> struct is_relocatable<HashObject<S, H> > : true_type { };
template <class T> struct is_relocatable<const T> : is_relocatable<T> { };
template <class T> struct is_relocatable<volatile T> : is_relocatable<T> { };
template <class T> struct is_relocatable<const volatile T> : is_relocatable<T> { };
template <class A, int N> struct is_relocatable<A[N]> : is_relocatable<A> { };
template <class T, class U> struct is_relocatable<std::pair<T, U> > :
integral_constant<bool, (is_relocatable<T>::value && is_relocatable<U>::value)>
{ };
// A template helper used to select A or B based on a condition.
// ------------------------------------------------------------
template<bool cond, typename A, typename B>
struct if_
{
typedef A type;
};
template<typename A, typename B>
struct if_<false, A, B>
{
typedef B type;
};
} // spp_ namespace
#endif // spp_traits_h_guard

215
resources/3rdparty/sparsepp/spp_utils.h → resources/3rdparty/sparsepp/sparsepp/spp_utils.h

@ -1,7 +1,7 @@
// ----------------------------------------------------------------------
// Copyright (c) 2016, Steven Gregory Popovitch - greg7mdp@gmail.com
// All rights reserved.
//
//
// Code derived derived from Boost libraries.
// Boost software licence reproduced below.
//
@ -15,8 +15,8 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * The name of Steven Gregory Popovitch may not be used to
// endorse or promote products derived from this software without
// * The name of Steven Gregory Popovitch may not be used to
// endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@ -34,21 +34,21 @@
// ---------------------------------------------------------------------------
// Boost Software License - Version 1.0 - August 17th, 2003
//
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
@ -63,16 +63,12 @@
// ----------------------------
//
// Implements spp::spp_hash() and spp::hash_combine()
//
// The exact same code is duplicated in sparsepp.h.
//
// WARNING: Any change here has to be duplicated in sparsepp.h.
// ----------------------------------------------------------------------
#if !defined(spp_utils_h_guard_)
#define spp_utils_h_guard_
#if defined(_MSC_VER)
#if defined(_MSC_VER)
#if (_MSC_VER >= 1600 ) // vs2010 (1900 is vs2015)
#include <functional>
#define SPP_HASH_CLASS std::hash
@ -83,6 +79,18 @@
#if (_MSC_FULL_VER < 190021730)
#define SPP_NO_CXX11_NOEXCEPT
#endif
#elif defined __clang__
#if __has_feature(cxx_noexcept) // what to use here?
#include <functional>
#define SPP_HASH_CLASS std::hash
#else
#include <tr1/unordered_map>
#define SPP_HASH_CLASS std::tr1::hash
#endif
#if !__has_feature(cxx_noexcept)
#define SPP_NO_CXX11_NOEXCEPT
#endif
#elif defined(__GNUC__)
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#include <functional>
@ -96,13 +104,6 @@
#define SPP_HASH_CLASS std::tr1::hash
#define SPP_NO_CXX11_NOEXCEPT
#endif
#elif defined __clang__
#include <functional>
#define SPP_HASH_CLASS std::hash
#if !__has_feature(cxx_noexcept)
#define SPP_NO_CXX11_NOEXCEPT
#endif
#else
#include <functional>
#define SPP_HASH_CLASS std::hash
@ -122,17 +123,20 @@
#define SPP_INLINE
#ifndef SPP_NAMESPACE
#define SPP_NAMESPACE spp
#ifndef spp_
#define spp_ spp
#endif
namespace SPP_NAMESPACE
namespace spp_
{
template <class T> T spp_min(T a, T b) { return a < b ? a : b; }
template <class T> T spp_max(T a, T b) { return a >= b ? a : b; }
template <class T>
struct spp_hash
{
SPP_INLINE size_t operator()(const T &__v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(const T &__v) const SPP_NOEXCEPT
{
SPP_HASH_CLASS<T> hasher;
return hasher(__v);
@ -142,10 +146,10 @@ struct spp_hash
template <class T>
struct spp_hash<T *>
{
static size_t spp_log2 (size_t val) SPP_NOEXCEPT
static size_t spp_log2 (size_t val) SPP_NOEXCEPT
{
size_t res = 0;
while (val > 1)
while (val > 1)
{
val >>= 1;
res++;
@ -153,15 +157,16 @@ struct spp_hash<T *>
return res;
}
SPP_INLINE size_t operator()(const T *__v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(const T *__v) const SPP_NOEXCEPT
{
static const size_t shift = 3; // spp_log2(1 + sizeof(T)); // T might be incomplete!
return static_cast<size_t>((*(reinterpret_cast<const uintptr_t *>(&__v))) >> shift);
const uintptr_t i = (const uintptr_t)__v;
return static_cast<size_t>(i >> shift);
}
};
// from http://burtleburtle.net/bob/hash/integer.html
// fast and efficient for power of two table sizes where we always
// fast and efficient for power of two table sizes where we always
// consider the last bits.
// ---------------------------------------------------------------
inline size_t spp_mix_32(uint32_t a)
@ -172,7 +177,7 @@ inline size_t spp_mix_32(uint32_t a)
return static_cast<size_t>(a);
}
// Maybe we should do a more thorough scrambling as described in
// Maybe we should do a more thorough scrambling as described in
// https://gist.github.com/badboy/6267743
// -------------------------------------------------------------
inline size_t spp_mix_64(uint64_t a)
@ -180,83 +185,83 @@ inline size_t spp_mix_64(uint64_t a)
a = a ^ (a >> 4);
a = (a ^ 0xdeadbeef) + (a << 5);
a = a ^ (a >> 11);
return a;
return (size_t)a;
}
template <>
struct spp_hash<bool> : public std::unary_function<bool, size_t>
{
SPP_INLINE size_t operator()(bool __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(bool __v) const SPP_NOEXCEPT
{ return static_cast<size_t>(__v); }
};
template <>
struct spp_hash<char> : public std::unary_function<char, size_t>
{
SPP_INLINE size_t operator()(char __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(char __v) const SPP_NOEXCEPT
{ return static_cast<size_t>(__v); }
};
template <>
struct spp_hash<signed char> : public std::unary_function<signed char, size_t>
{
SPP_INLINE size_t operator()(signed char __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(signed char __v) const SPP_NOEXCEPT
{ return static_cast<size_t>(__v); }
};
template <>
struct spp_hash<unsigned char> : public std::unary_function<unsigned char, size_t>
{
SPP_INLINE size_t operator()(unsigned char __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(unsigned char __v) const SPP_NOEXCEPT
{ return static_cast<size_t>(__v); }
};
template <>
struct spp_hash<wchar_t> : public std::unary_function<wchar_t, size_t>
{
SPP_INLINE size_t operator()(wchar_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(wchar_t __v) const SPP_NOEXCEPT
{ return static_cast<size_t>(__v); }
};
template <>
struct spp_hash<int16_t> : public std::unary_function<int16_t, size_t>
{
SPP_INLINE size_t operator()(int16_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(int16_t __v) const SPP_NOEXCEPT
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
template <>
struct spp_hash<uint16_t> : public std::unary_function<uint16_t, size_t>
{
SPP_INLINE size_t operator()(uint16_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(uint16_t __v) const SPP_NOEXCEPT
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct spp_hash<int32_t> : public std::unary_function<int32_t, size_t>
{
SPP_INLINE size_t operator()(int32_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(int32_t __v) const SPP_NOEXCEPT
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct spp_hash<uint32_t> : public std::unary_function<uint32_t, size_t>
{
SPP_INLINE size_t operator()(uint32_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(uint32_t __v) const SPP_NOEXCEPT
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct spp_hash<int64_t> : public std::unary_function<int64_t, size_t>
{
SPP_INLINE size_t operator()(int64_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(int64_t __v) const SPP_NOEXCEPT
{ return spp_mix_64(static_cast<uint64_t>(__v)); }
};
template <>
struct spp_hash<uint64_t> : public std::unary_function<uint64_t, size_t>
{
SPP_INLINE size_t operator()(uint64_t __v) const SPP_NOEXCEPT
SPP_INLINE size_t operator()(uint64_t __v) const SPP_NOEXCEPT
{ return spp_mix_64(static_cast<uint64_t>(__v)); }
};
@ -306,12 +311,136 @@ template <class T> struct Combiner<T, 8>
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
spp::spp_hash<T> hasher;
spp_::spp_hash<T> hasher;
Combiner<std::size_t, sizeof(std::size_t)> combiner;
combiner(seed, hasher(v));
}
static inline uint32_t s_spp_popcount_default(uint32_t i) SPP_NOEXCEPT
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
static inline uint32_t s_spp_popcount_default(uint64_t x) SPP_NOEXCEPT
{
const uint64_t m1 = uint64_t(0x5555555555555555); // binary: 0101...
const uint64_t m2 = uint64_t(0x3333333333333333); // binary: 00110011..
const uint64_t m4 = uint64_t(0x0f0f0f0f0f0f0f0f); // binary: 4 zeros, 4 ones ...
const uint64_t h01 = uint64_t(0x0101010101010101); // the sum of 256 to the power of 0,1,2,3...
x -= (x >> 1) & m1; // put count of each 2 bits into those 2 bits
x = (x & m2) + ((x >> 2) & m2); // put count of each 4 bits into those 4 bits
x = (x + (x >> 4)) & m4; // put count of each 8 bits into those 8 bits
return (x * h01)>>56; // returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24)+...
}
#ifdef __APPLE__
static inline uint32_t count_trailing_zeroes(size_t v) SPP_NOEXCEPT
{
size_t x = (v & -v) - 1;
// sadly sizeof() required to build on macos
return sizeof(size_t) == 8 ? s_spp_popcount_default((uint64_t)x) : s_spp_popcount_default((uint32_t)x);
}
static inline uint32_t s_popcount(size_t v) SPP_NOEXCEPT
{
// sadly sizeof() required to build on macos
return sizeof(size_t) == 8 ? s_spp_popcount_default((uint64_t)v) : s_spp_popcount_default((uint32_t)v);
}
#else
static inline uint32_t count_trailing_zeroes(size_t v) SPP_NOEXCEPT
{
return s_spp_popcount_default((v & -(intptr_t)v) - 1);
}
static inline uint32_t s_popcount(size_t v) SPP_NOEXCEPT
{
return s_spp_popcount_default(v);
}
#endif
// -----------------------------------------------------------
// -----------------------------------------------------------
template<class T>
class libc_allocator
{
public:
typedef T value_type;
typedef T* pointer;
typedef ptrdiff_t difference_type;
typedef const T* const_pointer;
typedef size_t size_type;
libc_allocator() {}
libc_allocator(const libc_allocator &) {}
libc_allocator& operator=(const libc_allocator &) { return *this; }
#ifndef SPP_NO_CXX11_RVALUE_REFERENCES
libc_allocator(libc_allocator &&) {}
libc_allocator& operator=(libc_allocator &&) { return *this; }
#endif
pointer allocate(size_t n, const_pointer /* unused */= 0)
{
return static_cast<pointer>(malloc(n * sizeof(T)));
}
void deallocate(pointer p, size_t /* unused */)
{
free(p);
}
pointer reallocate(pointer p, size_t new_size)
{
return static_cast<pointer>(realloc(p, new_size * sizeof(T)));
}
// extra API to match spp_allocator interface
pointer reallocate(pointer p, size_t /* old_size */, size_t new_size)
{
return static_cast<pointer>(realloc(p, new_size * sizeof(T)));
}
size_type max_size() const
{
return static_cast<size_type>(-1) / sizeof(value_type);
}
void construct(pointer p, const value_type& val)
{
new(p) value_type(val);
}
void destroy(pointer p) { p->~value_type(); }
template<class U>
struct rebind
{
typedef spp_::libc_allocator<U> other;
};
};
// forward declaration
// -------------------
template<class T>
class spp_allocator;
}
template<class T>
inline bool operator==(const spp_::libc_allocator<T> &, const spp_::libc_allocator<T> &)
{
return true;
}
template<class T>
inline bool operator!=(const spp_::libc_allocator<T> &, const spp_::libc_allocator<T> &)
{
return false;
}
#endif // spp_utils_h_guard_

41
resources/3rdparty/sparsepp/spp.natvis

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- VC 2015 -->
<Type Name="spp::sparse_hash_set&lt;*,*,*,*&gt;">
<AlternativeType Name="spp::sparse_hash_map&lt;*,*,*,*,*&gt;" />
<DisplayString>{{size = {rep.table._num_buckets}}}</DisplayString>
<Expand>
<CustomListItems MaxItemsPerView="1000" ExcludeView="Test">
<Variable Name="grp" InitialValue="rep.table._first_group" />
<Variable Name="last_grp" InitialValue="rep.table._last_group" />
<Variable Name="item_ptr" InitialValue="rep.table._first_group-&gt;_group" />
<Variable Name="cnt" InitialValue="-1" />
<Size>rep.table._num_buckets</Size>
<Loop>
<Break Condition="grp == last_grp" />
<Exec>item_ptr = grp-&gt;_group</Exec>
<Exec>cnt = grp-&gt;_num_buckets</Exec>
<Loop>
<Break Condition="cnt == 0" />
<Item>item_ptr,na</Item>
<Exec>item_ptr++</Exec>
<Exec>cnt--</Exec>
</Loop>
<Exec>++grp</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
<Type Name="spp::Two_d_iterator&lt;*,*,*,*&gt;">
<DisplayString Condition="row_current==0">end()</DisplayString>
<DisplayString Condition="row_current->_group == -1">end()</DisplayString>
<DisplayString>{*col_current}</DisplayString>
<Expand>
<ExpandedItem Condition="row_current->_group != -1">*col_current</ExpandedItem>
</Expand>
</Type>
</AutoVisualizer>

27
resources/3rdparty/sparsepp/tests/makefile

@ -0,0 +1,27 @@
CXXFLAGS = -O2 -std=c++11 -I..
CXXFLAGS += -Wall -pedantic -Wextra -D_XOPEN_SOURCE=700
SPP_DEPS_1 = spp.h spp_utils.h spp_dlalloc.h spp_traits.h spp_config.h
SPP_DEPS = $(addprefix ../sparsepp/,$(SPP_DEPS_1))
TARGETS = spp_test spp_alloc_test spp_bitset_test perftest1 bench
ifeq ($(OS),Windows_NT)
LDFLAGS = -lpsapi
endif
def: spp_test
all: $(TARGETS)
clean:
rm -rf $(TARGETS) vsprojects/x64/* vsprojects/x86/*
test:
./spp_test
spp_test: spp_test.cc $(SPP_DEPS) makefile
$(CXX) $(CXXFLAGS) -D_CRT_SECURE_NO_WARNINGS spp_test.cc -o spp_test
%: %.cc $(SPP_DEPS) makefile
$(CXX) $(CXXFLAGS) -DNDEBUG $< -o $@ $(LDFLAGS)

162
resources/3rdparty/sparsepp/tests/perftest1.cc

@ -0,0 +1,162 @@
// compile on linux with: g++ -std=c++11 -O2 perftest1.cc -o perftest1
// -----------------------------------------------------------------------
#include <fstream>
#include <iostream>
#include <ctime>
#include <cstdio>
#include <climits>
#include <functional>
#include <vector>
#include <utility>
#include <sparsepp/spp_timer.h>
#define SPP 1
#define DENSE 0
#define SPARSE 0
#define STD 0
#if SPP
#include <sparsepp/spp.h>
#elif DENSE
#include <google/dense_hash_map>
#elif SPARSE
#include <google/sparse_hash_map>
#elif STD
#include <unordered_map>
#endif
using std::make_pair;
template <class T>
void test(T &s, int count)
{
spp::Timer<std::milli> timer;
timer.snap();
srand(0);
for (int i = 0; i < count; ++i)
s.insert(make_pair(rand(), i));
printf("%d random inserts in %5.2f seconds\n", count, timer.get_delta() / 1000);
timer.snap();
srand(0);
for (int i = 0; i < count; ++i)
s.find(rand());
printf("%d random finds in %5.2f seconds\n", count, timer.get_delta() / 1000);
timer.snap();
srand(1);
for (int i = 0; i < count; ++i)
s.find(rand());
printf("%d random not-finds in %5.2f seconds\n", count, timer.get_delta() / 1000);
s.clear();
timer.snap();
srand(0);
for (int i = 0; i < count; ++i)
s.insert(make_pair(i, i));
printf("%d sequential inserts in %5.2f seconds\n", count, timer.get_delta() / 1000);
timer.snap();
srand(0);
for (int i = 0; i < count; ++i)
s.find(i);
printf("%d sequential finds in %5.2f seconds\n", count, timer.get_delta() / 1000);
timer.snap();
srand(1);
for (int i = 0; i < count; ++i)
{
int x = rand();
s.find(x);
}
printf("%d random not-finds in %5.2f seconds\n", count, timer.get_delta() / 1000);
s.clear();
timer.snap();
srand(0);
for (int i = 0; i < count; ++i)
s.insert(make_pair(-i, -i));
printf("%d neg sequential inserts in %5.2f seconds\n", count, timer.get_delta() / 1000);
timer.snap();
srand(0);
for (int i = 0; i < count; ++i)
s.find(-i);
printf("%d neg sequential finds in %5.2f seconds\n", count, timer.get_delta() / 1000);
timer.snap();
srand(1);
for (int i = 0; i < count; ++i)
s.find(rand());
printf("%d random not-finds in %5.2f seconds\n", count, timer.get_delta() / 1000);
s.clear();
}
struct Hasher64 {
size_t operator()(uint64_t k) const { return (k ^ 14695981039346656037ULL) * 1099511628211ULL; }
};
struct Hasher32 {
size_t operator()(uint32_t k) const { return (k ^ 2166136261U) * 16777619UL; }
};
struct Hasheri32 {
size_t operator()(int k) const
{
return (k ^ 2166136261U) * 16777619UL;
}
};
struct Hasher_32 {
size_t operator()(int k) const
{
uint32_t a = (uint32_t)k;
#if 0
a = (a ^ 61) ^ (a >> 16);
a = a + (a << 3);
a = a ^ (a >> 4);
a = a * 0x27d4eb2d;
a = a ^ (a >> 15);
return a;
#else
a = a ^ (a >> 4);
a = (a ^ 0xdeadbeef) + (a << 5);
a = a ^ (a >> 11);
return a;
#endif
}
};
int main()
{
#if SPP
spp::sparse_hash_map<int, int /*, Hasheri32 */> s;
printf ("Testing spp::sparse_hash_map\n");
#elif DENSE
google::dense_hash_map<int, int/* , Hasher_32 */> s;
s.set_empty_key(-INT_MAX);
s.set_deleted_key(-(INT_MAX - 1));
printf ("Testing google::dense_hash_map\n");
#elif SPARSE
google::sparse_hash_map<int, int/* , Hasher_32 */> s;
s.set_deleted_key(-INT_MAX);
printf ("Testing google::sparse_hash_map\n");
#elif STD
std::unordered_map<int, int/* , Hasher_32 */> s;
printf ("Testing std::unordered_map\n");
#endif
printf ("------------------------------\n");
test(s, 50000000);
return 0;
}

189
resources/3rdparty/sparsepp/tests/spp_alloc_test.cc

@ -0,0 +1,189 @@
#include <memory>
#include <cassert>
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <vector>
// enable debugging code in spp_bitset.h
#define SPP_TEST 1
#include <sparsepp/spp_timer.h>
#include <sparsepp/spp_memory.h>
#include <sparsepp/spp_dlalloc.h>
using namespace std;
static float _to_mb(uint64_t m) { return (float)((double)m / (1024 * 1024)); }
// -----------------------------------------------------------
// -----------------------------------------------------------
template <class T, class A>
class TestAlloc
{
public:
TestAlloc(size_t num_alloc = 8000000) :
_num_alloc(num_alloc)
{
_allocated.resize(_num_alloc, nullptr);
_sizes.resize(_num_alloc, 0);
_start_mem_usage = spp::GetProcessMemoryUsed();
}
void run()
{
srand(43); // always same sequence of random numbers
for (size_t i=0; i<_num_alloc; ++i)
_sizes[i] = std::max(2, (rand() % 5) * 2);
spp::Timer<std::milli> timer;
// allocate small buffers
// ----------------------
for (size_t i=0; i<_num_alloc; ++i)
{
_allocated[i] = _allocator.allocate(_sizes[i]);
_set_buf(_allocated[i], _sizes[i]);
}
#if 1
// and grow the buffers to a max size of 24 each
// ---------------------------------------------
for (uint32_t j=4; j<26; j += 2)
{
for (size_t i=0; i<_num_alloc; ++i)
{
// if ( _sizes[i] < j) // windows allocator friendly!
if ((rand() % 4) != 3 && _sizes[i] < j) // really messes up windows allocator
{
_allocated[i] = _allocator.reallocate(_allocated[i], j);
_check_buf(_allocated[i], _sizes[i]);
_set_buf(_allocated[i], j);
_sizes[i] = j;
}
}
}
#endif
#if 0
// test erase (shrinking the buffers)
// ---------------------------------------------
for (uint32_t j=28; j>4; j -= 2)
{
for (size_t i=0; i<_num_alloc; ++i)
{
// if ( _sizes[i] < j) // windows allocator friendly!
if ((rand() % 4) != 3 && _sizes[i] > j) // really messes up windows allocator
{
_allocated[i] = _allocator.reallocate(_allocated[i], j);
_check_buf1(_allocated[i], _sizes[i]);
_set_buf(_allocated[i], j);
_sizes[i] = j;
}
}
}
#endif
#if 0
// and grow the buffers back to a max size of 24 each
// --------------------------------------------------
for (uint32_t j=4; j<26; j += 2)
{
for (size_t i=0; i<_num_alloc; ++i)
{
// if ( _sizes[i] < j) // windows allocator friendly!
if ((rand() % 4) != 3 && _sizes[i] < j) // really messes up windows allocator
{
_allocated[i] = _allocator.reallocate(_allocated[i], j);
_check_buf(_allocated[i], _sizes[i]);
_set_buf(_allocated[i], j);
_sizes[i] = j;
}
}
}
#endif
size_t total_units = 0;
for (size_t i=0; i<_num_alloc; ++i)
total_units += _sizes[i];
uint64_t mem_usage = spp::GetProcessMemoryUsed();
uint64_t alloc_mem_usage = mem_usage - _start_mem_usage;
uint64_t expected_mem_usage = total_units * sizeof(T);
// finally free the memory
// -----------------------
for (size_t i=0; i<_num_alloc; ++i)
{
_check_buf(_allocated[i], _sizes[i]);
_allocator.deallocate(_allocated[i], _sizes[i]);
}
uint64_t mem_usage_end = spp::GetProcessMemoryUsed();
printf("allocated %zd entities of size %zd\n", total_units, sizeof(T));
printf("done in %3.2f seconds, mem_usage %4.1f/%4.1f/%4.1f MB\n",
timer.get_total() / 1000, _to_mb(_start_mem_usage), _to_mb(mem_usage), _to_mb(mem_usage_end));
printf("expected mem usage: %4.1f\n", _to_mb(expected_mem_usage));
if (expected_mem_usage <= alloc_mem_usage)
printf("overhead: %4.1f%%\n",
(float)((double)(alloc_mem_usage - expected_mem_usage) / expected_mem_usage) * 100);
else
printf("bug: alloc_mem_usage <= expected_mem_usage\n");
std::vector<T *>().swap(_allocated);
std::vector<uint32_t>().swap(_sizes);
printf("\nmem usage after freeing vectors: %4.1f\n", _to_mb(spp::GetProcessMemoryUsed()));
}
private:
void _set_buf(T *buff, uint32_t sz) { *buff = (T)sz; buff[sz - 1] = (T)sz; }
void _check_buf1(T *buff, uint32_t sz)
{
assert(*buff == (T)sz);
(void)(buff + sz); // silence warning
}
void _check_buf(T *buff, uint32_t sz)
{
assert(*buff == (T)sz && buff[sz - 1] == (T)sz);
(void)(buff + sz); // silence warning
}
size_t _num_alloc;
uint64_t _start_mem_usage;
std::vector<T *> _allocated;
std::vector<uint32_t> _sizes;
A _allocator;
};
// -----------------------------------------------------------
// -----------------------------------------------------------
template <class X, class A>
void run_test(const char *alloc_name)
{
printf("\n---------------- testing %s\n\n", alloc_name);
printf("\nmem usage before the alloc test: %4.1f\n",
_to_mb(spp::GetProcessMemoryUsed()));
{
TestAlloc< X, A > test_alloc;
test_alloc.run();
}
printf("mem usage after the alloc test: %4.1f\n",
_to_mb(spp::GetProcessMemoryUsed()));
printf("\n\n");
}
// -----------------------------------------------------------
// -----------------------------------------------------------
int main()
{
typedef uint64_t X;
run_test<X, spp::libc_allocator<X>>("libc_allocator");
run_test<X, spp::spp_allocator<X>>("spp_allocator");
}

284
resources/3rdparty/sparsepp/tests/spp_bitset_test.cc

@ -0,0 +1,284 @@
#include <memory>
#include <cassert>
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <vector>
// enable debugging code in spp_bitset.h
#define SPP_TEST 1
#include <sparsepp/spp_timer.h>
#include <sparsepp/spp_memory.h>
#include <sparsepp/spp_bitset.h>
using namespace std;
// -----------------------------------------------------------
// -----------------------------------------------------------
template <size_t N>
class TestBitset
{
public:
typedef spp::spp_bitset<N> BS;
TestBitset()
{}
void test_set(size_t num_iter)
{
size_t num_errors = 0;
BS bs, bs2;
printf("testing set on spp_bitset<%zu> , num_iter=%6zu -> ", N, num_iter);
for (size_t i=0; i<num_iter; ++i)
{
bs.reset();
bs2.reset();
size_t start = rand() % N;
size_t to = start + rand() % (N - start);
bs.set(start, to);
bs2.set_naive(start, to);
bool same = bs == bs2;
if (!same)
++num_errors;
assert(same);
}
printf("num_errors = %zu\n", num_errors);
}
void test_reset(size_t num_iter)
{
size_t num_errors = 0;
BS bs, bs2;
printf("testing reset on spp_bitset<%zu>, num_iter=%6zu -> ", N, num_iter);
for (size_t i=0; i<num_iter; ++i)
{
bs.set();
bs2.set();
size_t start = rand() % N;
size_t to = start + rand() % (N - start);
bs.reset(start, to);
bs2.reset_naive(start, to);
bool same = bs == bs2;
if (!same)
++num_errors;
assert(same);
}
printf("num_errors = %zu\n", num_errors);
}
void test_all(size_t num_iter)
{
size_t num_errors = 0;
BS bs;
printf("testing all() on spp_bitset<%zu>, num_iter=%6zu -> ", N, num_iter);
for (size_t i=0; i<4 * N; ++i)
{
bs.set(rand() % N);
if (i > 2 * N)
{
for (size_t j=0; j<num_iter; ++j)
{
size_t start = rand() % N;
size_t to = start + rand() % (N - start);
bool same = bs.all(start, to) == bs.all_naive(start, to);
if (!same)
++num_errors;
assert(same);
}
size_t start = 0, start_naive = 1;
bs.all(start);
bs.all_naive(start_naive);
bool same = (start == start_naive);
if (!same)
++num_errors;
assert(same);
}
}
printf("num_errors = %zu\n", num_errors);
}
void test_any(size_t num_iter)
{
size_t num_errors = 0;
BS bs;
printf("testing any() on spp_bitset<%zu>, num_iter=%6zu -> ", N, num_iter);
for (size_t i=0; i<num_iter; ++i)
{
bs.set(rand() % N);
for (size_t j=0; j<100; ++j)
{
size_t start = rand() % N;
size_t to = start + rand() % (N - start);
bool same = bs.any(start, to) == bs.any_naive(start, to);
if (!same)
++num_errors;
assert(same);
}
}
printf("num_errors = %zu\n", num_errors);
}
void test_longest(size_t num_iter)
{
size_t num_errors = 0;
BS bs, bs2;
assert(bs.longest_zero_sequence() == N);
bs.set(0);
assert(bs.longest_zero_sequence() == N-1);
bs.set(10);
assert(bs.find_next_n(3, 8) == 11);
assert(bs.find_next_n(3, 6) == 6);
assert(bs.find_next_n(3, N-2) == 1);
assert(bs.longest_zero_sequence() == N-11);
if (N > 1000)
{
bs.set(1000);
size_t longest = bs.longest_zero_sequence();
assert(longest == 1000-11 || longest == N-1001);
if (!(longest == 1000-11 || longest == N-1001))
++num_errors;
}
spp::Timer<std::milli> timer_lz;
spp::Timer<std::milli> timer_lz_slow;
float lz_time(0), lz_time_slow(0);
printf("testing longest_zero_sequence() , num_iter=%6zu -> ", num_iter);
srand(1);
for (size_t i=0; i<num_iter; ++i)
{
bs.reset();
for (size_t j=0; j<N; ++j)
{
bs.set(rand() % N);
timer_lz.snap();
size_t lz1 = bs.longest_zero_sequence();
lz_time += timer_lz.get_delta();
timer_lz_slow.snap();
size_t lz2 = bs.longest_zero_sequence_naive();
lz_time_slow += timer_lz_slow.get_delta();
num_errors += (lz1 != lz2);
assert(!num_errors);
}
}
printf("num_errors = %zu, time=%7.1f, slow_time=%7.1f\n", num_errors, lz_time, lz_time_slow);
}
void test_longest2(size_t num_iter)
{
size_t num_errors = 0;
BS bs, bs2;
assert(bs.longest_zero_sequence() == N);
bs.set(0);
assert(bs.longest_zero_sequence() == N-1);
bs.set(10);
assert(bs.find_next_n(3, 8) == 11);
assert(bs.find_next_n(3, 6) == 6);
assert(bs.find_next_n(3, N-2) == 1);
assert(bs.longest_zero_sequence() == N-11);
if (N > 1000)
{
bs.set(1000);
size_t longest = bs.longest_zero_sequence();
assert(longest == 1000-11 || longest == N-1001);
if (!(longest == 1000-11 || longest == N-1001))
++num_errors;
}
spp::Timer<std::milli> timer_lz;
spp::Timer<std::milli> timer_lz_slow;
float lz_time(0), lz_time_slow(0);
printf("testing longest_zero_sequence2() , num_iter=%6zu -> ", num_iter);
srand(1);
for (size_t i=0; i<num_iter; ++i)
{
bs.reset();
for (size_t j=0; j<N; ++j)
{
bs.set(rand() % N);
size_t start_pos1 = 0, start_pos2 = 0;
timer_lz.snap();
size_t lz1 = bs.longest_zero_sequence(64, start_pos1);
lz_time += timer_lz.get_delta();
timer_lz_slow.snap();
size_t lz2 = bs.longest_zero_sequence_naive(64, start_pos2);
lz_time_slow += timer_lz_slow.get_delta();
assert(start_pos1 == start_pos2);
num_errors += (lz1 != lz2) || (start_pos1 != start_pos2);
assert(!num_errors);
}
}
printf("num_errors = %zu, time=%7.1f, slow_time=%7.1f\n", num_errors, lz_time, lz_time_slow);
}
void test_ctz(size_t num_iter)
{
size_t num_errors = 0;
spp::Timer<std::milli> timer_ctz;
spp::Timer<std::milli> timer_ctz_slow;
float ctz_time(0), ctz_time_slow(0);
printf("testing count_trailing_zeroes() , num_iter=%6zu -> ", num_iter);
for (size_t i=0; i<num_iter; ++i)
{
size_t v = rand() ^ (rand() << 16);
timer_ctz.snap();
uint32_t ctz1 = spp::count_trailing_zeroes(v);
ctz_time += timer_ctz.get_delta();
timer_ctz_slow.snap();
size_t ctz2 = spp::count_trailing_zeroes_naive(v);
ctz_time_slow += timer_ctz_slow.get_delta();
num_errors += (ctz1 != ctz2);
assert(!num_errors);
}
printf("num_errors = %zu, time=%7.1f, slow_time=%7.1f\n", num_errors, ctz_time, ctz_time_slow);
}
void run()
{
test_ctz(10000);
test_all(10000);
test_any(1000);
test_set(1000);
test_reset(1000);
test_longest(200);
test_longest2(200);
}
};
// -----------------------------------------------------------
// -----------------------------------------------------------
int main()
{
TestBitset<1024> test_bitset_1024;
test_bitset_1024.run();
TestBitset<4096> test_bitset_4096;
test_bitset_4096.run();
//TestBitset<8192> test_bitset_8192;
//test_bitset_8192.run();
}

86
resources/3rdparty/sparsepp/spp_test.cc → resources/3rdparty/sparsepp/tests/spp_test.cc

@ -41,7 +41,7 @@
#pragma warning( disable : 4996 ) // 'fopen': This function or variable may be unsafe
#endif
#include "sparsepp.h"
#include <sparsepp/spp.h>
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // conditional expression is constant
@ -357,7 +357,6 @@ public:
void set_deleted_key(const key_type& k) { ht_.set_deleted_key(k); }
void clear_deleted_key() { ht_.clear_deleted_key(); }
key_type deleted_key() const { return ht_.deleted_key(); }
size_type erase(const key_type& key) { return ht_.erase(key); }
void erase(typename HT::iterator it) { ht_.erase(it); }
@ -432,9 +431,9 @@ protected:
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
template <class Key, class T,
class HashFcn = SPP_HASH_CLASS<Key>,
class HashFcn = SPP_HASH_CLASS<Key>,
class EqualKey = std::equal_to<Key>,
class Alloc = spp::libc_allocator_with_realloc<std::pair<const Key, T> > >
class Alloc = SPP_DEFAULT_ALLOCATOR<std::pair<const Key, T> > >
class HashtableInterface_SparseHashMap
: public BaseHashtableInterface< sparse_hash_map<Key, T, HashFcn,
EqualKey, Alloc> >
@ -518,9 +517,9 @@ void swap(HashtableInterface_SparseHashMap<K,T,H,E,A>& a,
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
template <class Value,
class HashFcn = SPP_HASH_CLASS<Value>,
class HashFcn = SPP_HASH_CLASS<Value>,
class EqualKey = std::equal_to<Value>,
class Alloc = spp::libc_allocator_with_realloc<Value> >
class Alloc = SPP_DEFAULT_ALLOCATOR<Value> >
class HashtableInterface_SparseHashSet
: public BaseHashtableInterface< sparse_hash_set<Value, HashFcn,
EqualKey, Alloc> >
@ -749,8 +748,8 @@ void EXPECT_TRUE(bool cond)
}
}
SPP_START_NAMESPACE
namespace spp_
{
namespace testing
{
@ -897,8 +896,7 @@ class Test { };
} // namespace testing
SPP_END_NAMESPACE
} // namespace spp_
namespace testing = SPP_NAMESPACE::testing;
@ -1287,7 +1285,7 @@ namespace {
#define INT_HASHTABLES \
HashtableInterface_SparseHashMap<int, int, Hasher, Hasher, \
Alloc<int> >, \
Alloc<std::pair<const int, int> > >, \
HashtableInterface_SparseHashSet<int, Hasher, Hasher, \
Alloc<int> >, \
/* This is a table where the key associated with a value is -value */ \
@ -1297,7 +1295,7 @@ namespace {
#define STRING_HASHTABLES \
HashtableInterface_SparseHashMap<string, string, Hasher, Hasher, \
Alloc<string> >, \
Alloc<std::pair<const string, string> > >, \
HashtableInterface_SparseHashSet<string, Hasher, Hasher, \
Alloc<string> >, \
/* This is a table where the key associated with a value is Cap(value) */ \
@ -1312,7 +1310,7 @@ namespace {
// ---------------------------------------------------------------------
#define CHARSTAR_HASHTABLES \
HashtableInterface_SparseHashMap<const char*, ValueType, \
Hasher, Hasher, Alloc<const char*> >, \
Hasher, Hasher, Alloc<std::pair<const char* const, ValueType> > >, \
HashtableInterface_SparseHashSet<const char*, Hasher, Hasher, \
Alloc<const char*> >, \
HashtableInterface_SparseHashtable<const char*, const char*, \
@ -1436,7 +1434,6 @@ TYPED_TEST(HashtableIntTest, Typedefs)
// different, arbitrary function that returns the type. Sometimes
// the type isn't used at all, and there's no good way to use the
// variable.
kt = this->ht_.deleted_key();
(void)vt; // value_type may not be copyable. Easiest not to try.
h = this->ht_.hash_funct();
ke = this->ht_.key_eq();
@ -1551,6 +1548,38 @@ TEST(HashtableTest, ReferenceWrapper)
}
#endif
#if !defined(SPP_NO_CXX11_RVALUE_REFERENCES)
class CNonCopyable
{
public:
CNonCopyable(CNonCopyable const &) = delete;
const CNonCopyable& operator=(CNonCopyable const &) = delete;
CNonCopyable() = default;
};
struct Probe : CNonCopyable
{
Probe() {}
Probe(Probe &&) {}
void operator=(Probe &&) {}
private:
Probe(const Probe &);
Probe& operator=(const Probe &);
};
TEST(HashtableTest, NonCopyable)
{
typedef spp::sparse_hash_map<uint64_t, Probe> THashMap;
THashMap probes;
probes.insert(THashMap::value_type(27, Probe()));
EXPECT_EQ(probes.begin()->first, 27);
}
#endif
TEST(HashtableTest, ModifyViaIterator)
{
@ -1642,7 +1671,7 @@ TYPED_TEST(HashtableIntTest, Constructors)
// placement-news we have to do below.
Hasher hasher(1); // 1 is a unique id
int alloc_count = 0;
Alloc<typename TypeParam::key_type> alloc(2, &alloc_count);
Alloc<typename TypeParam::value_type> alloc(2, &alloc_count);
TypeParam ht_noarg;
TypeParam ht_onearg(100);
@ -1793,9 +1822,6 @@ TYPED_TEST(HashtableAllTest, Swap)
this->ht_.swap(other_ht);
EXPECT_EQ(this->UniqueKey(2), this->ht_.deleted_key());
EXPECT_EQ(this->UniqueKey(1), other_ht.deleted_key());
EXPECT_EQ(1, this->ht_.hash_funct().id());
EXPECT_EQ(0, other_ht.hash_funct().id());
@ -1826,8 +1852,6 @@ TYPED_TEST(HashtableAllTest, Swap)
std::swap(this->ht_, other_ht);
#endif
EXPECT_EQ(this->UniqueKey(1), this->ht_.deleted_key());
EXPECT_EQ(this->UniqueKey(2), other_ht.deleted_key());
EXPECT_EQ(0, this->ht_.hash_funct().id());
EXPECT_EQ(1, other_ht.hash_funct().id());
EXPECT_EQ(1996u, this->ht_.size());
@ -2251,24 +2275,6 @@ TYPED_TEST(HashtableStringTest, EmptyKey)
EXPECT_EQ(kEmptyString, this->ht_.empty_key());
}
TYPED_TEST(HashtableAllTest, DeletedKey)
{
if (!this->ht_.supports_deleted_key())
return;
this->ht_.insert(this->UniqueObject(10));
this->ht_.insert(this->UniqueObject(20));
this->ht_.set_deleted_key(this->UniqueKey(1));
EXPECT_EQ(this->ht_.deleted_key(), this->UniqueKey(1));
EXPECT_EQ(2u, this->ht_.size());
this->ht_.erase(this->UniqueKey(20));
EXPECT_EQ(1u, this->ht_.size());
// Changing the deleted key is fine.
this->ht_.set_deleted_key(this->UniqueKey(2));
EXPECT_EQ(this->ht_.deleted_key(), this->UniqueKey(2));
EXPECT_EQ(1u, this->ht_.size());
}
TYPED_TEST(HashtableAllTest, Erase)
{
this->ht_.set_deleted_key(this->UniqueKey(1));
@ -2329,7 +2335,7 @@ TYPED_TEST(HashtableAllTest, Equals)
// The choice of allocator/etc doesn't matter either.
Hasher hasher(1);
Alloc<typename TypeParam::key_type> alloc(2, NULL);
Alloc<typename TypeParam::value_type> alloc(2, NULL);
TypeParam ht3(5, hasher, hasher, alloc);
EXPECT_TRUE(ht1 == ht3);
EXPECT_FALSE(ht1 != ht3);
@ -2746,7 +2752,7 @@ TEST(HashtableTest, SimpleDataTypeOptimizations)
// Only sparsehashtable optimizes moves in this way.
sparse_hash_map<int, Memmove, Hasher, Hasher> memmove;
sparse_hash_map<int, NoMemmove, Hasher, Hasher> nomemmove;
sparse_hash_map<int, Memmove, Hasher, Hasher, Alloc<int> >
sparse_hash_map<int, Memmove, Hasher, Hasher, Alloc<std::pair<const int, Memmove> > >
memmove_nonstandard_alloc;
Memmove::num_copies = 0;

38
resources/3rdparty/sparsepp/tests/vsprojects/spp.sln

@ -0,0 +1,38 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spp_test", "spp_test.vcxproj", "{9863A521-E9DB-4775-A276-CADEF726CF11}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spp_alloc_test", "spp_alloc_test.vcxproj", "{19BC4240-15ED-4C76-BC57-34BB70FE163B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9863A521-E9DB-4775-A276-CADEF726CF11}.Debug|x64.ActiveCfg = Debug|x64
{9863A521-E9DB-4775-A276-CADEF726CF11}.Debug|x64.Build.0 = Debug|x64
{9863A521-E9DB-4775-A276-CADEF726CF11}.Debug|x86.ActiveCfg = Debug|Win32
{9863A521-E9DB-4775-A276-CADEF726CF11}.Debug|x86.Build.0 = Debug|Win32
{9863A521-E9DB-4775-A276-CADEF726CF11}.Release|x64.ActiveCfg = Release|x64
{9863A521-E9DB-4775-A276-CADEF726CF11}.Release|x64.Build.0 = Release|x64
{9863A521-E9DB-4775-A276-CADEF726CF11}.Release|x86.ActiveCfg = Release|Win32
{9863A521-E9DB-4775-A276-CADEF726CF11}.Release|x86.Build.0 = Release|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x64.ActiveCfg = Debug|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x64.Build.0 = Debug|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x86.ActiveCfg = Debug|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Debug|x86.Build.0 = Debug|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x64.ActiveCfg = Release|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x64.Build.0 = Release|x64
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x86.ActiveCfg = Release|Win32
{19BC4240-15ED-4C76-BC57-34BB70FE163B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

176
resources/3rdparty/sparsepp/tests/vsprojects/spp_alloc_test.vcxproj

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\spp_alloc_test.cc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\sparsepp\spp.h" />
<ClInclude Include="..\..\sparsepp\spp_alloc.h" />
<ClInclude Include="..\..\sparsepp\spp_bitset.h" />
<ClInclude Include="..\..\sparsepp\spp_memory.h" />
<ClInclude Include="..\..\sparsepp\spp_timer.h" />
<ClInclude Include="..\..\sparsepp\spp_utils.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{19BC4240-15ED-4C76-BC57-34BB70FE163B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup>
<IntDirSharingDetected>None</IntDirSharingDetected>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)spp_alloc_test.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)spp_alloc_test.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
<Profile>true</Profile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_alloc_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<Profile>true</Profile>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

28
resources/3rdparty/sparsepp/tests/vsprojects/spp_alloc_test.vcxproj.filters

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{c644622a-f598-4fcf-861c-199b4b988881}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\sparsepp\spp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_alloc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_bitset.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_utils.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

175
resources/3rdparty/sparsepp/tests/vsprojects/spp_test.vcxproj

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\spp_test.cc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\sparsepp\spp.h" />
<ClInclude Include="..\..\sparsepp\spp_alloc.h" />
<ClInclude Include="..\..\sparsepp\spp_bitset.h" />
<ClInclude Include="..\..\sparsepp\spp_memory.h" />
<ClInclude Include="..\..\sparsepp\spp_timer.h" />
<ClInclude Include="..\..\sparsepp\spp_utils.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9863A521-E9DB-4775-A276-CADEF726CF11}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup>
<IntDirSharingDetected>None</IntDirSharingDetected>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
<IntDir>$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)spp_test.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>EnableAllWarnings</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)spp_test.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)spp_test.exe</OutputFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

32
resources/3rdparty/sparsepp/tests/vsprojects/spp_test.vcxproj.filters

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\spp_test.cc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\sparsepp\spp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_alloc.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_bitset.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\sparsepp\spp_utils.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

6
resources/3rdparty/sylvan/.travis.yml

@ -58,12 +58,12 @@ install:
script:
- ${CC} --version
- ${CXX} --version
- cmake . -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DSYLVAN_STATS=${SYLVAN_STATS} -DWITH_COVERAGE=${COVERAGE} -DSYLVAN_BUILD_DOCS=${SYLVAN_BUILD_DOCS}
- cmake . -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DSYLVAN_STATS=${SYLVAN_STATS} -DWITH_COVERAGE=${COVERAGE} -DSYLVAN_BUILD_DOCS=${SYLVAN_BUILD_DOCS} -DSYLVAN_BUILD_EXAMPLES=ON
- make -j 2
- make test
- examples/simple
- examples/mc models/schedule_world.2.8-rgs.bdd -w 2 | tee /dev/fd/2 | grep -q "1,570,340"
- examples/lddmc models/blocks.2.ldd -w 2 | tee /dev/fd/2 | grep -q "7057 states"
- examples/mc models/schedule_world.2.bdd -w 2 | tee /dev/fd/2 | grep -q "1,570,340"
- examples/lddmc models/blocks.2.ldd -w 2 | tee /dev/fd/2 | grep -q "7,057 states"
notifications:
email: false

48
resources/3rdparty/sylvan/CHANGELOG.md

@ -2,12 +2,60 @@
All notable changes to Sylvan will be documented in this file.
## [Unreleased]
### Changed
- We now implement twisted tabulation as the hash function for the nodes table. The old hash function is still available and the default behavior can be changed in `sylvan_table.h`.
## [1.4.0] - 2017-07-12
### Added
- Function `mtbdd_cmpl` that computes the complement for MTBDDs. (0 becomes 1, non-0 becomes 0)
### Changed
- Changed file formats used by the examples to match the changes in LTSmin.
- Function `mtbdd_satcount` now does not count assignments leading to 0. Perhaps in the future we make this configurable. (Like in CuDD.)
- Slightly improved C++ support by wrapping header files in the namespace sylvan.
### Fixed
- There was a bug where Lace tasks are overwritten during SYNC, which causes problems during garbage collection. Lace reusing the bucket during SYNC is by design and is difficult to change. We fix the issue by checking during garbage collection if the stored task is still the same function, which in the worst case marks more nodes than needed.
- Band-aid patch for hashing; very similar nodes were hashing to similar positions and strides, causing early garbage collections and full tables. The patch works for now, but we need a more robust solution.
### Removed
- Removed support for HWLOC (pinning on NUMA machines). Planning to bring this back as an option, but in its current form it prevents multiple Sylvan programs from running simultaneously on the same machine.
## [1.3.3] - 2017-06-03
### Changed
- Changed file format for .bdd files in the MC example.
### Fixed
- A major bug in `lddmc_match_sat_par` has been fixed.
- A bug in the saturation algorithm in the model checking example has been fixed.
- A major bug in the hash table rehashing implementation has been fixed.
## [1.3.2] - 2017-05-23
### Added
- Now implements `lddmc_protect` and `lddmc_unprotect` for external pointer references.
- Now implements `lddmc_refs_pushptr` and `lddmc_refs_popptr` for internal pointer references
### Changed
- New version of Lace has slightly different API for manually created threads.
## [1.3.1] - 2017-05-22
### Fixed
- A bug in `mtbdd_refs_ptrs_up` caused a segfault. This has been fixed.
## [1.3.0] - 2017-05-16
### Added
- The embedded work-stealing framework now explicitly checks for stack overflows and aborts with an appropriate error message written to stderr.
- New functions `sylvan_project` and `sylvan_and_project` for BDDs, a dual of existential quantification, where instead of the variables to remove, the given set of variables are the variables to keep.
- New functions `mtbdd_refs_pushptr` and `mtbdd_refs_popptr` allow thread-specific referencing of pointers.
### Changed
- Rewritten initialization of Sylvan. Before the call to `sylvan_init_package`, table sizes must be initialized either using `sylvan_set_sizes` or with the new function `sylvan_set_limits`. This new function allows the user to set a maximum number of bytes allocated for the nodes table and for the operation cache.
- Rewritten MTBDD referencing system.
- Rewritten MTBDD map and set functions (no API change except renaming `mtbdd_map_addall` to `mtbdd_map_update` with backward compatibility)
- The lock-free unique table now uses double hashing instead of rehashing. This can improve the performance for custom leaves and improves the hash spread.
### Fixed
- A bug in `llmsset_lookup` affecting custom leaves has been fixed.
## [1.2.0] - 2017-02-03
### Added

13
resources/3rdparty/sylvan/CMakeLists.txt

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.1)
project(sylvan LANGUAGES C CXX VERSION 1.2.0)
project(sylvan LANGUAGES C CXX VERSION 1.4.0)
set(PROJECT_DESCRIPTION "Sylvan, a parallel decision diagram library")
set(PROJECT_URL "https://github.com/trolando/sylvan")
@ -25,8 +25,8 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
option(SYLVAN_PORTABLE "If set, the created library will be portable." OFF)
option(USE_CARL "Sets whether carl should be included." ON)
set(CMAKE_C_FLAGS "-O2 -Wextra -Wall -fno-strict-aliasing -fPIC ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-O2 -Wextra -Wall -fno-strict-aliasing -Wno-deprecated -fPIC ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "-O2 -Wextra -Wall -fno-strict-aliasing ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "-O2 -Wextra -Wall -fno-strict-aliasing -Wno-deprecated ${CMAKE_CXX_FLAGS}")
if (NOT SYLVAN_PORTABLE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
@ -73,18 +73,17 @@ include_directories("${PROJECT_BINARY_DIR}/../../../include")
include_directories(src)
add_subdirectory(src)
option(SYLVAN_BUILD_TESTS "Build example tools" ON)
option(SYLVAN_BUILD_TESTS "Build example tests" ON)
if(SYLVAN_BUILD_TESTS)
add_subdirectory(test)
endif()
option(SYLVAN_BUILD_EXAMPLES "Build example tools" ON)
option(SYLVAN_BUILD_EXAMPLES "Build example tools" OFF)
if(SYLVAN_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
option(SYLVAN_BUILD_DOCS "Build documentation" ON)
option(SYLVAN_BUILD_DOCS "Build documentation" OFF)
if(SYLVAN_BUILD_DOCS)
configure_file("docs/conf.py.in" "docs/conf.py" @ONLY)
find_package(Sphinx REQUIRED)

7
resources/3rdparty/sylvan/cmake/FindGMP.cmake

@ -8,16 +8,13 @@
find_package(PkgConfig)
pkg_check_modules(PC_GMP QUIET gmp)
set(GMP_INCLUDE "" CACHE PATH "include dir")
set(GMP_LOCATION "" CACHE PATH "location dir")
set(GMP_DEFINITIONS ${PC_GMP_CFLAGS_OTHER})
find_path(GMP_INCLUDE_DIR gmp.h
HINTS ${GMP_INCLUDE} ${PC_GMP_INCLUDEDIR} ${PC_GMP_INCLUDE_DIRS})
HINTS ${PC_GMP_INCLUDEDIR} ${PC_GMP_INCLUDE_DIRS})
find_library(GMP_LIBRARIES NAMES gmp libgmp
HINTS ${GMP_LOCATION} ${PC_GMP_LIBDIR} ${PC_GMP_LIBRARY_DIRS} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
HINTS ${PC_GMP_LIBDIR} ${PC_GMP_LIBRARY_DIRS})
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set GMP_FOUND to TRUE

268
resources/3rdparty/sylvan/docs/index.rst

@ -31,15 +31,19 @@ Bindings for other languages than C/C++ also exist:
Dependencies
------------
Sylvan has the following required dependencies:
Sylvan has the following dependencies:
- **CMake** for compiling.
- **gmp** (``libgmp-dev``) for the GMP leaves in MTBDDs.
- **hwloc** (``libhwloc-dev``) for pinning worker threads to processors.
- **Sphinx** if you want to build the documentation.
Sylvan depends on the `work-stealing framework
Lace <http://fmt.ewi.utwente.nl/tools/lace>`__ for its implementation.
Lace is embedded in the Sylvan distribution.
Lace requires one additional library:
- **hwloc** (``libhwloc-dev``) for pinning worker threads to processors.
Building
--------
@ -71,14 +75,12 @@ To use Sylvan, the library and its dependency Lace must be initialized:
lace_init(n_workers, 0);
lace_startup(0, NULL, NULL);
size_t nodes_minsize = 1LL<<22;
size_t nodes_maxsize = 1LL<<26;
size_t cache_minsize = 1LL<<23;
size_t cache_maxsize = 1LL<<27;
sylvan_init_package(nodes_minsize, nodes_maxsize, cache_minsize, cache_maxsize);
// use at most 512 MB, nodes:cache ratio 2:1, initial size 1/32 of maximum
sylvan_set_limits(512*1024*1024, 1, 5);
sylvan_init_package();
sylvan_init_mtbdd();
...
/* ... do stuff ... */
sylvan_stats_report(stdout);
sylvan_quit();
@ -90,19 +92,20 @@ for work-stealing. The parameter ``n_workers`` can be set to 0 for auto-detectio
function ``lace_startup`` then creates all other worker threads. The worker threads run
until ``lace_exit`` is called. Lace must be started before Sylvan can be initialized.
Sylvan is initialized with a call to ``sylvan_init_package``. Here we choose the initial
and maximum sizes of the nodes table and the operation cache. In the example, we choose a maximum
nodes table size of 2^26 and a maximum cache size of 2^27. The initial sizes are
set to 2^22 and 2^23, respectively. The sizes must be powers of 2.
Sylvan allocates memory for the maximum sizes *in virtual memory* but only uses the space
needed for the initial sizes. The sizes are doubled during garbage collection, until the maximum
size has been reached.
Sylvan is initialized with a call to ``sylvan_init_package``. Before this call, Sylvan needs to know
how much memory to allocate for the nodes table and the operation cache. In this example, we use the
``sylvan_set_limits`` function to tell Sylvan that it may allocate at most 512 MB for these tables.
The second parameter indicates the ratio of the nodes table and the operation cache, with each
higher number doubling the size of the nodes table. Negative numbers double the size of the operation
cache instead. In the example, we want the nodes table to be twice as big as the operation cache.
The third parameter controls how often garbage collection doubles the table sizes before
their maximum size is reached. The value 5 means that the initial tables are 32x as small as the maximum size.
By default, every execution of garbage collection doubles the table sizes.
After ``sylvan_init_package``, the subpackages ``mtbdd`` and ``ldd`` can be initialized with
``sylvan_init_mtbdd`` and ``sylvan_init_ldd``. This mainly allocates auxiliary datastructures for
garbage collection.
After ``sylvan_init_package``, subpackages like ``mtbdd`` and ``ldd`` can be initialized with
``sylvan_init_mtbdd`` and ``sylvan_init_ldd``. This allocates auxiliary datastructures.
If you enable statistics generation (via CMake) then you can use ``sylvan_stats_report`` to report
If you enabled statistics generation (via CMake), then you can use ``sylvan_stats_report`` to report
the obtained statistics to a given ``FILE*``.
The Lace framework
@ -110,7 +113,7 @@ The Lace framework
Sylvan uses the Lace framework to offer 'automatic' parallelization of decision diagram operations.
Many functions in Sylvan are Lace tasks. To call a Lace task, the variables
``__lace_worker`` and ``__lace_dq_head`` must be initialized **locally**.
``__lace_worker`` and ``__lace_dq_head`` must be initialized as **local** variables of the current function.
Use the macro ``LACE_ME`` to initialize the variables in every function that calls Sylvan functions
and is not itself a Lace task.
@ -121,98 +124,207 @@ Like all decision diagram implementations, Sylvan performs garbage collection.
Garbage collection is triggered when trying to insert a new node and no
empty space can be found in the table within a reasonable upper bound.
Garbage collection can be disabled with ``sylvan_gc_disable`` and enabled again with ``sylvan_gc_enable``.
Call ``sylvan_gc`` to manually trigger garbage collection.
To ensure that no decision diagram nodes are overwritten, you must ensure that
Sylvan knows which decision diagrams you care about.
The easiest way to do this is with ``sylvan_protect`` and ``sylvan_unprotect`` to protect
a given pointer.
These functions protect the decision diagram referenced to by that pointer at the time
that garbage collection is performed.
Unlike some other implementations of decision diagrams,
you can modify the variable between the calls to ``sylvan_protect`` and ``sylvan_unprotect``
without explicitly changing the reference.
To manually trigger garbage collection, call ``sylvan_gc``.
You can use ``sylvan_gc_disable`` and ``sylvan_gc_enable`` to disable garbage collection or
enable it again. If garbage collection is disabled, the program will abort when the nodes table
is full.
Each subpackage implements mechanisms to store references to decision diagrams that must be kept.
For example, the *mtbdd* subpackage implements ``mtbdd_protect`` and ``mtbdd_unprotect`` to store pointers to
MTBDD variables.
.. code:: c
MTBDD* allocate_var() {
MTBDD* my_var = (MTBDD*)calloc(sizeof(MTBDD), 1);
mtbdd_protect(my_var);
return my_var;
}
free_var(MTBDD* my_var) {
mtbdd_unprotect(my_var);
free(my_var);
}
If you use ``mtbdd_protect`` you do not need to update the reference every time the value changes.
The *mtbdd* subpackage also implements thread-local stacks to temporarily store pointers and results of tasks:
.. code:: c
MTBDD some_thing = ...;
mtbdd_refs_pushptr(&some_thing);
MTBDD result_param1 = mtbdd_false, result_param2 = mtbdd_false;
mtbdd_refs_pushptr(&result_param1);
mtbdd_refs_pushptr(&result_param2);
while (some_condition) {
mtbdd_refs_spawn(SPAWN(an_operation, some_thing, param1));
result_param2 = CALL(an_operation, some_thing, param2);
result_param1 = mtbdd_refs_sync(SYNC(an_operation));
some_thing = CALL(another_operation, result1, result2);
}
mtbdd_refs_popptr(3);
return some_thing;
It is recommended to use the thread-local stacks for local variables, and to use the ``protect`` and ``unprotect``
functions for other variables. Every SPAWN and SYNC of a Lace task that returns an MTBDD must be decorated with
``mtbdd_refs_stack`` and ``mtbdd_refs_sync`` as in the above example.
References to decision diagrams must be added before a worker may cooperate on garbage collection.
Workers can cooperate on garbage collection during ``SYNC`` and when functions create nodes or use ``sylvan_gc_test`` to test whether to assist in garbage collection.
Functions for adding or removing references never perform garbage collection.
Furthermore, only the ``mtbdd_makenode`` function (and other node making primitives) implicitly reference their parameters; all other functions do not reference their parameters.
Nesting Sylvan functions (including ``sylvan_ithvar``) is bad practice and should be avoided.
**Warning**: Sylvan is a multi-threaded library and all workers must cooperate for garbage collection. If you use locking mechanisms in your code, beware of deadlocks!
You can explicitly cooperate on garbage collection with ``sylvan_gc_test()``.
Basic BDD/MTBDD functionality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Basic BDD functionality
~~~~~~~~~~~~~~~~~~~~~~~
In Sylvan, BDDs are special cases of MTBDDs.
Several functions are specific for BDDs and they start with ``sylvan_``, whereas generic MTBDD functions start
with ``mtbdd_``.
To create new BDDs, you can use:
- ``sylvan_true``: representation of constant ``true``.
- ``sylvan_false``: representation of constant ``false``.
- ``mtbdd_true``: representation of constant ``true``.
- ``mtbdd_false``: representation of constant ``false``.
- ``sylvan_ithvar(var)``: representation of literal <var> (negated: ``sylvan_nithvar(var)``)
To follow the BDD edges and obtain the variable at the root of a BDD,
you can use (only for internal nodes, not for leaves ``sylvan_true`` and ``sylvan_false``):
you can use (only for internal nodes, not for leaves ``mtbdd_true`` and ``mtbdd_false``):
- ``sylvan_var(bdd)``: obtain the variable of the root node of <bdd>.
- ``sylvan_high(bdd)``: follow the high edge of <bdd>.
- ``sylvan_low(bdd)``: follow the low edge of <bdd>.
- ``mtbdd_getvar(bdd)``: obtain the variable of the root node of <bdd>.
- ``mtbdd_gethigh(bdd)``: follow the high edge of <bdd>.
- ``mtbdd_getlow(bdd)``: follow the low edge of <bdd>.
You need to manually reference BDDs that you want to keep during garbage
collection:
collection (see the above explanation):
- ``sylvan_protect(bddptr)``: add a pointer reference to <bddptr>.
- ``sylvan_unprotect(bddptr)``: remove a pointer reference to <bddptr>.
- ``sylvan_ref(bdd)``: add a reference to <bdd>.
- ``sylvan_deref(bdd)``: remove a reference to <bdd>.
- ``mtbdd_protect(bddptr)``: add a pointer reference to <bddptr>.
- ``mtbdd_unprotect(bddptr)``: remove a pointer reference to <bddptr>.
- ``mtbdd_refs_pushptr(bddptr)``: add a local pointer reference to <bddptr>.
- ``mtbdd_refs_popptr(amount)``: remove the last <amount> local pointer references.
- ``mtbdd_refs_spawn(SPAWN(...))``: spawn a task that returns a BDD/MTBDD.
- ``mtbdd_refs_sync(SYNC(...))``: sync a task that returns a BDD/MTBDD.
It is recommended to use ``sylvan_protect`` and ``sylvan_unprotect``.
It is recommended to use ``mtbdd_protect`` and ``mtbdd_unprotect``.
The C++ objects (defined in ``sylvan_obj.hpp``) handle this automatically.
For local variables, we recommend ``mtbdd_refs_pushptr`` and ``mtbdd_refs_popptr``.
The following basic operations are implemented:
The following basic BDD operations are implemented:
- ``sylvan_not(bdd)``: compute the negation of <bdd>.
- ``sylvan_ite(a,b,c)``: compute 'if <a> then <b> else <c>'.
- ``sylvan_and(a, b)``: compute '<a> and <b>'
- ``sylvan_or(a, b)``: compute '<a> or <b>'
- ``sylvan_nand(a, b)``: compute 'not (<a> and <b>)'
- ``sylvan_nor(a, b)``: compute 'not (<a> or <b>)'
- ``sylvan_imp(a, b)``: compute '<a> then <b>'
- ``sylvan_invimp(a, b)``: compute '<b> then <a>'
- ``sylvan_xor(a, b)``: compute '<a> xor <b>'
- ``sylvan_equiv(a, b)``: compute '<a> = <b>'
- ``sylvan_diff(a, b)``: compute '<a> and not <b>'
- ``sylvan_less(a, b)``: compute '<b> and not <a>'
- ``sylvan_and(a, b)``: compute '<a> and <b>'.
- ``sylvan_or(a, b)``: compute '<a> or <b>'.
- ``sylvan_nand(a, b)``: compute 'not (<a> and <b>)'.
- ``sylvan_nor(a, b)``: compute 'not (<a> or <b>)'.
- ``sylvan_imp(a, b)``: compute '<a> then <b>'.
- ``sylvan_invimp(a, b)``: compute '<b> then <a>'.
- ``sylvan_xor(a, b)``: compute '<a> xor <b>'.
- ``sylvan_equiv(a, b)``: compute '<a> = <b>'.
- ``sylvan_diff(a, b)``: compute '<a> and not <b>'.
- ``sylvan_less(a, b)``: compute '<b> and not <a>'.
- ``sylvan_exists(bdd, vars)``: existential quantification of <bdd> with respect to variables <vars>.
- ``sylvan_forall(bdd, vars)``: universal quantification of <bdd> with respect to variables <vars>.
- ``sylvan_project(bdd, vars)``: the dual of ``sylvan_exists``, projects the <bdd> to the variable domain <vars>.
A set of variables (like <vars> above) is a BDD representing the conjunction of the variables.
Other BDD operations
~~~~~~~~~~~~~~~~~~~~
See ``src/sylvan_bdd.h`` for other operations on BDDs, especially operations
that are relevant for model checking.
Basic MTBDD functionality
~~~~~~~~~~~~~~~~~~~~~~~~~
See ``src/sylvan_mtbdd.h`` for operations on multi-terminal BDDs.
Basic LDD functionality
~~~~~~~~~~~~~~~~~~~~~~~
See ``src/sylvan_ldd.h`` for operations on List DDs.
A number of convencience functions are defined to manipulate sets of variables:
- ``mtbdd_set_empty()``: obtain an empty set.
- ``mtbdd_set_isempty(set)``: compute whether the set is empty.
- ``mtbdd_set_first(set)``: obtain the first variable of the set.
- ``mtbdd_set_next(set)``: obtain the subset without the first variable.
- ``mtbdd_set_from_array(arr, len)``: create a set from a given array.
- ``mtbdd_set_to_array(set, arr)``: write the set to the given array.
- ``mtbdd_set_add(set, var)``: compute the set plus the variable.
- ``mtbdd_set_union(set1, set2)``: compute the union of two sets.
- ``mtbdd_set_remove(set, var)``: compute the set minus the variable.
- ``mtbdd_set_minus(set1, set2)``: compute the set <set1> minus the variables in <set2>.
- ``mtbdd_set_count(set)``: compute the number of variables in the set.
- ``mtbdd_set_contains(set, var)``: compute whether the set contains the variable.
Sylvan also implements composition and substitution/variable renaming using a "MTBDD map". An MTBDD map is a special structure
implemented with special MTBDD nodes to store a mapping from variables (uint32_t) to MTBDDs. Like sets of variables and MTBDDs, MTBDD maps must
also be referenced for garbage collection. The following functions are related to MTBDD maps:
- ``mtbdd_compose(dd, map)``: apply the map to the given decision diagram, transforming every node with a variable that is associated with some function F in the map by ``if <F> then <high> else <low>``.
- ``sylvan_compose(dd, map)``: same as ``mtbdd_compose``, but assumes the decision diagram only has Boolean leaves.
- ``mtbdd_map_empty()``: obtain an empty map.
- ``mtbdd_map_isempty(map)``: compute whether the map is empty.
- ``mtbdd_map_key(map)``: obtain the key of the first pair of the map.
- ``mtbdd_map_value(map)``: obtain the value of the first pair of the map.
- ``mtbdd_map_next(map)``: obtain the submap without the first pair.
- ``mtbdd_map_add(map, key, value)``: compute the map plus the given key-value pair.
- ``mtbdd_map_update(map1, map2)``: compute the union of two maps, with priority to map2 if both maps share variables.
- ``mtbdd_map_remove(map, var)``: compute the map minus the variable.
- ``mtbdd_map_removeall(map, set)``: compute the map minus the given variables.
- ``mtbdd_map_count(set)``: compute the number of pairs in the map.
- ``mtbdd_map_contains(map, var)``: compute whether the map contains the variable.
Sylvan implements a number of counting operations:
- ``mtbdd_satcount(bdd, number_of_vars)``: compute the number of minterms (assignments that lead to True) for a function with <number_of_vars> variables; we don't need to know the exact variables that may be in the BDD, just how many there are.
- ``sylvan_pathcount(bdd)``: compute the number of distinct paths to True.
- ``mtbdd_nodecount(bdd)``: compute the number of nodes (and leaves) in the BDD.
- ``mtbdd_nodecount_more(array, length)``: compute the number of nodes (and leaves) in the array of BDDs.
Sylvan implements various advanced operations:
- ``sylvan_and_exists(bdd_a, bdd_b, vars)``: compute ``sylvan_exists(sylvan_and(bdd_a, bdd_b), vars)`` in one step.
- ``sylvan_and_project(bdd_a, bdd_b, vars)``: compute ``sylvan_project(sylvan_and(bdd_a, bdd_b), vars)`` in one step.
- ``sylvan_cube(vars, values)``: compute a cube (to leaf True) of the given variables, where the array values indicates for each variable whether to use it in negative form (value 0) or positive form (value 1) or to skip it (as dont-care, value 2).
- ``sylvan_union_cube(set, vars, values)``: compute ``sylvan_or(set, sylvan_cube(vars, values))`` in one step.
- ``sylvan_constrain(bdd_f, bdd_c)``: compute the generic cofactor of F constrained by C, i.e, set F to False for all assignments not in C.
- ``sylvan_restrict(bdd_f, bdd_c)``: compute Coudert and Madre's restrict algorithm, which tries to minimize bdd_f according to a care set C using sibling substitution; the invariant is ``restrict(f, c) \and c == f \and c``; the result of this algorithm is often but not always smaller than the original.
- ``sylvan_pick_cube(bdd)`` or ``sylvan_sat_one_bdd(bdd)``: extract a single path to True from the BDD (returns the BDD of this path)
- ``sylvan_pick_single_cube(bdd, vars)`` or ``sylvan_sat_single(bdd, vars)`` extracts a single minterm from the BDD (returns the BDD of this assignment)
- ``sylvan_sat_one(bdd, vars, array)``: extract a single minterm from the BDD given the set of variables and write the values of the variables in order to the given array, with 0 when it is negative, 1 when it is positive, and 2 when it is dontcare.
Sylvan implements several operations for transition systems. These operations assume an interleaved variable ordering, such that *source* or *unprimed* variables have even parity (0, 2, 4...) and matching *target* or *primed* variables have odd parity (1, 3, 5...).
The transition relations may be partial transition relations that only manipulate a subset of variables; hence, the operations also require the set of variables.
- ``sylvan_relnext(set, relation, vars)``: apply the (partial) relation on the given variables to the set.
- ``sylvan_relprev(relation, set, vars)``: apply the (partial) relation in reverse to the set; this computes predecessors but can also concatenate relations as follows: ``sylvan_relprev(rel1, rel2, rel1_vars)``.
- ``sylvan_closure(relation)``: compute the transitive closure of the given set recursively (see Matsunaga et al, DAC 1993)
See ``src/sylvan_bdd.h`` and ``src/mtbdd.h`` for other operations on BDDs and MTBDDs.
Custom leaves
~~~~~~~~~~~~~
See ``src/sylvan_mt.h`` and the example in ``src/sylvan_gmp.h`` and ``src/sylvan_gmp.c`` for custom leaves in MTBDDs.
Custom decision diagram operations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adding custom decision diagram operations is easy. Include ``sylvan_int.h`` for the internal functions. See ``sylvan_cache.h``
for how to use the operation cache.
List decision diagrams
~~~~~~~~~~~~~~~~~~~~~~
See ``src/sylvan_ldd.h`` for operations on list decision diagrams.
File I/O
~~~~~~~~
You can store and load BDDs using a number of methods, which are documented in the header files ``sylvan_mtbdd.h`` and ``sylvan_ldd.h``.
Support for C++
~~~~~~~~~~~~~~~
See ``src/sylvan_obj.hpp`` for the C++ interface.
.. Adding custom decision diagram operations
.. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Table resizing
~~~~~~~~~~~~~~
During garbage collection, it is possible to resize the nodes table and
the cache. Sylvan provides two default implementations: an aggressive
version that resizes every time garbage collection is performed, and a
the cache. By default, Sylvan doubles the table sizes during every garbage
collection until the maximum table size has been reached. There is also a
less aggressive version that only resizes when at least half the table is
full. This can be configured in ``src/sylvan_config.h``. It is not
possible to decrease the size of the nodes table and the cache.

328
resources/3rdparty/sylvan/examples/ldd2bdd.c

@ -13,15 +13,15 @@ static int workers = 0; // autodetect
static int verbose = 0;
static char* model_filename = NULL; // filename of model
static char* bdd_filename = NULL; // filename of output BDD
static char* sizes = "22,27,21,26"; // default sizes
static int check_results = 0;
static int no_reachable = 0;
/* argp configuration */
static struct argp_option options[] =
{
{"workers", 'w', "<workers>", 0, "Number of workers (default=0: autodetect)", 0},
{"table-sizes", 1, "<tablesize>,<tablemax>,<cachesize>,<cachemax>", 0, "Sizes of nodes table and operation cache as powers of 2", 0},
{"check-results", 2, 0, 0, "Check new transition relations ", 0},
{"check-results", 2, 0, 0, "Check new transition relations", 0},
{"no-reachable", 1, 0, 0, "Do not write reachabile states", 0},
{"verbose", 'v', 0, 0, "Set verbose", 0},
{0, 0, 0, 0, 0, 0}
};
@ -37,7 +37,7 @@ parse_opt(int key, char *arg, struct argp_state *state)
verbose = 1;
break;
case 1:
sizes = arg;
no_reachable = 1;
break;
case 2:
check_results = 1;
@ -58,67 +58,112 @@ parse_opt(int key, char *arg, struct argp_state *state)
static struct argp argp = { options, parse_opt, "<model> [<output-bdd>]", 0, 0, 0, 0 };
/* Globals */
/**
* Types (set and relation)
*/
typedef struct set
{
MDD mdd;
MDD proj;
MDD dd;
} *set_t;
typedef struct relation
{
MDD mdd;
MDD meta;
MDD dd;
MDD meta; // for relprod
int r_k, w_k, *r_proj, *w_proj;
} *rel_t;
static size_t vector_size; // size of vector
static int vector_size; // size of vector
static int next_count; // number of partitions of the transition relation
static rel_t *next; // each partition of the transition relation
static int actionbits = 0;
static int has_actions = 0;
#define Abort(...) { fprintf(stderr, __VA_ARGS__); exit(-1); }
#define Abort(...) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "Abort at line %d!\n", __LINE__); exit(-1); }
/* Load a set from file */
#define set_load(f) CALL(set_load, f)
TASK_1(set_t, set_load, FILE*, f)
{
lddmc_serialize_fromfile(f);
size_t mdd;
size_t proj;
int size;
set_t set = (set_t)malloc(sizeof(struct set));
if (fread(&mdd, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!\n");
if (fread(&proj, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!\n");
if (fread(&size, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
int k;
if (fread(&k, sizeof(int), 1, f) != 1) Abort("Invalid input file!");
if (k != -1) Abort("Invalid input file!");
set_t set = (set_t)malloc(sizeof(struct set));
set->mdd = lddmc_ref(lddmc_serialize_get_reversed(mdd));
set->proj = lddmc_ref(lddmc_serialize_get_reversed(proj));
lddmc_serialize_fromfile(f);
size_t dd;
if (fread(&dd, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!");
set->dd = lddmc_serialize_get_reversed(dd);
lddmc_protect(&set->dd);
return set;
}
/* Load a relation from file */
#define rel_load(f) CALL(rel_load, f)
TASK_1(rel_t, rel_load, FILE*, f)
#define rel_load_proj(f) CALL(rel_load_proj, f)
TASK_1(rel_t, rel_load_proj, FILE*, f)
{
lddmc_serialize_fromfile(f);
int r_k, w_k;
if (fread(&r_k, sizeof(int), 1, f) != 1) Abort("Invalid file format.");
if (fread(&w_k, sizeof(int), 1, f) != 1) Abort("Invalid file format.");
size_t mdd;
size_t meta;
rel_t rel = (rel_t)malloc(sizeof(struct relation));
rel->r_k = r_k;
rel->w_k = w_k;
rel->r_proj = (int*)malloc(sizeof(int[rel->r_k]));
rel->w_proj = (int*)malloc(sizeof(int[rel->w_k]));
if (fread(rel->r_proj, sizeof(int), rel->r_k, f) != (size_t)rel->r_k) Abort("Invalid file format.");
if (fread(rel->w_proj, sizeof(int), rel->w_k, f) != (size_t)rel->w_k) Abort("Invalid file format.");
int *r_proj = rel->r_proj;
int *w_proj = rel->w_proj;
/* Compute the meta */
uint32_t meta[vector_size*2+2];
memset(meta, 0, sizeof(uint32_t[vector_size*2+2]));
int r_i=0, w_i=0, i=0, j=0;
for (;;) {
int type = 0;
if (r_i < r_k && r_proj[r_i] == i) {
r_i++;
type += 1; // read
}
if (w_i < w_k && w_proj[w_i] == i) {
w_i++;
type += 2; // write
}
if (type == 0) meta[j++] = 0;
else if (type == 1) { meta[j++] = 3; }
else if (type == 2) { meta[j++] = 4; }
else if (type == 3) { meta[j++] = 1; meta[j++] = 2; }
if (r_i == r_k && w_i == w_k) {
meta[j++] = 5; // action label
meta[j++] = (uint32_t)-1;
break;
}
i++;
}
if (fread(&mdd, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!\n");
if (fread(&meta, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!\n");
rel->meta = lddmc_cube((uint32_t*)meta, j);
rel->dd = lddmc_false;
rel_t rel = (rel_t)malloc(sizeof(struct relation));
rel->mdd = lddmc_ref(lddmc_serialize_get_reversed(mdd));
rel->meta = lddmc_ref(lddmc_serialize_get_reversed(meta));
lddmc_protect(&rel->meta);
lddmc_protect(&rel->dd);
return rel;
}
#define rel_load(f, rel) CALL(rel_load, f, rel)
VOID_TASK_2(rel_load, FILE*, f, rel_t, rel)
{
lddmc_serialize_fromfile(f);
size_t dd;
if (fread(&dd, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!");
rel->dd = lddmc_serialize_get_reversed(dd);
}
/**
* Compute the highest value for each variable level.
* This method is called for the set of reachable states.
@ -199,7 +244,7 @@ VOID_TASK_3(compute_highest_action, MDD, dd, MDD, meta, uint32_t*, target)
*/
static uint64_t bdd_from_ldd_id;
#define bdd_from_ldd(dd, bits, firstvar) CALL(bdd_from_ldd, dd, bits, firstvar)
TASK_3(MTBDD, bdd_from_ldd, MDD, dd, MDD, bits_mdd, uint32_t, firstvar)
TASK_3(MTBDD, bdd_from_ldd, MDD, dd, MDD, bits_dd, uint32_t, firstvar)
{
/* simple for leaves */
if (dd == lddmc_false) return mtbdd_false;
@ -208,16 +253,16 @@ TASK_3(MTBDD, bdd_from_ldd, MDD, dd, MDD, bits_mdd, uint32_t, firstvar)
MTBDD result;
/* get from cache */
/* note: some assumptions about the encoding... */
if (cache_get3(bdd_from_ldd_id, dd, bits_mdd, firstvar, &result)) return result;
if (cache_get3(bdd_from_ldd_id, dd, bits_dd, firstvar, &result)) return result;
mddnode_t n = LDD_GETNODE(dd);
mddnode_t nbits = LDD_GETNODE(bits_mdd);
mddnode_t nbits = LDD_GETNODE(bits_dd);
int bits = (int)mddnode_getvalue(nbits);
/* spawn right, same bits_mdd and firstvar */
mtbdd_refs_spawn(SPAWN(bdd_from_ldd, mddnode_getright(n), bits_mdd, firstvar));
/* spawn right, same bits_dd and firstvar */
mtbdd_refs_spawn(SPAWN(bdd_from_ldd, mddnode_getright(n), bits_dd, firstvar));
/* call down, with next bits_mdd and firstvar */
/* call down, with next bits_dd and firstvar */
MTBDD down = CALL(bdd_from_ldd, mddnode_getdown(n), mddnode_getdown(nbits), firstvar + 2*bits);
/* encode current value */
@ -239,7 +284,7 @@ TASK_3(MTBDD, bdd_from_ldd, MDD, dd, MDD, bits_mdd, uint32_t, firstvar)
mtbdd_refs_pop(2);
/* put in cache */
cache_put3(bdd_from_ldd_id, dd, bits_mdd, firstvar, result);
cache_put3(bdd_from_ldd_id, dd, bits_dd, firstvar, result);
return result;
}
@ -249,7 +294,7 @@ TASK_3(MTBDD, bdd_from_ldd, MDD, dd, MDD, bits_mdd, uint32_t, firstvar)
*/
static uint64_t bdd_from_ldd_rel_id;
#define bdd_from_ldd_rel(dd, bits, firstvar, meta) CALL(bdd_from_ldd_rel, dd, bits, firstvar, meta)
TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD, meta)
TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_dd, uint32_t, firstvar, MDD, meta)
{
if (dd == lddmc_false) return mtbdd_false;
if (dd == lddmc_true) return mtbdd_true;
@ -266,11 +311,11 @@ TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD,
MTBDD result;
/* note: assumptions */
if (cache_get4(bdd_from_ldd_rel_id, dd, bits_mdd, firstvar, meta, &result)) return result;
if (cache_get4(bdd_from_ldd_rel_id, dd, bits_dd, firstvar, meta, &result)) return result;
const mddnode_t n = LDD_GETNODE(dd);
const mddnode_t nmeta = LDD_GETNODE(meta);
const mddnode_t nbits = LDD_GETNODE(bits_mdd);
const mddnode_t nbits = LDD_GETNODE(bits_dd);
const int bits = (int)mddnode_getvalue(nbits);
const uint32_t vmeta = mddnode_getvalue(nmeta);
@ -285,10 +330,10 @@ TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD,
assert(mddnode_getright(n) != mtbdd_true);
/* spawn right */
mtbdd_refs_spawn(SPAWN(bdd_from_ldd_rel, mddnode_getright(n), bits_mdd, firstvar, meta));
mtbdd_refs_spawn(SPAWN(bdd_from_ldd_rel, mddnode_getright(n), bits_dd, firstvar, meta));
/* compute down with same bits / firstvar */
MTBDD down = bdd_from_ldd_rel(mddnode_getdown(n), bits_mdd, firstvar, mddnode_getdown(nmeta));
MTBDD down = bdd_from_ldd_rel(mddnode_getdown(n), bits_dd, firstvar, mddnode_getdown(nmeta));
mtbdd_refs_push(down);
/* encode read value */
@ -319,7 +364,7 @@ TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD,
/* spawn right */
assert(mddnode_getright(n) != mtbdd_true);
mtbdd_refs_spawn(SPAWN(bdd_from_ldd_rel, mddnode_getright(n), bits_mdd, firstvar, meta));
mtbdd_refs_spawn(SPAWN(bdd_from_ldd_rel, mddnode_getright(n), bits_dd, firstvar, meta));
/* get recursive result */
MTBDD down = CALL(bdd_from_ldd_rel, mddnode_getdown(n), mddnode_getdown(nbits), firstvar + 2*bits, mddnode_getdown(nmeta));
@ -358,7 +403,7 @@ TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD,
assert(!mddnode_getcopy(n)); // do not process read copy nodes
/* spawn right */
mtbdd_refs_spawn(SPAWN(bdd_from_ldd_rel, mddnode_getright(n), bits_mdd, firstvar, meta));
mtbdd_refs_spawn(SPAWN(bdd_from_ldd_rel, mddnode_getright(n), bits_dd, firstvar, meta));
/* get recursive result */
MTBDD down = CALL(bdd_from_ldd_rel, mddnode_getdown(n), mddnode_getdown(nbits), firstvar + 2*bits, mddnode_getdown(nmeta));
@ -402,7 +447,7 @@ TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD,
assert(vmeta <= 5);
}
cache_put4(bdd_from_ldd_rel_id, dd, bits_mdd, firstvar, meta, result);
cache_put4(bdd_from_ldd_rel_id, dd, bits_dd, firstvar, meta, result);
return result;
}
@ -411,7 +456,7 @@ TASK_4(MTBDD, bdd_from_ldd_rel, MDD, dd, MDD, bits_mdd, uint32_t, firstvar, MDD,
* Compute the BDD equivalent of the meta variable (to a variables cube)
*/
MTBDD
meta_to_bdd(MDD meta, MDD bits_mdd, uint32_t firstvar)
meta_to_bdd(MDD meta, MDD bits_dd, uint32_t firstvar)
{
if (meta == lddmc_false || meta == lddmc_true) return mtbdd_true;
@ -430,10 +475,10 @@ meta_to_bdd(MDD meta, MDD bits_mdd, uint32_t firstvar)
if (vmeta == 1) {
/* return recursive result, don't go down on bits */
return meta_to_bdd(mddnode_getdown(nmeta), bits_mdd, firstvar);
return meta_to_bdd(mddnode_getdown(nmeta), bits_dd, firstvar);
}
const mddnode_t nbits = LDD_GETNODE(bits_mdd);
const mddnode_t nbits = LDD_GETNODE(bits_dd);
const int bits = (int)mddnode_getvalue(nbits);
/* compute recursive result */
@ -450,16 +495,6 @@ meta_to_bdd(MDD meta, MDD bits_mdd, uint32_t firstvar)
return res;
}
static char*
to_h(double size, char *buf)
{
const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
int i = 0;
for (;size>1024;size/=1024) i++;
sprintf(buf, "%.*f %s", i, size, units[i]);
return buf;
}
VOID_TASK_0(gc_start)
{
printf("Starting garbage collection\n");
@ -475,37 +510,13 @@ main(int argc, char **argv)
{
argp_parse(&argp, argc, argv, 0, 0, 0);
// Parse table sizes
int tablesize, maxtablesize, cachesize, maxcachesize;
if (sscanf(sizes, "%d,%d,%d,%d", &tablesize, &maxtablesize, &cachesize, &maxcachesize) != 4) {
Abort("Invalid string for --table-sizes, try e.g. --table-sizes=23,28,22,27");
}
if (tablesize < 10 || maxtablesize < 10 || cachesize < 10 || maxcachesize < 10 ||
tablesize > 40 || maxtablesize > 40 || cachesize > 40 || maxcachesize > 40) {
Abort("Invalid string for --table-sizes, must be between 10 and 40");
}
if (tablesize > maxtablesize) {
Abort("Invalid string for --table-sizes, tablesize is larger than maxtablesize");
}
if (cachesize > maxcachesize) {
Abort("Invalid string for --table-sizes, cachesize is larger than maxcachesize");
}
// Report table sizes
char buf[32];
to_h((1ULL<<maxtablesize)*24+(1ULL<<maxcachesize)*36, buf);
printf("Sylvan allocates %s virtual memory for nodes table and operation cache.\n", buf);
to_h((1ULL<<tablesize)*24+(1ULL<<cachesize)*36, buf);
printf("Initial nodes table and operation cache requires %s.\n", buf);
// Init Lace
lace_init(workers, 1000000); // auto-detect number of workers, use a 1,000,000 size task queue
lace_startup(0, NULL, NULL); // auto-detect program stack, do not use a callback for startup
LACE_ME;
// Init Sylvan
sylvan_set_sizes(1LL<<21, 1LL<<27, 1LL<<20, 1LL<<26);
sylvan_set_limits(1LL<<30, 1, 10);
sylvan_init_package();
sylvan_init_ldd();
sylvan_init_mtbdd();
@ -523,34 +534,20 @@ main(int argc, char **argv)
if (f == NULL) Abort("Cannot open file '%s'!\n", model_filename);
// Read integers per vector
if (fread(&vector_size, sizeof(size_t), 1, f) != 1) Abort("Invalid input file!\n");
if (fread(&vector_size, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
// Read initial state
if (verbose) {
printf("Loading initial state... ");
fflush(stdout);
}
if (verbose) printf("Loading initial state.\n");
set_t initial = set_load(f);
if (verbose) printf("done.\n");
// Read number of transitions
if (fread(&next_count, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
next = (rel_t*)malloc(sizeof(rel_t) * next_count);
// Read transitions
if (verbose) {
printf("Loading transition relations... ");
fflush(stdout);
}
int i;
for (i=0; i<next_count; i++) {
next[i] = rel_load(f);
if (verbose) {
printf("%d, ", i);
fflush(stdout);
}
}
if (verbose) printf("done.\n");
if (verbose) printf("Loading transition relations.\n");
for (int i=0; i<next_count; i++) next[i] = rel_load_proj(f);
for (int i=0; i<next_count; i++) rel_load(f, next[i]);
// Read whether reachable states are stored
int has_reachable = 0;
@ -558,16 +555,13 @@ main(int argc, char **argv)
if (has_reachable == 0) Abort("Input file missing reachable states!\n");
// Read reachable states
if (verbose) {
printf("Loading reachable states... ");
fflush(stdout);
}
if (verbose) printf("Loading reachable states.\n");
set_t states = set_load(f);
if (verbose) printf("done.\n");
// Read number of action labels
int action_labels_count = 0;
if (fread(&action_labels_count, sizeof(int), 1, f) != 1) Abort("Input file missing action label count!\n");
if (fread(&action_labels_count, sizeof(int), 1, f) != 1) action_labels_count = 0;
// ignore: Abort("Input file missing action label count!\n");
// Read action labels
char *action_labels[action_labels_count];
@ -587,11 +581,11 @@ main(int argc, char **argv)
// Report statistics
if (verbose) {
printf("%zu integers per state, %d transition groups\n", vector_size, next_count);
printf("%d integers per state, %d transition groups\n", vector_size, next_count);
printf("LDD nodes:\n");
printf("Initial states: %zu LDD nodes\n", lddmc_nodecount(initial->mdd));
for (i=0; i<next_count; i++) {
printf("Transition %d: %zu LDD nodes\n", i, lddmc_nodecount(next[i]->mdd));
printf("Initial states: %zu LDD nodes\n", lddmc_nodecount(initial->dd));
for (int i=0; i<next_count; i++) {
printf("Transition %d: %zu LDD nodes\n", i, lddmc_nodecount(next[i]->dd));
}
}
@ -600,28 +594,18 @@ main(int argc, char **argv)
// Compute highest value at each level (from reachable states)
uint32_t highest[vector_size];
for (size_t i=0; i<vector_size; i++) highest[i] = 0;
compute_highest(states->mdd, highest);
for (int i=0; i<vector_size; i++) highest[i] = 0;
compute_highest(states->dd, highest);
// Compute highest action label value (from transition relations)
uint32_t highest_action = 0;
for (int i=0; i<next_count; i++) {
compute_highest_action(next[i]->mdd, next[i]->meta, &highest_action);
}
// Report highest integers
/*
printf("Highest integer per level: ");
for (size_t i=0; i<vector_size; i++) {
if (i>0) printf(", ");
printf("%u", highest[i]);
compute_highest_action(next[i]->dd, next[i]->meta, &highest_action);
}
printf("\n");
*/
// Compute number of bits for each level
int bits[vector_size];
for (size_t i=0; i<vector_size; i++) {
for (int i=0; i<vector_size; i++) {
bits[i] = 0;
while (highest[i] != 0) {
bits[i]++;
@ -641,7 +625,7 @@ main(int argc, char **argv)
// Report number of bits
if (verbose) {
printf("Bits per level: ");
for (size_t i=0; i<vector_size; i++) {
for (int i=0; i<vector_size; i++) {
if (i>0) printf(", ");
printf("%d", bits[i]);
}
@ -650,15 +634,15 @@ main(int argc, char **argv)
}
// Compute bits MDD
MDD bits_mdd = lddmc_true;
for (size_t i=0; i<vector_size; i++) {
bits_mdd = lddmc_makenode(bits[vector_size-i-1], bits_mdd, lddmc_false);
MDD bits_dd = lddmc_true;
for (int i=0; i<vector_size; i++) {
bits_dd = lddmc_makenode(bits[vector_size-i-1], bits_dd, lddmc_false);
}
lddmc_ref(bits_mdd);
lddmc_ref(bits_dd);
// Compute total number of bits
int totalbits = 0;
for (size_t i=0; i<vector_size; i++) {
for (int i=0; i<vector_size; i++) {
totalbits += bits[i];
}
@ -677,28 +661,23 @@ main(int argc, char **argv)
if (f == NULL) Abort("Cannot open file '%s'!\n", bdd_filename);
// Write domain...
int vector_size = 1;
fwrite(&totalbits, sizeof(int), 1, f); // use number of bits as vector size
fwrite(&vector_size, sizeof(int), 1, f); // set each to 1
fwrite(&vector_size, sizeof(int), 1, f);
fwrite(bits, sizeof(int), vector_size, f);
fwrite(&actionbits, sizeof(int), 1, f);
// Write initial state...
MTBDD new_initial = bdd_from_ldd(initial->mdd, bits_mdd, 0);
assert((size_t)mtbdd_satcount(new_initial, totalbits) == (size_t)lddmc_satcount_cached(initial->mdd));
MTBDD new_initial = bdd_from_ldd(initial->dd, bits_dd, 0);
assert((size_t)mtbdd_satcount(new_initial, totalbits) == (size_t)lddmc_satcount_cached(initial->dd));
mtbdd_refs_push(new_initial);
{
size_t a = sylvan_serialize_add(new_initial);
size_t b = sylvan_serialize_add(state_vars);
size_t s = totalbits;
sylvan_serialize_tofile(f);
fwrite(&a, sizeof(size_t), 1, f);
fwrite(&s, sizeof(size_t), 1, f);
fwrite(&b, sizeof(size_t), 1, f);
int k = -1;
fwrite(&k, sizeof(int), 1, f);
mtbdd_writer_tobinary(f, &new_initial, 1);
}
// Custom operation that converts to BDD given number of bits for each level
MTBDD new_states = bdd_from_ldd(states->mdd, bits_mdd, 0);
assert((size_t)mtbdd_satcount(new_states, totalbits) == (size_t)lddmc_satcount_cached(states->mdd));
MTBDD new_states = bdd_from_ldd(states->dd, bits_dd, 0);
assert((size_t)mtbdd_satcount(new_states, totalbits) == (size_t)lddmc_satcount_cached(states->dd));
mtbdd_refs_push(new_states);
// Report size of BDD
@ -710,51 +689,52 @@ main(int argc, char **argv)
// Write number of transitions
fwrite(&next_count, sizeof(int), 1, f);
// Write transitions
// Write meta for each transition
for (int i=0; i<next_count; i++) {
fwrite(&next[i]->r_k, sizeof(int), 1, f);
fwrite(&next[i]->w_k, sizeof(int), 1, f);
fwrite(next[i]->r_proj, sizeof(int), next[i]->r_k, f);
fwrite(next[i]->w_proj, sizeof(int), next[i]->w_k, f);
}
// Write BDD for each transition
for (int i=0; i<next_count; i++) {
// Compute new transition relation
MTBDD new_rel = bdd_from_ldd_rel(next[i]->mdd, bits_mdd, 0, next[i]->meta);
MTBDD new_rel = bdd_from_ldd_rel(next[i]->dd, bits_dd, 0, next[i]->meta);
mtbdd_refs_push(new_rel);
mtbdd_writer_tobinary(f, &new_rel, 1);
// Compute new <variables> for the current transition relation
MTBDD new_vars = meta_to_bdd(next[i]->meta, bits_mdd, 0);
mtbdd_refs_push(new_vars);
// Report number of nodes
if (verbose) printf("Transition %d: %zu BDD nodes\n", i, mtbdd_nodecount(new_rel));
if (check_results) {
// Compute new <variables> for the current transition relation
MTBDD new_vars = meta_to_bdd(next[i]->meta, bits_dd, 0);
mtbdd_refs_push(new_vars);
// Test if the transition is correctly converted
MTBDD test = sylvan_relnext(new_states, new_rel, new_vars);
mtbdd_refs_push(test);
MDD succ = lddmc_relprod(states->mdd, next[i]->mdd, next[i]->meta);
MDD succ = lddmc_relprod(states->dd, next[i]->dd, next[i]->meta);
lddmc_refs_push(succ);
MTBDD test2 = bdd_from_ldd(succ, bits_mdd, 0);
MTBDD test2 = bdd_from_ldd(succ, bits_dd, 0);
if (test != test2) Abort("Conversion error!\n");
mtbdd_refs_pop(1);
lddmc_refs_pop(1);
mtbdd_refs_pop(2);
}
// Report number of nodes
if (verbose) printf("Transition %d: %zu BDD nodes\n", i, mtbdd_nodecount(new_rel));
size_t a = sylvan_serialize_add(new_rel);
size_t b = sylvan_serialize_add(new_vars);
sylvan_serialize_tofile(f);
fwrite(&a, sizeof(size_t), 1, f);
fwrite(&b, sizeof(size_t), 1, f);
mtbdd_refs_pop(1);
}
// Write reachable states
has_reachable = 1;
if (no_reachable) has_reachable = 0;
fwrite(&has_reachable, sizeof(int), 1, f);
{
size_t a = sylvan_serialize_add(new_states);
size_t b = sylvan_serialize_add(state_vars);
size_t s = totalbits;
sylvan_serialize_tofile(f);
fwrite(&a, sizeof(size_t), 1, f);
fwrite(&s, sizeof(size_t), 1, f);
fwrite(&b, sizeof(size_t), 1, f);
if (has_reachable) {
int k = -1;
fwrite(&k, sizeof(int), 1, f);
mtbdd_writer_tobinary(f, &new_states, 1);
}
mtbdd_refs_pop(1); // new_states
// Write action labels
fwrite(&action_labels_count, sizeof(int), 1, f);

834
resources/3rdparty/sylvan/examples/lddmc.c
File diff suppressed because it is too large
View File

558
resources/3rdparty/sylvan/examples/mc.c

@ -10,15 +10,17 @@
#include <gperftools/profiler.h>
#endif
#include <getrss.h>
#include <sylvan.h>
#include <sylvan_table.h>
#include <sylvan_int.h>
/* Configuration */
/* Configuration (via argp) */
static int report_levels = 0; // report states at end of every level
static int report_table = 0; // report table size at end of every level
static int report_nodes = 0; // report number of nodes of BDDs
static int strategy = 1; // set to 1 = use PAR strategy; set to 0 = use BFS strategy
static int check_deadlocks = 0; // set to 1 to check for deadlocks
static int strategy = 2; // 0 = BFS, 1 = PAR, 2 = SAT, 3 = CHAINING
static int check_deadlocks = 0; // set to 1 to check for deadlocks on-the-fly (only bfs/par)
static int merge_relations = 0; // merge relations to 1 relation
static int print_transition_matrix = 0; // print transition relation matrix
static int workers = 0; // autodetect
@ -31,7 +33,7 @@ static char* profile_filename = NULL; // filename for profiling
static struct argp_option options[] =
{
{"workers", 'w', "<workers>", 0, "Number of workers (default=0: autodetect)", 0},
{"strategy", 's', "<bfs|par|sat>", 0, "Strategy for reachability (default=par)", 0},
{"strategy", 's', "<bfs|par|sat|chaining>", 0, "Strategy for reachability (default=sat)", 0},
#ifdef HAVE_PROFILER
{"profiler", 'p', "<filename>", 0, "Filename for profiling", 0},
#endif
@ -54,6 +56,7 @@ parse_opt(int key, char *arg, struct argp_state *state)
if (strcmp(arg, "bfs")==0) strategy = 0;
else if (strcmp(arg, "par")==0) strategy = 1;
else if (strcmp(arg, "sat")==0) strategy = 2;
else if (strcmp(arg, "chaining")==0) strategy = 3;
else argp_usage(state);
break;
case 4:
@ -93,7 +96,9 @@ parse_opt(int key, char *arg, struct argp_state *state)
}
static struct argp argp = { options, parse_opt, "<model>", 0, 0, 0, 0 };
/* Globals */
/**
* Types (set and relation)
*/
typedef struct set
{
BDD bdd;
@ -104,15 +109,19 @@ typedef struct relation
{
BDD bdd;
BDD variables; // all variables in the relation (used by relprod)
int r_k, w_k, *r_proj, *w_proj;
} *rel_t;
static int vector_size; // size of vector
static int statebits, actionbits; // number of bits for state, number of bits for action
static int bits_per_integer; // number of bits per integer in the vector
static int vectorsize; // size of vector in integers
static int *statebits; // number of bits for each state integer
static int actionbits; // number of bits for action label
static int totalbits; // total number of bits
static int next_count; // number of partitions of the transition relation
static rel_t *next; // each partition of the transition relation
/* Obtain current wallclock time */
/**
* Obtain current wallclock time
*/
static double
wctime()
{
@ -123,66 +132,171 @@ wctime()
static double t_start;
#define INFO(s, ...) fprintf(stdout, "[% 8.2f] " s, wctime()-t_start, ##__VA_ARGS__)
#define Abort(...) { fprintf(stderr, __VA_ARGS__); exit(-1); }
#define Abort(...) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "Abort at line %d!\n", __LINE__); exit(-1); }
/* Load a set from file */
#define set_load(f) CALL(set_load, f)
TASK_1(set_t, set_load, FILE*, f)
static char*
to_h(double size, char *buf)
{
sylvan_serialize_fromfile(f);
const char* units[] = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
int i = 0;
for (;size>1024;size/=1024) i++;
sprintf(buf, "%.*f %s", i, size, units[i]);
return buf;
}
size_t set_bdd, set_vector_size, set_state_vars;
if ((fread(&set_bdd, sizeof(size_t), 1, f) != 1) ||
(fread(&set_vector_size, sizeof(size_t), 1, f) != 1) ||
(fread(&set_state_vars, sizeof(size_t), 1, f) != 1)) {
Abort("Invalid input file!\n");
}
static void
print_memory_usage(void)
{
char buf[32];
to_h(getCurrentRSS(), buf);
INFO("Memory usage: %s\n", buf);
}
/**
* Load a set from file
* The expected binary format:
* - int k : projection size, or -1 for full state
* - int[k] proj : k integers specifying the variables of the projection
* - MTBDD[1] BDD (mtbdd binary format)
*/
#define set_load(f) CALL(set_load, f)
TASK_1(set_t, set_load, FILE*, f)
{
// allocate set
set_t set = (set_t)malloc(sizeof(struct set));
set->bdd = sylvan_serialize_get_reversed(set_bdd);
set->variables = sylvan_support(sylvan_serialize_get_reversed(set_state_vars));
set->bdd = sylvan_false;
set->variables = sylvan_true;
sylvan_protect(&set->bdd);
sylvan_protect(&set->variables);
// read k
int k;
if (fread(&k, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
if (k == -1) {
// create variables for a full state vector
uint32_t vars[totalbits];
for (int i=0; i<totalbits; i++) vars[i] = 2*i;
set->variables = sylvan_set_fromarray(vars, totalbits);
} else {
// read proj
int proj[k];
if (fread(proj, sizeof(int), k, f) != (size_t)k) Abort("Invalid input file!\n");
// create variables for a short/projected state vector
uint32_t vars[totalbits];
uint32_t cv = 0;
int j = 0, n = 0;
for (int i=0; i<vectorsize && j<k; i++) {
if (i == proj[j]) {
for (int x=0; x<statebits[i]; x++) vars[n++] = (cv += 2) - 2;
j++;
} else {
cv += 2 * statebits[i];
}
}
set->variables = sylvan_set_fromarray(vars, n);
}
// read bdd
if (mtbdd_reader_frombinary(f, &set->bdd, 1) != 0) Abort("Invalid input file!\n");
return set;
}
/* Load a relation from file */
#define rel_load(f) CALL(rel_load, f)
TASK_1(rel_t, rel_load, FILE*, f)
/**
* Load a relation from file
* This part just reads the r_k, w_k, r_proj and w_proj variables.
*/
#define rel_load_proj(f) CALL(rel_load_proj, f)
TASK_1(rel_t, rel_load_proj, FILE*, f)
{
sylvan_serialize_fromfile(f);
size_t rel_bdd, rel_vars;
if ((fread(&rel_bdd, sizeof(size_t), 1, f) != 1) ||
(fread(&rel_vars, sizeof(size_t), 1, f) != 1)) {
Abort("Invalid input file!\n");
}
rel_t rel = (rel_t)malloc(sizeof(struct relation));
rel->bdd = sylvan_serialize_get_reversed(rel_bdd);
rel->variables = sylvan_support(sylvan_serialize_get_reversed(rel_vars));
int r_k, w_k;
if (fread(&r_k, sizeof(int), 1, f) != 1) Abort("Invalid file format.");
if (fread(&w_k, sizeof(int), 1, f) != 1) Abort("Invalid file format.");
rel->r_k = r_k;
rel->w_k = w_k;
int *r_proj = (int*)malloc(sizeof(int[r_k]));
int *w_proj = (int*)malloc(sizeof(int[w_k]));
if (fread(r_proj, sizeof(int), r_k, f) != (size_t)r_k) Abort("Invalid file format.");
if (fread(w_proj, sizeof(int), w_k, f) != (size_t)w_k) Abort("Invalid file format.");
rel->r_proj = r_proj;
rel->w_proj = w_proj;
rel->bdd = sylvan_false;
sylvan_protect(&rel->bdd);
/* Compute a_proj the union of r_proj and w_proj, and a_k the length of a_proj */
int a_proj[r_k+w_k];
int r_i = 0, w_i = 0, a_i = 0;
for (;r_i < r_k || w_i < w_k;) {
if (r_i < r_k && w_i < w_k) {
if (r_proj[r_i] < w_proj[w_i]) {
a_proj[a_i++] = r_proj[r_i++];
} else if (r_proj[r_i] > w_proj[w_i]) {
a_proj[a_i++] = w_proj[w_i++];
} else /* r_proj[r_i] == w_proj[w_i] */ {
a_proj[a_i++] = w_proj[w_i++];
r_i++;
}
} else if (r_i < r_k) {
a_proj[a_i++] = r_proj[r_i++];
} else if (w_i < w_k) {
a_proj[a_i++] = w_proj[w_i++];
}
}
const int a_k = a_i;
/* Compute all_variables, which are all variables the transition relation is defined on */
uint32_t all_vars[totalbits * 2];
uint32_t curvar = 0; // start with variable 0
int i=0, j=0, n=0;
for (; i<vectorsize && j<a_k; i++) {
if (i == a_proj[j]) {
for (int k=0; k<statebits[i]; k++) {
all_vars[n++] = curvar;
all_vars[n++] = curvar + 1;
curvar += 2;
}
j++;
} else {
curvar += 2 * statebits[i];
}
}
rel->variables = sylvan_set_fromarray(all_vars, n);
sylvan_protect(&rel->variables);
return rel;
}
/**
* Load a relation from file
* This part just reads the bdd of the relation
*/
#define rel_load(rel, f) CALL(rel_load, rel, f)
VOID_TASK_2(rel_load, rel_t, rel, FILE*, f)
{
if (mtbdd_reader_frombinary(f, &rel->bdd, 1) != 0) Abort("Invalid file format!\n");
}
/**
* Print a single example of a set to stdout
* Assumption: the example is a full vector and variables contains all state variables...
*/
#define print_example(example, variables) CALL(print_example, example, variables)
VOID_TASK_2(print_example, BDD, example, BDDSET, variables)
{
uint8_t str[vector_size * bits_per_integer];
uint8_t str[totalbits];
if (example != sylvan_false) {
sylvan_sat_one(example, variables, str);
int x=0;
printf("[");
for (int i=0; i<vector_size; i++) {
for (int i=0; i<vectorsize; i++) {
uint32_t res = 0;
for (int j=0; j<bits_per_integer; j++) {
if (str[bits_per_integer*i+j] == 1) res++;
res<<=1;
for (int j=0; j<statebits[i]; j++) {
if (str[x++] == 1) res++;
res <<= 1;
}
if (i>0) printf(",");
printf("%" PRIu32, res);
@ -191,7 +305,84 @@ VOID_TASK_2(print_example, BDD, example, BDDSET, variables)
}
}
/* Straight-forward implementation of parallel reduction */
/**
* Implementation of (parallel) saturation
* (assumes relations are ordered on first variable)
*/
TASK_2(BDD, go_sat, BDD, set, int, idx)
{
/* Terminal cases */
if (set == sylvan_false) return sylvan_false;
if (idx == next_count) return set;
/* Consult the cache */
BDD result;
const BDD _set = set;
if (cache_get3(200LL<<40, _set, idx, 0, &result)) return result;
mtbdd_refs_pushptr(&_set);
/**
* Possible improvement: cache more things (like intermediate results?)
* and chain-apply more of the current level before going deeper?
*/
/* Check if the relation should be applied */
const uint32_t var = sylvan_var(next[idx]->variables);
if (set == sylvan_true || var <= sylvan_var(set)) {
/* Count the number of relations starting here */
int count = idx+1;
while (count < next_count && var == sylvan_var(next[count]->variables)) count++;
count -= idx;
/*
* Compute until fixpoint:
* - SAT deeper
* - chain-apply all current level once
*/
BDD prev = sylvan_false;
BDD step = sylvan_false;
mtbdd_refs_pushptr(&set);
mtbdd_refs_pushptr(&prev);
mtbdd_refs_pushptr(&step);
while (prev != set) {
prev = set;
// SAT deeper
set = CALL(go_sat, set, idx+count);
// chain-apply all current level once
for (int i=0;i<count;i++) {
step = sylvan_relnext(set, next[idx+i]->bdd, next[idx+i]->variables);
set = sylvan_or(set, step);
step = sylvan_false; // unset, for gc
}
}
mtbdd_refs_popptr(3);
result = set;
} else {
/* Recursive computation */
mtbdd_refs_spawn(SPAWN(go_sat, sylvan_low(set), idx));
BDD high = mtbdd_refs_push(CALL(go_sat, sylvan_high(set), idx));
BDD low = mtbdd_refs_sync(SYNC(go_sat));
mtbdd_refs_pop(1);
result = sylvan_makenode(sylvan_var(set), low, high);
}
/* Store in cache */
cache_put3(200LL<<40, _set, idx, 0, result);
mtbdd_refs_popptr(1);
return result;
}
/**
* Wrapper for the Saturation strategy
*/
VOID_TASK_1(sat, set_t, set)
{
set->bdd = CALL(go_sat, set->bdd, 0);
}
/**
* Implement parallel strategy (that performs the relnext operations in parallel)
* This function does one level...
*/
TASK_5(BDD, go_par, BDD, cur, BDD, visited, size_t, from, size_t, len, BDD*, deadlocks)
{
if (len == 1) {
@ -239,7 +430,9 @@ TASK_5(BDD, go_par, BDD, cur, BDD, visited, size_t, from, size_t, len, BDD*, dea
}
}
/* PAR strategy, parallel strategy (operations called in parallel *and* parallelized by Sylvan) */
/**
* Implementation of the PAR strategy
*/
VOID_TASK_1(par, set_t, set)
{
BDD visited = set->bdd;
@ -301,7 +494,10 @@ VOID_TASK_1(par, set_t, set)
sylvan_unprotect(&deadlocks);
}
/* Sequential version of merge-reduction */
/**
* Implement sequential strategy (that performs the relnext operations one by one)
* This function does one level...
*/
TASK_5(BDD, go_bfs, BDD, cur, BDD, visited, size_t, from, size_t, len, BDD*, deadlocks)
{
if (len == 1) {
@ -350,7 +546,9 @@ TASK_5(BDD, go_bfs, BDD, cur, BDD, visited, size_t, from, size_t, len, BDD*, dea
}
}
/* BFS strategy, sequential strategy (but operations are parallelized by Sylvan) */
/**
* Implementation of the BFS strategy
*/
VOID_TASK_1(bfs, set_t, set)
{
BDD visited = set->bdd;
@ -412,26 +610,77 @@ VOID_TASK_1(bfs, set_t, set)
sylvan_unprotect(&deadlocks);
}
/**
* Implementation of the Chaining strategy (does not support deadlock detection)
*/
VOID_TASK_1(chaining, set_t, set)
{
BDD visited = set->bdd;
BDD next_level = visited;
BDD succ = sylvan_false;
bdd_refs_pushptr(&visited);
bdd_refs_pushptr(&next_level);
bdd_refs_pushptr(&succ);
int iteration = 1;
do {
// calculate successors in parallel
for (int i=0; i<next_count; i++) {
succ = sylvan_relnext(next_level, next[i]->bdd, next[i]->variables);
next_level = sylvan_or(next_level, succ);
succ = sylvan_false; // reset, for gc
}
// new = new - visited
// visited = visited + new
next_level = sylvan_diff(next_level, visited);
visited = sylvan_or(visited, next_level);
if (report_table && report_levels) {
size_t filled, total;
sylvan_table_usage(&filled, &total);
INFO("Level %d done, %'0.0f states explored, table: %0.1f%% full (%'zu nodes)\n",
iteration, sylvan_satcount(visited, set->variables),
100.0*(double)filled/total, filled);
} else if (report_table) {
size_t filled, total;
sylvan_table_usage(&filled, &total);
INFO("Level %d done, table: %0.1f%% full (%'zu nodes)\n",
iteration,
100.0*(double)filled/total, filled);
} else if (report_levels) {
INFO("Level %d done, %'0.0f states explored\n", iteration, sylvan_satcount(visited, set->variables));
} else {
INFO("Level %d done\n", iteration);
}
iteration++;
} while (next_level != sylvan_false);
set->bdd = visited;
bdd_refs_popptr(3);
}
/**
* Extend a transition relation to a larger domain (using s=s')
*/
#define extend_relation(rel, vars) CALL(extend_relation, rel, vars)
TASK_2(BDD, extend_relation, BDD, relation, BDDSET, variables)
TASK_2(BDD, extend_relation, MTBDD, relation, MTBDD, variables)
{
/* first determine which state BDD variables are in rel */
int has[statebits];
for (int i=0; i<statebits; i++) has[i] = 0;
BDDSET s = variables;
int has[totalbits];
for (int i=0; i<totalbits; i++) has[i] = 0;
MTBDD s = variables;
while (!sylvan_set_isempty(s)) {
BDDVAR v = sylvan_set_first(s);
if (v/2 >= (unsigned)statebits) break; // action labels
uint32_t v = sylvan_set_first(s);
if (v/2 >= (unsigned)totalbits) break; // action labels
has[v/2] = 1;
s = sylvan_set_next(s);
}
/* create "s=s'" for all variables not in rel */
BDD eq = sylvan_true;
for (int i=statebits-1; i>=0; i--) {
for (int i=totalbits-1; i>=0; i--) {
if (has[i]) continue;
BDD low = sylvan_makenode(2*i+1, eq, sylvan_false);
bdd_refs_push(low);
@ -463,148 +712,209 @@ TASK_2(BDD, big_union, int, first, int, count)
return result;
}
/**
* Print one row of the transition matrix (for vars)
*/
static void
print_matrix(BDD vars)
print_matrix_row(rel_t rel)
{
for (int i=0; i<vector_size; i++) {
if (sylvan_set_isempty(vars)) {
fprintf(stdout, "-");
} else {
BDDVAR next_s = 2*((i+1)*bits_per_integer);
if (sylvan_set_first(vars) < next_s) {
fprintf(stdout, "+");
for (;;) {
vars = sylvan_set_next(vars);
if (sylvan_set_isempty(vars)) break;
if (sylvan_set_first(vars) >= next_s) break;
}
} else {
fprintf(stdout, "-");
}
int r_i = 0, w_i = 0;
for (int i=0; i<vectorsize; i++) {
int s = 0;
if (r_i < rel->r_k && rel->r_proj[r_i] == i) {
s |= 1;
r_i++;
}
if (w_i < rel->w_k && rel->w_proj[w_i] == i) {
s |= 2;
w_i++;
}
if (s == 0) fprintf(stdout, "-");
else if (s == 1) fprintf(stdout, "r");
else if (s == 2) fprintf(stdout, "w");
else if (s == 3) fprintf(stdout, "+");
}
}
VOID_TASK_0(gc_start)
{
INFO("(GC) Starting garbage collection...\n");
char buf[32];
to_h(getCurrentRSS(), buf);
INFO("(GC) Starting garbage collection... (rss: %s)\n", buf);
}
VOID_TASK_0(gc_end)
{
INFO("(GC) Garbage collection done.\n");
char buf[32];
to_h(getCurrentRSS(), buf);
INFO("(GC) Garbage collection done. (rss: %s)\n", buf);
}
int
main(int argc, char **argv)
{
/**
* Parse command line, set locale, set startup time for INFO messages.
*/
argp_parse(&argp, argc, argv, 0, 0, 0);
setlocale(LC_NUMERIC, "en_US.utf-8");
t_start = wctime();
FILE *f = fopen(model_filename, "r");
if (f == NULL) {
fprintf(stderr, "Cannot open file '%s'!\n", model_filename);
return -1;
}
// Init Lace
lace_init(workers, 1000000); // auto-detect number of workers, use a 1,000,000 size task queue
lace_startup(0, NULL, NULL); // auto-detect program stack, do not use a callback for startup
/**
* Initialize Lace.
*
* First: setup with given number of workers (0 for autodetect) and some large size task queue.
* Second: start all worker threads with default settings.
* Third: setup local variables using the LACE_ME macro.
*/
lace_init(workers, 1000000);
lace_startup(0, NULL, NULL);
LACE_ME;
// Init Sylvan
// Nodes table size: 24 bytes * 2**N_nodes
// Cache table size: 36 bytes * 2**N_cache
// With: N_nodes=25, N_cache=24: 1.3 GB memory
sylvan_set_sizes(1LL<<21, 1LL<<27, 1LL<<20, 1LL<<26);
/**
* Initialize Sylvan.
*
* First: set memory limits
* - 2 GB memory, nodes table twice as big as cache, initial size halved 6x
* (that means it takes 6 garbage collections to get to the maximum nodes&cache size)
* Second: initialize package and subpackages
* Third: add hooks to report garbage collection
*/
sylvan_set_limits(2LL<<30, 1, 6);
sylvan_init_package();
sylvan_set_granularity(6); // granularity 6 is decent default value - 1 means "use cache for every operation"
sylvan_init_bdd();
sylvan_gc_hook_pregc(TASK(gc_start));
sylvan_gc_hook_postgc(TASK(gc_end));
/* Load domain information */
if ((fread(&vector_size, sizeof(int), 1, f) != 1) ||
(fread(&statebits, sizeof(int), 1, f) != 1) ||
(fread(&actionbits, sizeof(int), 1, f) != 1)) {
Abort("Invalid input file!\n");
}
/**
* Read the model from file
*/
bits_per_integer = statebits;
statebits *= vector_size;
/* Open the file */
FILE *f = fopen(model_filename, "r");
if (f == NULL) Abort("Cannot open file '%s'!\n", model_filename);
// Read initial state
/* Read domain data */
if (fread(&vectorsize, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
statebits = (int*)malloc(sizeof(int[vectorsize]));
if (fread(statebits, sizeof(int), vectorsize, f) != (size_t)vectorsize) Abort("Invalid input file!\n");
if (fread(&actionbits, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
totalbits = 0;
for (int i=0; i<vectorsize; i++) totalbits += statebits[i];
/* Read initial state */
set_t states = set_load(f);
// Read transitions
/* Read number of transition relations */
if (fread(&next_count, sizeof(int), 1, f) != 1) Abort("Invalid input file!\n");
next = (rel_t*)malloc(sizeof(rel_t) * next_count);
int i;
for (i=0; i<next_count; i++) {
next[i] = rel_load(f);
}
/* Read transition relations */
for (int i=0; i<next_count; i++) next[i] = rel_load_proj(f);
for (int i=0; i<next_count; i++) rel_load(next[i], f);
/* Done */
/* We ignore the reachable states and action labels that are stored after the relations */
/* Close the file */
fclose(f);
if (print_transition_matrix) {
for (i=0; i<next_count; i++) {
INFO("");
print_matrix(next[i]->variables);
fprintf(stdout, "\n");
/**
* Pre-processing and some statistics reporting
*/
if (strategy == 2 || strategy == 3) {
// for SAT and CHAINING, sort the transition relations (gnome sort because I like gnomes)
int i = 1, j = 2;
rel_t t;
while (i < next_count) {
rel_t *p = &next[i], *q = p-1;
if (sylvan_var((*q)->variables) > sylvan_var((*p)->variables)) {
t = *q;
*q = *p;
*p = t;
if (--i) continue;
}
i = j++;
}
}
// Report statistics
INFO("Read file '%s'\n", model_filename);
INFO("%d integers per state, %d bits per integer, %d transition groups\n", vector_size, bits_per_integer, next_count);
INFO("%d integers per state, %d bits per state, %d transition groups\n", vectorsize, totalbits, next_count);
if (merge_relations) {
BDD prime_variables = sylvan_set_empty();
for (int i=statebits-1; i>=0; i--) {
bdd_refs_push(prime_variables);
prime_variables = sylvan_set_add(prime_variables, i*2+1);
bdd_refs_pop(1);
/* if requested, print the transition matrix */
if (print_transition_matrix) {
for (int i=0; i<next_count; i++) {
INFO(""); // print time prefix
print_matrix_row(next[i]); // print row
fprintf(stdout, "\n"); // print newline
}
}
bdd_refs_push(prime_variables);
/* merge all relations to one big transition relation if requested */
if (merge_relations) {
BDD newvars = sylvan_set_empty();
bdd_refs_pushptr(&newvars);
for (int i=totalbits-1; i>=0; i--) {
newvars = sylvan_set_add(newvars, i*2+1);
newvars = sylvan_set_add(newvars, i*2);
}
INFO("Extending transition relations to full domain.\n");
for (int i=0; i<next_count; i++) {
next[i]->bdd = extend_relation(next[i]->bdd, next[i]->variables);
next[i]->variables = prime_variables;
next[i]->variables = newvars;
}
bdd_refs_popptr(1);
INFO("Taking union of all transition relations.\n");
next[0]->bdd = big_union(0, next_count);
for (int i=1; i<next_count; i++) {
next[i]->bdd = sylvan_false;
next[i]->variables = sylvan_true;
}
next_count = 1;
}
if (report_nodes) {
INFO("BDD nodes:\n");
INFO("Initial states: %zu BDD nodes\n", sylvan_nodecount(states->bdd));
for (i=0; i<next_count; i++) {
for (int i=0; i<next_count; i++) {
INFO("Transition %d: %zu BDD nodes\n", i, sylvan_nodecount(next[i]->bdd));
}
}
print_memory_usage();
#ifdef HAVE_PROFILER
if (profile_filename != NULL) ProfilerStart(profile_filename);
#endif
if (strategy == 1) {
if (strategy == 0) {
double t1 = wctime();
CALL(bfs, states);
double t2 = wctime();
INFO("BFS Time: %f\n", t2-t1);
} else if (strategy == 1) {
double t1 = wctime();
CALL(par, states);
double t2 = wctime();
INFO("PAR Time: %f\n", t2-t1);
} else {
} else if (strategy == 2) {
double t1 = wctime();
CALL(bfs, states);
CALL(sat, states);
double t2 = wctime();
INFO("BFS Time: %f\n", t2-t1);
INFO("SAT Time: %f\n", t2-t1);
} else if (strategy == 3) {
double t1 = wctime();
CALL(chaining, states);
double t2 = wctime();
INFO("CHAINING Time: %f\n", t2-t1);
} else {
Abort("Invalid strategy set?!\n");
}
#ifdef HAVE_PROFILER
if (profile_filename != NULL) ProfilerStop();
#endif
@ -615,6 +925,8 @@ main(int argc, char **argv)
INFO("Final states: %'zu BDD nodes\n", sylvan_nodecount(states->bdd));
}
print_memory_usage();
sylvan_stats_report(stdout);
return 0;

BIN
resources/3rdparty/sylvan/models/anderson.4.bdd

BIN
resources/3rdparty/sylvan/models/anderson.4.ldd

BIN
resources/3rdparty/sylvan/models/anderson.6.ldd

BIN
resources/3rdparty/sylvan/models/anderson.8.ldd

BIN
resources/3rdparty/sylvan/models/at.5.8-rgs.bdd

BIN
resources/3rdparty/sylvan/models/at.6.8-rgs.bdd

BIN
resources/3rdparty/sylvan/models/at.7.8-rgs.bdd

BIN
resources/3rdparty/sylvan/models/bakery.4.bdd

BIN
resources/3rdparty/sylvan/models/bakery.4.ldd

BIN
resources/3rdparty/sylvan/models/bakery.5.ldd

BIN
resources/3rdparty/sylvan/models/bakery.6.ldd

BIN
resources/3rdparty/sylvan/models/bakery.7.ldd

BIN
resources/3rdparty/sylvan/models/blocks.2.ldd

BIN
resources/3rdparty/sylvan/models/blocks.3.ldd

BIN
resources/3rdparty/sylvan/models/blocks.4.ldd

BIN
resources/3rdparty/sylvan/models/collision.4.9-rgs.bdd

BIN
resources/3rdparty/sylvan/models/collision.4.bdd

BIN
resources/3rdparty/sylvan/models/collision.4.ldd

BIN
resources/3rdparty/sylvan/models/collision.5.9-rgs.bdd

BIN
resources/3rdparty/sylvan/models/collision.5.bdd

BIN
resources/3rdparty/sylvan/models/collision.5.ldd

BIN
resources/3rdparty/sylvan/models/collision.6.bdd

BIN
resources/3rdparty/sylvan/models/collision.6.ldd

BIN
resources/3rdparty/sylvan/models/lifts.6.bdd

BIN
resources/3rdparty/sylvan/models/lifts.6.ldd

BIN
resources/3rdparty/sylvan/models/lifts.7.bdd

BIN
resources/3rdparty/sylvan/models/lifts.7.ldd

BIN
resources/3rdparty/sylvan/models/schedule_world.2.8-rgs.bdd

BIN
resources/3rdparty/sylvan/models/schedule_world.2.bdd

BIN
resources/3rdparty/sylvan/models/schedule_world.2.ldd

BIN
resources/3rdparty/sylvan/models/schedule_world.3.8-rgs.bdd

BIN
resources/3rdparty/sylvan/models/schedule_world.3.bdd

BIN
resources/3rdparty/sylvan/models/schedule_world.3.ldd

9
resources/3rdparty/sylvan/src/CMakeLists.txt

@ -37,6 +37,8 @@ set(HEADERS
sylvan_table.h
sylvan_tls.h
storm_wrapper.h
sylvan_bdd_storm.h
sylvan_mtbdd_storm.h
sylvan_storm_rational_function.h
sylvan_storm_rational_number.h
)
@ -47,10 +49,9 @@ option(BUILD_STATIC_LIBS "Enable/disable creation of static libraries" ON)
add_library(sylvan ${SOURCES})
find_package(GMP REQUIRED)
find_package(Hwloc REQUIRED)
include_directories(sylvan ${HWLOC_INCLUDE_DIR} ${GMP_INCLUDE_DIR})
target_link_libraries(sylvan m pthread ${GMP_LIBRARIES} ${HWLOC_LIBRARIES})
include_directories(sylvan ${GMP_INCLUDE_DIR})
target_link_libraries(sylvan m pthread ${GMP_LIBRARIES})
if(UNIX AND NOT APPLE)
target_link_libraries(sylvan rt)
@ -60,12 +61,10 @@ option(SYLVAN_STATS "Collect statistics" OFF)
if(SYLVAN_STATS)
set_target_properties(sylvan PROPERTIES COMPILE_DEFINITIONS "SYLVAN_STATS")
endif()
set_target_properties(sylvan PROPERTIES COMPILE_DEFINITIONS "STORM_SILENCE_WARNINGS")
install(TARGETS sylvan DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES ${HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
# MODIFICATIONS NEEDED MADE FOR STORM
# We need to make sure that the binary is put into a folder that is independent of the

2
resources/3rdparty/sylvan/src/avl.h

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

406
resources/3rdparty/sylvan/src/lace.c

@ -15,6 +15,7 @@
* limitations under the License.
*/
#define _GNU_SOURCE
#include <errno.h> // for errno
#include <sched.h> // for sched_getaffinity
#include <stdio.h> // for fprintf
@ -26,28 +27,46 @@
#include <unistd.h>
#include <assert.h>
// work around for missing MAP_ANONYMOUS definition in sys/mman.h on
// older OS X versions
#if !(defined MAP_ANONYMOUS) && defined MAP_ANON
#define MAP_ANONYMOUS MAP_ANON
#endif
#include <lace.h>
#include <hwloc.h>
// public Worker data
static Worker **workers = NULL;
static size_t default_stacksize = 0; // set by lace_init
static size_t default_dqsize = 100000;
#if LACE_USE_HWLOC
#include <hwloc.h>
/**
* HWLOC information
*/
static hwloc_topology_t topo;
static unsigned int n_nodes, n_cores, n_pus;
#endif
/**
* (public) Worker data
*/
static Worker **workers = NULL;
/**
* Default sizes for program stack and task deque
*/
static size_t default_stacksize = 0; // 0 means "set by lace_init"
static size_t default_dqsize = 100000;
/**
* Verbosity flag, set with lace_set_verbosity
*/
static int verbosity = 0;
static int n_workers = 0;
static int enabled_workers = 0;
/**
* Number of workers and number of enabled/active workers
*/
static unsigned int n_workers = 0;
static unsigned int enabled_workers = 0;
/**
* Datastructure of the task deque etc for each worker.
* - first public cachelines (accessible via global "workers" variable)
* - then private cachelines
* - then the deque array
*/
typedef struct {
Worker worker_public;
char pad1[PAD(sizeof(Worker), LINE_SIZE)];
@ -56,26 +75,51 @@ typedef struct {
Task deque[];
} worker_data;
/**
* (Secret) holds pointers to the memory block allocated for each worker
*/
static worker_data **workers_memory = NULL;
/**
* Number of bytes allocated for each worker's worker data.
*/
static size_t workers_memory_size = 0;
// private Worker data (just for stats at end )
/**
* (Secret) holds pointer to private Worker data, just for stats collection at end
*/
static WorkerP **workers_p;
// set to 0 when quitting
/**
* Flag to signal all workers to quit.
*/
static int lace_quits = 0;
// for storing private Worker data
/**
* Thread-specific mechanism to access current worker data
*/
#ifdef __linux__ // use gcc thread-local storage (i.e. __thread variables)
static __thread WorkerP *current_worker;
#else
static pthread_key_t worker_key;
#endif
/**
* worker_attr used for creating threads
* - initialized by lace_init
* - used by lace_spawn_worker
*/
static pthread_attr_t worker_attr;
/**
* The condition/mutex pair for when the root thread sleeps until the end of the program
*/
static pthread_cond_t wait_until_done = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t wait_until_done_mutex = PTHREAD_MUTEX_INITIALIZER;
/**
* Data structure that contains the stack and stack size for each worker.
*/
struct lace_worker_init
{
void* stack;
@ -84,8 +128,14 @@ struct lace_worker_init
static struct lace_worker_init *workers_init;
/**
* Global newframe variable used for the implementation of NEWFRAME and TOGETHER
*/
lace_newframe_t lace_newframe;
/**
* Get the private Worker data of the current thread
*/
WorkerP*
lace_get_worker()
{
@ -96,14 +146,20 @@ lace_get_worker()
#endif
}
/**
* Find the head of the task deque, using the given private Worker data
*/
Task*
lace_get_head(WorkerP *self)
{
Task *dq = self->dq;
/* First check the first tasks linearly */
if (dq[0].thief == 0) return dq;
if (dq[1].thief == 0) return dq+1;
if (dq[2].thief == 0) return dq+2;
/* Then fast search for a low/high bound using powers of 2: 4, 8, 16... */
size_t low = 2;
size_t high = self->end - self->dq;
@ -118,6 +174,7 @@ lace_get_head(WorkerP *self)
}
}
/* Finally zoom in using binary search */
while (low < high) {
size_t mid = low + (high-low)/2;
if (dq[mid].thief == 0) high = mid;
@ -127,22 +184,27 @@ lace_get_head(WorkerP *self)
return dq+low;
}
size_t
/**
* Get the number of workers
*/
unsigned int
lace_workers()
{
return n_workers;
}
/**
* Get the default stack size (or 0 for automatically determine)
*/
size_t
lace_default_stacksize()
{
return default_stacksize;
}
#ifndef cas
#define cas(ptr, old, new) (__sync_bool_compare_and_swap((ptr),(old),(new)))
#endif
/**
* If we are collecting PIE times, then we need some helper functions.
*/
#if LACE_PIE_TIMES
static uint64_t count_at_start, count_at_end;
static long long unsigned us_elapsed_timer;
@ -169,7 +231,9 @@ us_elapsed(void)
}
#endif
/* Barrier */
/**
* Lace barrier implementation, that synchronizes on all currently enabled workers.
*/
typedef struct {
volatile int __attribute__((aligned(LINE_SIZE))) count;
volatile int __attribute__((aligned(LINE_SIZE))) leaving;
@ -178,11 +242,14 @@ typedef struct {
barrier_t lace_bar;
/**
* Enter the Lace barrier and wait until all workers have entered the Lace barrier.
*/
void
lace_barrier()
{
int wait = lace_bar.wait;
if (enabled_workers == __sync_add_and_fetch(&lace_bar.count, 1)) {
if ((int)enabled_workers == __sync_add_and_fetch(&lace_bar.count, 1)) {
lace_bar.count = 0;
lace_bar.leaving = enabled_workers;
lace_bar.wait = 1 - wait; // flip wait
@ -193,12 +260,18 @@ lace_barrier()
__sync_add_and_fetch(&lace_bar.leaving, -1);
}
/**
* Initialize the Lace barrier
*/
static void
lace_barrier_init()
{
memset(&lace_bar, 0, sizeof(barrier_t));
}
/**
* Destroy the Lace barrier (just wait until all are exited)
*/
static void
lace_barrier_destroy()
{
@ -206,9 +279,13 @@ lace_barrier_destroy()
while (lace_bar.leaving != 0) continue;
}
static void
/**
* For debugging purposes, check if memory is allocated on the correct memory nodes.
*/
static void __attribute__((unused))
lace_check_memory(void)
{
#if LACE_USE_HWLOC
// get our current worker
WorkerP *w = lace_get_worker();
void* mem = workers_memory[w->worker];
@ -229,14 +306,10 @@ lace_check_memory(void)
hwloc_membind_policy_t policy;
int res = hwloc_get_area_membind_nodeset(topo, mem, sizeof(worker_data), memlocation, &policy, HWLOC_MEMBIND_STRICT);
if (res == -1) {
#ifndef STORM_SILENCE_WARNINGS
fprintf(stderr, "Lace warning: hwloc_get_area_membind_nodeset returned -1!\n");
#endif
}
if (policy != HWLOC_MEMBIND_BIND) {
#ifndef STORM_SILENCE_WARNINGS
fprintf(stderr, "Lace warning: Lace worker memory not bound with BIND policy!\n");
#endif
}
#endif
@ -258,22 +331,27 @@ lace_check_memory(void)
hwloc_bitmap_free(cpuset);
hwloc_bitmap_free(cpunodes);
hwloc_bitmap_free(memlocation);
#endif
}
WorkerP *
lace_init_worker(int worker)
void
lace_pin_worker(void)
{
// Get our core
#if LACE_USE_HWLOC
// Get our worker
unsigned int worker = lace_get_worker()->worker;
// Get our core (hwloc object)
hwloc_obj_t pu = hwloc_get_obj_by_type(topo, HWLOC_OBJ_CORE, worker % n_cores);
// Get our copy of the bitmap
hwloc_cpuset_t bmp = hwloc_bitmap_dup(pu->cpuset);
// Get number of PUs in set
// Get number of PUs in bitmap
int n = -1, count=0;
while ((n=hwloc_bitmap_next(bmp, n)) != -1) count++;
// Check if we actually have logical processors
// Check if we actually have any logical processors
if (count == 0) {
fprintf(stderr, "Lace error: trying to pin a worker on an empty core?\n");
exit(-1);
@ -293,18 +371,46 @@ lace_init_worker(int worker)
// Pin our thread...
if (hwloc_set_cpubind(topo, bmp, HWLOC_CPUBIND_THREAD) == -1) {
#ifndef STORM_SILENCE_WARNINGS
fprintf(stderr, "Lace warning: hwloc_set_cpubind returned -1!\n");
#endif
}
// Free allocated memory
// Free our copy of the bitmap
hwloc_bitmap_free(bmp);
// Get allocated memory
Worker *wt = &workers_memory[worker]->worker_public;
WorkerP *w = &workers_memory[worker]->worker_private;
// Pin the memory area (using the appropriate hwloc function)
#ifdef HWLOC_MEMBIND_BYNODESET
int res = hwloc_set_area_membind(topo, workers_memory[worker], workers_memory_size, pu->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_STRICT | HWLOC_MEMBIND_MIGRATE | HWLOC_MEMBIND_BYNODESET);
#else
int res = hwloc_set_area_membind_nodeset(topo, workers_memory[worker], workers_memory_size, pu->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_STRICT | HWLOC_MEMBIND_MIGRATE);
#endif
if (res != 0) {
fprintf(stderr, "Lace error: Unable to bind worker memory to node!\n");
}
// Check if everything is on the correct node
lace_check_memory();
#endif
}
void
lace_init_worker(unsigned int worker)
{
// Allocate our memory
workers_memory[worker] = mmap(NULL, workers_memory_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (workers_memory[worker] == MAP_FAILED) {
fprintf(stderr, "Lace error: Unable to allocate memory for the Lace worker!\n");
exit(1);
}
// Set pointers
Worker *wt = workers[worker] = &workers_memory[worker]->worker_public;
WorkerP *w = workers_p[worker] = &workers_memory[worker]->worker_private;
w->dq = workers_memory[worker]->deque;
#ifdef __linux__
current_worker = w;
#else
pthread_setspecific(worker_key, w);
#endif
// Initialize public worker data
wt->dq = w->dq;
@ -318,7 +424,11 @@ lace_init_worker(int worker)
w->split = w->dq;
w->allstolen = 0;
w->worker = worker;
#if LACE_USE_HWLOC
w->pu = worker % n_cores;
#else
w->pu = -1;
#endif
w->enabled = 1;
if (workers_init[worker].stack != 0) {
w->stack_trigger = ((size_t)workers_init[worker].stack) + workers_init[worker].stacksize/20;
@ -328,20 +438,10 @@ lace_init_worker(int worker)
w->rng = (((uint64_t)rand())<<32 | rand());
#if LACE_COUNT_EVENTS
// Reset counters
// Initialize counters
{ int k; for (k=0; k<CTR_MAX; k++) w->ctr[k] = 0; }
#endif
// Set pointers
#ifdef __linux__
current_worker = w;
#else
pthread_setspecific(worker_key, w);
#endif
// Check if everything is on the correct node
lace_check_memory();
// Synchronize with others
lace_barrier();
@ -350,9 +450,14 @@ lace_init_worker(int worker)
w->level = 0;
#endif
return w;
if (worker == 0) {
lace_time_event(w, 1);
}
}
/**
* Some OSX systems do not implement pthread_barrier_t, so we provide an implementation here.
*/
#if defined(__APPLE__) && !defined(pthread_barrier_t)
typedef int pthread_barrierattr_t;
@ -442,13 +547,13 @@ lace_resume()
}
/**
* With set_workers, all workers 0..(N-1) are enabled and N..max are disabled.
* You can never disable the current worker or reduce the number of workers below 1.
* Disable worker <worker>.
* If the given worker is the current worker, this function does nothing.
*/
void
lace_disable_worker(int worker)
lace_disable_worker(unsigned int worker)
{
int self = lace_get_worker()->worker;
unsigned int self = lace_get_worker()->worker;
if (worker == self) return;
if (workers_p[worker]->enabled == 1) {
workers_p[worker]->enabled = 0;
@ -456,10 +561,14 @@ lace_disable_worker(int worker)
}
}
/**
* Enable worker <worker>.
* If the given worker is the current worker, this function does nothing.
*/
void
lace_enable_worker(int worker)
lace_enable_worker(unsigned int worker)
{
int self = lace_get_worker()->worker;
unsigned int self = lace_get_worker()->worker;
if (worker == self) return;
if (workers_p[worker]->enabled == 0) {
workers_p[worker]->enabled = 1;
@ -467,26 +576,38 @@ lace_enable_worker(int worker)
}
}
/**
* Enables all workers 0..(N-1) and disables workers N..max.
* This function _should_ be called by worker 0.
* Ignores the current worker if >= N.
* The number of workers is never reduces below 1.
*/
void
lace_set_workers(int workercount)
lace_set_workers(unsigned int workercount)
{
if (workercount < 1) workercount = 1;
if (workercount > n_workers) workercount = n_workers;
enabled_workers = workercount;
int self = lace_get_worker()->worker;
unsigned int self = lace_get_worker()->worker;
if (self >= workercount) workercount--;
int i;
for (i=0; i<n_workers; i++) {
for (unsigned int i=0; i<n_workers; i++) {
workers_p[i]->enabled = (i < workercount || i == self) ? 1 : 0;
}
}
int
/**
* Get the number of currently enabled workers.
*/
unsigned int
lace_enabled_workers()
{
return enabled_workers;
}
/**
* Simple random number generated (like rand) using the given seed.
* (Used for thread-specific (scalable) random number generation.
*/
static inline uint32_t
rng(uint32_t *seed, int max)
{
@ -500,6 +621,9 @@ rng(uint32_t *seed, int max)
return next % max;
}
/**
* (Try to) steal and execute a task from a random worker.
*/
VOID_TASK_0(lace_steal_random)
{
Worker *victim = workers[(__lace_worker->worker + 1 + rng(&__lace_worker->seed, n_workers-1)) % n_workers];
@ -515,26 +639,19 @@ VOID_TASK_0(lace_steal_random)
}
}
VOID_TASK_1(lace_steal_random_loop, int*, quit)
{
while(!(*(volatile int*)quit)) {
lace_steal_random();
if (must_suspend) {
lace_barrier();
do {
pthread_barrier_wait(&suspend_barrier);
} while (__lace_worker->enabled == 0);
}
}
}
/**
* Variable to hold the main/root task.
*/
static lace_startup_cb main_cb;
/**
* Wrapper around the main/root task.
*/
static void*
lace_main_wrapper(void *arg)
{
lace_init_main();
lace_init_worker(0);
lace_pin_worker();
LACE_ME;
WRAP(main_cb, arg);
lace_exit();
@ -547,7 +664,10 @@ lace_main_wrapper(void *arg)
return NULL;
}
#define lace_steal_loop(quit) CALL(lace_steal_loop, quit)
/**
* Main Lace worker implementation.
* Steal from random victims until "quit" is set.
*/
VOID_TASK_1(lace_steal_loop, int*, quit)
{
// Determine who I am
@ -599,12 +719,12 @@ VOID_TASK_1(lace_steal_loop, int*, quit)
/**
* Initialize worker 0.
* Calls lace_init_worker and then signals the event.
*/
void
lace_init_main()
{
WorkerP * __attribute__((unused)) __lace_worker = lace_init_worker(0);
lace_time_event(__lace_worker, 1);
lace_init_worker(0);
}
/**
@ -614,16 +734,13 @@ lace_init_main()
* For worker 0, use lace_init_main
*/
void
lace_run_worker(int worker)
lace_run_worker(void)
{
// Initialize local datastructure
WorkerP *__lace_worker = lace_init_worker(worker);
Task *__lace_dq_head = __lace_worker->dq;
// Steal for a while
lace_steal_loop(&lace_quits);
// Run the steal loop
LACE_ME;
CALL(lace_steal_loop, &lace_quits);
// Time the quit event
// Time worker exit event
lace_time_event(__lace_worker, 9);
// Synchronize with lace_exit
@ -633,7 +750,10 @@ lace_run_worker(int worker)
static void*
lace_default_worker_thread(void* arg)
{
lace_run_worker((int)(size_t)arg);
int worker = (int)(size_t)arg;
lace_init_worker(worker);
lace_pin_worker();
lace_run_worker();
return NULL;
}
@ -646,6 +766,7 @@ lace_spawn_worker(int worker, size_t stacksize, void* (*fun)(void*), void* arg)
size_t pagesize = sysconf(_SC_PAGESIZE);
stacksize = (stacksize + pagesize - 1) & ~(pagesize - 1); // ceil(stacksize, pagesize)
#if LACE_USE_HWLOC
// Get our logical processor
hwloc_obj_t pu = hwloc_get_obj_by_type(topo, HWLOC_OBJ_PU, worker % n_pus);
@ -655,6 +776,9 @@ lace_spawn_worker(int worker, size_t stacksize, void* (*fun)(void*), void* arg)
fprintf(stderr, "Lace error: Unable to allocate memory for the pthread stack!\n");
exit(1);
}
#else
void *stack_location = mmap(NULL, stacksize+ pagesize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
#endif
if (0 != mprotect(stack_location, pagesize, PROT_NONE)) {
fprintf(stderr, "Lace error: Unable to protect the allocated program stack with a guard page!\n");
@ -679,22 +803,23 @@ lace_spawn_worker(int worker, size_t stacksize, void* (*fun)(void*), void* arg)
return res;
}
static int
get_cpu_count()
{
int count = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_PU);
return count < 1 ? 1 : count;
}
/**
* Set the verbosity of Lace.
*/
void
lace_set_verbosity(int level)
{
verbosity = level;
}
/**
* Initialize Lace for work-stealing with <n> workers, where
* each worker gets a task deque with <dqsize> elements.
*/
void
lace_init(int _n_workers, size_t dqsize)
lace_init(unsigned int _n_workers, size_t dqsize)
{
#if LACE_USE_HWLOC
// Initialize topology and information about cpus
hwloc_topology_init(&topo);
hwloc_topology_load(topo);
@ -702,15 +827,23 @@ lace_init(int _n_workers, size_t dqsize)
n_nodes = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_NODE);
n_cores = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_CORE);
n_pus = hwloc_get_nbobjs_by_type(topo, HWLOC_OBJ_PU);
#elif defined(sched_getaffinity)
cpu_set_t cs;
CPU_ZERO(&cs);
sched_getaffinity(0, sizeof(cs), &cs);
unsigned int n_pus = CPU_COUNT(&cs);
#else
unsigned int n_pus = sysconf(_SC_NPROCESSORS_ONLN);
#endif
// Initialize globals
n_workers = _n_workers;
if (n_workers == 0) n_workers = get_cpu_count();
n_workers = _n_workers == 0 ? n_pus : _n_workers;
enabled_workers = n_workers;
if (dqsize != 0) default_dqsize = dqsize;
else dqsize = default_dqsize;
lace_quits = 0;
// Create barrier for all workers
// Initialize Lace barrier
lace_barrier_init();
// Create suspend barrier
@ -724,37 +857,9 @@ lace_init(int _n_workers, size_t dqsize)
exit(1);
}
// Allocate memory for each worker
// Compute memory size for each worker
workers_memory_size = sizeof(worker_data) + sizeof(Task) * dqsize;
for (int i=0; i<n_workers; i++) {
workers_memory[i] = mmap(NULL, workers_memory_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (workers_memory[i] == MAP_FAILED) {
fprintf(stderr, "Lace error: Unable to allocate memory for the Lace worker!\n");
exit(1);
}
workers[i] = &workers_memory[i]->worker_public;
workers_p[i] = &workers_memory[i]->worker_private;
}
// Pin allocated memory of each worker
for (int i=0; i<n_workers; i++) {
// Get our core
hwloc_obj_t core = hwloc_get_obj_by_type(topo, HWLOC_OBJ_CORE, i % n_cores);
// Pin the memory area
#ifdef HWLOC_MEMBIND_BYNODESET
int res = hwloc_set_area_membind(topo, workers_memory[i], workers_memory_size, core->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_STRICT | HWLOC_MEMBIND_MIGRATE | HWLOC_MEMBIND_BYNODESET);
#else
int res = hwloc_set_area_membind_nodeset(topo, workers_memory[i], workers_memory_size, core->nodeset, HWLOC_MEMBIND_BIND, HWLOC_MEMBIND_STRICT | HWLOC_MEMBIND_MIGRATE);
#endif
if (res != 0) {
#ifndef STORM_SILENCE_WARNINGS
fprintf(stderr, "Lace error: Unable to bind worker memory to node!\n");
#endif
}
}
// Create pthread key
#ifndef __linux__
pthread_key_create(&worker_key, NULL);
@ -773,7 +878,11 @@ lace_init(int _n_workers, size_t dqsize)
}
if (verbosity) {
#if LACE_USE_HWLOC
fprintf(stderr, "Initializing Lace, %u nodes, %u cores, %u logical processors, %d workers.\n", n_nodes, n_cores, n_pus, n_workers);
#else
fprintf(stderr, "Initializing Lace, %u available cores, %d workers.\n", n_pus, n_workers);
#endif
}
// Prepare lace_init structure
@ -788,11 +897,18 @@ lace_init(int _n_workers, size_t dqsize)
#endif
}
/**
* Start the worker threads.
* If cb is set, then the current thread is suspended and Worker 0 is a new thread that starts with
* the given cb(arg) as the root task.
* If cb is not set, then the current thread is Worker 0 and this function returns.
*/
void
lace_startup(size_t stacksize, lace_startup_cb cb, void *arg)
{
if (stacksize == 0) stacksize = default_stacksize;
/* Report startup if verbose */
if (verbosity) {
if (cb != 0) {
fprintf(stderr, "Lace startup, creating %d worker threads with program stack %zu bytes.\n", n_workers, stacksize);
@ -803,22 +919,21 @@ lace_startup(size_t stacksize, lace_startup_cb cb, void *arg)
}
}
/* Spawn workers */
int i;
for (i=1; i<n_workers; i++) lace_spawn_worker(i, stacksize, 0, 0);
/* Spawn all other workers */
for (unsigned int i=1; i<n_workers; i++) lace_spawn_worker(i, stacksize, 0, 0);
if (cb != 0) {
/* If cb set, spawn worker 0 */
main_cb = cb;
lace_spawn_worker(0, stacksize, lace_main_wrapper, arg);
// Suspend this thread until cb returns
/* Suspend this thread until cb returns */
pthread_mutex_lock(&wait_until_done_mutex);
if (lace_quits == 0) pthread_cond_wait(&wait_until_done, &wait_until_done_mutex);
pthread_mutex_unlock(&wait_until_done_mutex);
} else {
// use this thread as worker and return control
/* If cb not set, use current thread as worker 0 */
lace_init_worker(0);
lace_time_event(lace_get_worker(), 1);
}
}
@ -826,6 +941,9 @@ lace_startup(size_t stacksize, lace_startup_cb cb, void *arg)
static uint64_t ctr_all[CTR_MAX];
#endif
/**
* Reset the counters of Lace.
*/
void
lace_count_reset()
{
@ -851,6 +969,9 @@ lace_count_reset()
#endif
}
/**
* Report counters to the given file.
*/
void
lace_count_report_file(FILE *file)
{
@ -948,11 +1069,15 @@ lace_count_report_file(FILE *file)
(void)file;
}
/**
* End Lace. All disabled threads are re-enabled, and then all Workers are signaled to quit.
* This function waits until all threads are done, then returns.
*/
void lace_exit()
{
lace_time_event(lace_get_worker(), 2);
// first suspend all other threads
// first suspend all enabled threads
lace_suspend();
// now enable all threads and tell them to quit
@ -1030,7 +1155,7 @@ VOID_TASK_2(lace_together_helper, Task*, t, volatile int*, finished)
for (;;) {
int f = *finished;
if (cas(finished, f, f-1)) break;
if (__sync_bool_compare_and_swap(finished, f, f-1)) break;
}
while (*finished != 0) STEAL_RANDOM();
@ -1086,7 +1211,7 @@ lace_do_together(WorkerP *__lace_worker, Task *__lace_dq_head, Task *t)
t2->d.args.arg_1 = t;
t2->d.args.arg_2 = &done;
while (!cas(&lace_newframe.t, 0, &_t2)) lace_yield(__lace_worker, __lace_dq_head);
while (!__sync_bool_compare_and_swap(&lace_newframe.t, 0, &_t2)) lace_yield(__lace_worker, __lace_dq_head);
lace_sync_and_exec(__lace_worker, __lace_dq_head, &_t2);
}
@ -1113,10 +1238,13 @@ lace_do_newframe(WorkerP *__lace_worker, Task *__lace_dq_head, Task *t)
compiler_barrier();
while (!cas(&lace_newframe.t, 0, &_s)) lace_yield(__lace_worker, __lace_dq_head);
while (!__sync_bool_compare_and_swap(&lace_newframe.t, 0, &_s)) lace_yield(__lace_worker, __lace_dq_head);
lace_sync_and_exec(__lace_worker, __lace_dq_head, &_t2);
}
/**
* Called by _SPAWN functions when the Task stack is full.
*/
void
lace_abort_stack_overflow(void)
{

424
resources/3rdparty/sylvan/src/lace.h

@ -23,40 +23,281 @@
#ifndef __LACE_H__
#define __LACE_H__
#ifdef __has_include
# if __has_include("lace_config.h")
# include <lace_config.h>
# else
# define LACE_PIE_TIMES 0
# define LACE_COUNT_TASKS 0
# define LACE_COUNT_STEALS 0
# define LACE_COUNT_SPLITS 0
# define LACE_USE_HWLOC 0
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Some flags */
/**
* Using Lace.
*
* Optionally set the verbosity level with lace_set_verbosity.
* Then call lace_init to initialize the system.
* - lace_init(n_workers, deque_size);
* set both parameters to 0 for reasonable defaults, using all available cores.
*
* You can create Worker threads yourself or let Lace create threads with lace_startup.
*
* When creating threads yourself, call the following functions:
* - lace_init_worker to allocate and initialize the worker data structures
* this method returns when all workers have called lace_init_worker
* - lace_pin_worker (optional) to pin the thread and memory to a core
* The main worker can now start its root task. All other workers:
* - lace_run_worker to perform work-stealing until the main worker calls lace_exit
*
* When letting Lace create threads with lace_startup
* - Call lace_startup with a callback to create N threads.
* Returns after the callback has returned and all created threads are destroyed
* - Call lace_startup without a callback to create N-1 threads.
* Returns control to the caller. When lace_exit is called, all created threads are terminated.
*/
#ifndef LACE_DEBUG_PROGRAMSTACK /* Write to stderr when 95% program stack reached */
#define LACE_DEBUG_PROGRAMSTACK 0
#endif
/**
* Type definitions used in the functions below.
* - WorkerP contains the (private) Worker data
* - Task contains a single Task
*/
typedef struct _WorkerP WorkerP;
typedef struct _Task Task;
#ifndef LACE_LEAP_RANDOM /* Use random leaping when leapfrogging fails */
#define LACE_LEAP_RANDOM 0
#endif
/**
* The macro LACE_TYPEDEF_CB(typedefname, taskname, parametertypes) defines
* a Task for use as a callback function.
*/
#define LACE_TYPEDEF_CB(t, f, ...) typedef t (*f)(WorkerP *, Task *, ##__VA_ARGS__);
#ifndef LACE_PIE_TIMES /* Record time spent stealing and leapfrogging */
#define LACE_PIE_TIMES 0
#endif
/**
* The lace_startup_cb type for a void Task with one void* parameter.
*/
LACE_TYPEDEF_CB(void, lace_startup_cb, void*);
#ifndef LACE_COUNT_TASKS /* Count number of tasks executed */
#define LACE_COUNT_TASKS 0
#endif
/**
* Set verbosity level (0 = no startup messages, 1 = startup messages)
* Default level: 0
*/
void lace_set_verbosity(int level);
/**
* Initialize Lace for <n_workers> workers with a deque size of <dqsize> per worker.
* If <n_workers> is set to 0, automatically detects available cores.
* If <dqsize> is est to 0, uses a reasonable default value.
*/
void lace_init(unsigned int n_workers, size_t dqsize);
/**
* Let Lace create worker threads.
* If <stacksize> is set to 0, uses a reaonable default value.
* If cb, arg are set to 0, then the current thread is initialized as the main Worker (Worker 0).
*
* If cb,arg are set, then the current thread is suspended. A new thread is made for Worker 0 and
* the task cb with paremeter arg is called; when cb returns, Lace is exited automatically.
*/
void lace_startup(size_t stacksize, lace_startup_cb, void* arg);
/**
* Initialize worker <worker>, allocating memory.
* If <worker> is 0, then the current thread is the main worker.
*/
void lace_init_worker(unsigned int worker);
/**
* Use hwloc to pin the current thread to a CPU and its allocated memory in the closest domain.
* Call this *after* lace_init_worker and *before* lace_run_worker.
*/
void lace_pin_worker(void);
/**
* Perform work-stealing until lace_exit is called.
*/
void lace_run_worker(void);
/**
* Steal a random task.
*/
#define lace_steal_random() CALL(lace_steal_random)
void lace_steal_random_CALL(WorkerP*, Task*);
/**
* Enter the Lace barrier. (all active workers must enter it before we can continue)
*/
void lace_barrier();
/**
* Suspend all workers except the current worker.
* May only be used when all other workers are idle.
*/
void lace_suspend();
/**
* Resume all workers.
*/
void lace_resume();
/**
* When all other workers are suspended, some workers can be disabled using the following functions.
* With set_workers, all workers 0..(N-1) are enabled and N..max are disabled.
* You can never disable the current worker or reduce the number of workers below 1.
* You cannot add workers.
*/
void lace_set_workers(unsigned int workercount);
/**
* Disable a suspended worker.
*/
void lace_disable_worker(unsigned int worker);
/**
* Enable a suspended worker.
*/
void lace_enable_worker(unsigned int worker);
/**
* Retrieve the number of enabled/active workers.
*/
unsigned int lace_enabled_workers();
/**
* Retrieve the number of Lace workers
*/
unsigned int lace_workers();
/**
* Retrieve the default program stack size
*/
size_t lace_default_stacksize();
/**
* Retrieve the current worker data.
*/
WorkerP *lace_get_worker();
/**
* Retrieve the current head of the deque
*/
Task *lace_get_head(WorkerP *);
/**
* Exit Lace.
* This function is automatically called when lace_startup is called with a callback.
* This function must be called to exit Lace when lace_startup is called without a callback.
*/
void lace_exit();
/**
* Create a pointer to a Tasks main function.
*/
#define TASK(f) ( f##_CALL )
/**
* Call a Tasks implementation (adds Lace variables to call)
*/
#define WRAP(f, ...) ( f((WorkerP *)__lace_worker, (Task *)__lace_dq_head, ##__VA_ARGS__) )
/**
* Sync a task.
*/
#define SYNC(f) ( __lace_dq_head--, WRAP(f##_SYNC) )
/**
* Sync a task, but if the task is not stolen, then do not execute it.
*/
#define DROP() ( __lace_dq_head--, WRAP(lace_drop) )
/**
* Spawn a task.
*/
#define SPAWN(f, ...) ( WRAP(f##_SPAWN, ##__VA_ARGS__), __lace_dq_head++ )
/**
* Directly execute a task.
*/
#define CALL(f, ...) ( WRAP(f##_CALL, ##__VA_ARGS__) )
/**
* Signal all workers to interrupt their current tasks and instead perform (a personal copy of) the given task.
*/
#define TOGETHER(f, ...) ( WRAP(f##_TOGETHER, ##__VA_ARGS__) )
/**
* Signal all workers to interrupt their current tasks and help the current thread with the given task.
*/
#define NEWFRAME(f, ...) ( WRAP(f##_NEWFRAME, ##__VA_ARGS__) )
/**
* (Try to) steal a task from a random worker.
*/
#define STEAL_RANDOM() ( CALL(lace_steal_random) )
/**
* Get the current worker id.
*/
#define LACE_WORKER_ID ( __lace_worker->worker )
/**
* Get the core where the current worker is pinned.
*/
#define LACE_WORKER_PU ( __lace_worker->pu )
/**
* Initialize local variables __lace_worker and __lace_dq_head which are required for most Lace functionality.
*/
#define LACE_ME WorkerP * __attribute__((unused)) __lace_worker = lace_get_worker(); Task * __attribute__((unused)) __lace_dq_head = lace_get_head(__lace_worker);
#ifndef LACE_COUNT_STEALS /* Count number of steals performed */
#define LACE_COUNT_STEALS 0
/**
* Check if current tasks must be interrupted, and if so, interrupt.
*/
void lace_yield(WorkerP *__lace_worker, Task *__lace_dq_head);
#define YIELD_NEWFRAME() { if (unlikely((*(Task* volatile *)&lace_newframe.t) != NULL)) lace_yield(__lace_worker, __lace_dq_head); }
/**
* True if the given task is stolen, False otherwise.
*/
#define TASK_IS_STOLEN(t) ((size_t)t->thief > 1)
/**
* True if the given task is completed, False otherwise.
*/
#define TASK_IS_COMPLETED(t) ((size_t)t->thief == 2)
/**
* Retrieves a pointer to the result of the given task.
*/
#define TASK_RESULT(t) (&t->d[0])
/**
* Compute a random number, thread-local (so scalable)
*/
#define LACE_TRNG (__lace_worker->rng = 2862933555777941757ULL * __lace_worker->rng + 3037000493ULL)
/* Some flags that influence Lace behavior */
#ifndef LACE_DEBUG_PROGRAMSTACK /* Write to stderr when 95% program stack reached */
#define LACE_DEBUG_PROGRAMSTACK 0
#endif
#ifndef LACE_COUNT_SPLITS /* Count number of times the split point is moved */
#define LACE_COUNT_SPLITS 0
#ifndef LACE_LEAP_RANDOM /* Use random leaping when leapfrogging fails */
#define LACE_LEAP_RANDOM 1
#endif
#ifndef LACE_COUNT_EVENTS
#define LACE_COUNT_EVENTS (LACE_PIE_TIMES || LACE_COUNT_TASKS || LACE_COUNT_STEALS || LACE_COUNT_SPLITS)
#endif
/**
* Now follows the implementation of Lace
*/
/* Typical cacheline size of system architectures */
#ifndef LINE_SIZE
#define LINE_SIZE 64
@ -167,10 +408,6 @@ typedef enum {
CTR_MAX
} CTR_index;
struct _WorkerP;
struct _Worker;
struct _Task;
#define THIEF_EMPTY ((struct _Worker*)0x0)
#define THIEF_TASK ((struct _Worker*)0x1)
#define THIEF_COMPLETED ((struct _Worker*)0x2)
@ -215,7 +452,7 @@ typedef struct _WorkerP {
size_t stack_trigger; // for stack overflow detection
uint64_t rng; // my random seed (for lace_trng)
uint32_t seed; // my random seed (for lace_steal_random)
int16_t worker; // what is my worker id?
uint16_t worker; // what is my worker id?
uint8_t allstolen; // my allstolen
volatile int8_t enabled; // if this worker is enabled
@ -228,145 +465,10 @@ typedef struct _WorkerP {
int16_t pu; // my pu (for HWLOC)
} WorkerP;
#define LACE_TYPEDEF_CB(t, f, ...) typedef t (*f)(WorkerP *, Task *, ##__VA_ARGS__);
LACE_TYPEDEF_CB(void, lace_startup_cb, void*);
/**
* Using Lace.
*
* Optionally set the verbosity level with lace_set_verbosity.
* Call lace_init to allocate all data structures.
*
* You can create threads yourself or let Lace create threads with lace_startup.
*
* When creating threads yourself:
* - call lace_init_main for worker 0
* this method returns when all other workers have started
* - call lace_run_worker for all other workers
* workers perform work-stealing until worker 0 calls lace_exit
*
* When letting Lace create threads with lace_startup
* - calling with startup callback creates N threads and returns
* after the callback has returned, and all created threads are destroyed
* - calling without a startup callback creates N-1 threads and returns
* control to the caller. When lace_exit is called, all created threads are terminated.
*/
/**
* Set verbosity level (0 = no startup messages, 1 = startup messages)
* Default level: 0
*/
void lace_set_verbosity(int level);
/**
* Initialize master structures for Lace with <n_workers> workers
* and default deque size of <dqsize>.
* Does not create new threads.
* Tries to detect number of cpus, if n_workers equals 0.
*/
void lace_init(int n_workers, size_t dqsize);
/**
* After lace_init, start all worker threads.
* If cb,arg are set, suspend this thread, call cb(arg) in a new thread
* and exit Lace upon return
* Otherwise, the current thread is initialized as worker 0.
*/
void lace_startup(size_t stacksize, lace_startup_cb, void* arg);
/**
* Initialize worker 0. This method returns when all other workers are initialized
* (using lace_run_worker).
*
* When done, run lace_exit so all worker threads return from lace_run_worker.
*/
void lace_init_main();
/**
* Initialize the current thread as the Lace thread of worker <worker>, and perform
* work-stealing until lace_exit is called.
*
* For worker 0, call lace_init_main instead.
*/
void lace_run_worker(int worker);
/**
* Steal a random task.
*/
#define lace_steal_random() CALL(lace_steal_random)
void lace_steal_random_CALL(WorkerP*, Task*);
/**
* Barrier (all workers must enter it before progressing)
*/
void lace_barrier();
/**
* Suspend and resume all other workers.
* May only be used when all other workers are idle.
*/
void lace_suspend();
void lace_resume();
/**
* When all tasks are suspended, workers can be temporarily disabled.
* With set_workers, all workers 0..(N-1) are enabled and N..max are disabled.
* You can never disable the current worker or reduce the number of workers below 1.
* You cannot add workers.
*/
void lace_disable_worker(int worker);
void lace_enable_worker(int worker);
void lace_set_workers(int workercount);
int lace_enabled_workers();
/**
* Retrieve number of Lace workers
*/
size_t lace_workers();
/**
* Retrieve default program stack size
*/
size_t lace_default_stacksize();
/**
* Retrieve current worker.
*/
WorkerP *lace_get_worker();
/**
* Retrieve the current head of the deque
*/
Task *lace_get_head(WorkerP *);
/**
* Exit Lace. Automatically called when started with cb,arg.
*/
void lace_exit();
#define LACE_STOLEN ((Worker*)0)
#define LACE_BUSY ((Worker*)1)
#define LACE_NOWORK ((Worker*)2)
#define TASK(f) ( f##_CALL )
#define WRAP(f, ...) ( f((WorkerP *)__lace_worker, (Task *)__lace_dq_head, ##__VA_ARGS__) )
#define SYNC(f) ( __lace_dq_head--, WRAP(f##_SYNC) )
#define DROP() ( __lace_dq_head--, WRAP(lace_drop) )
#define SPAWN(f, ...) ( WRAP(f##_SPAWN, ##__VA_ARGS__), __lace_dq_head++ )
#define CALL(f, ...) ( WRAP(f##_CALL, ##__VA_ARGS__) )
#define TOGETHER(f, ...) ( WRAP(f##_TOGETHER, ##__VA_ARGS__) )
#define NEWFRAME(f, ...) ( WRAP(f##_NEWFRAME, ##__VA_ARGS__) )
#define STEAL_RANDOM() ( CALL(lace_steal_random) )
#define LACE_WORKER_ID ( __lace_worker->worker )
#define LACE_WORKER_PU ( __lace_worker->pu )
/* Use LACE_ME to initialize Lace variables, in case you want to call multiple Lace tasks */
#define LACE_ME WorkerP * __attribute__((unused)) __lace_worker = lace_get_worker(); Task * __attribute__((unused)) __lace_dq_head = lace_get_head(__lace_worker);
#define TASK_IS_STOLEN(t) ((size_t)t->thief > 1)
#define TASK_IS_COMPLETED(t) ((size_t)t->thief == 2)
#define TASK_RESULT(t) (&t->d[0])
#if LACE_DEBUG_PROGRAMSTACK
static inline void CHECKSTACK(WorkerP *w)
{
@ -402,14 +504,6 @@ extern lace_newframe_t lace_newframe;
void lace_do_together(WorkerP *__lace_worker, Task *__lace_dq_head, Task *task);
void lace_do_newframe(WorkerP *__lace_worker, Task *__lace_dq_head, Task *task);
void lace_yield(WorkerP *__lace_worker, Task *__lace_dq_head);
#define YIELD_NEWFRAME() { if (unlikely((*(Task* volatile *)&lace_newframe.t) != NULL)) lace_yield(__lace_worker, __lace_dq_head); }
/**
* Compute a random number, thread-local
*/
#define LACE_TRNG (__lace_worker->rng = 2862933555777941757ULL * __lace_worker->rng + 3037000493ULL)
/**
* Make all tasks of the current worker shared.
*/

4
resources/3rdparty/sylvan/src/storm_wrapper.cpp

@ -18,6 +18,8 @@
#if defined(STORM_HAVE_GMP) && !defined(STORM_USE_CLN_EA)
#define RATIONAL_NUMBER_THREAD_SAFE
#else
#warning "Rational numbers do not appear to be thread-safe. Use in sylvan will be protected by mutexes, performance might degrade."
#endif
// A mutex that is used to lock all operations accessing rational numbers as they are not necessarily thread-safe.
@ -123,6 +125,8 @@ int storm_rational_number_is_zero(storm_rational_number_ptr a) {
std::lock_guard<std::mutex> lock(rationalNumberMutex);
#endif
std::cout << "got ptr for eq check " << a << std::endl;
return storm::utility::isZero(*(storm::RationalNumber const*)a) ? 1 : 0;
}

37
resources/3rdparty/sylvan/src/sylvan.h

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,24 +17,49 @@
/**
* Sylvan: parallel MTBDD/ListDD package.
*
* This is a multi-core implementation of MTBDDs with complement edges.
*
* This package requires parallel the work-stealing framework Lace.
* Lace must be initialized before initializing Sylvan
* Include this file.
*/
#include <sylvan_config.h>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h> // for FILE
#include <stdlib.h> // for realloc
#include <unistd.h>
#include <pthread.h>
#if SYLVAN_STATS
#ifdef __MACH__
#include <mach/mach_time.h>
#else
#include <time.h>
#endif
#endif
/**
* Sylvan header files outside the namespace
*/
#include <lace.h>
#include <sylvan_tls.h>
#ifdef __cplusplus
//namespace sylvan {
#endif
/**
* Sylvan header files inside the namespace
*/
#include <sylvan_common.h>
#include <sylvan_stats.h>
#include <sylvan_mt.h>
#include <sylvan_mtbdd.h>
#include <sylvan_bdd.h>
#include <sylvan_ldd.h>
#ifdef __cplusplus
//}
#endif

22
resources/3rdparty/sylvan/src/sylvan_bdd.c

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,20 +15,12 @@
* limitations under the License.
*/
#include <sylvan_config.h>
#include <sylvan_int.h>
#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sylvan.h>
#include <sylvan_int.h>
#include <avl.h>
static int granularity = 1; // default
@ -45,12 +37,6 @@ sylvan_get_granularity()
return granularity;
}
BDD
sylvan_ithvar(BDDVAR level)
{
return sylvan_makenode(level, sylvan_false, sylvan_true);
}
/**
* Implementation of unary, binary and if-then-else operators.
*/
@ -1834,10 +1820,10 @@ TASK_IMPL_3(BDD, sylvan_union_cube, BDD, bdd, BDDSET, vars, uint8_t *, cube)
} else if (v > n_level) {
BDD high = node_high(bdd, n);
BDD low = node_low(bdd, n);
SPAWN(sylvan_union_cube, high, vars, cube);
bdd_refs_spawn(SPAWN(sylvan_union_cube, high, vars, cube));
BDD new_low = sylvan_union_cube(low, vars, cube);
bdd_refs_push(new_low);
BDD new_high = SYNC(sylvan_union_cube);
BDD new_high = bdd_refs_sync(SYNC(sylvan_union_cube));
bdd_refs_pop(1);
if (new_low != low || new_high != high) {
result = sylvan_makenode(n_level, new_low, new_high);

41
resources/3rdparty/sylvan/src/sylvan_bdd.h

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,10 +23,19 @@
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* For strictly non-MT BDDs */
#define sylvan_isconst(bdd) (bdd == sylvan_true || bdd == sylvan_false)
#define sylvan_isnode(bdd) (bdd != sylvan_true && bdd != sylvan_false)
static inline int
sylvan_isconst(MTBDD bdd)
{
return bdd == mtbdd_true || bdd == mtbdd_false ? 1 : 0;
}
static inline int
sylvan_isnode(MTBDD bdd)
{
return bdd != mtbdd_true && bdd != mtbdd_false ? 1 : 0;
}
/**
* Granularity (BDD only) determines usage of operation cache.
@ -43,15 +52,16 @@ extern "C" {
void sylvan_set_granularity(int granularity);
int sylvan_get_granularity(void);
/* Create a BDD representing just <var> or the negation of <var> */
BDD sylvan_ithvar(BDDVAR var);
#define sylvan_nithvar(var) sylvan_not(sylvan_ithvar(var))
/*
* Unary, binary and if-then-else operations.
* These operations are all implemented by NOT, AND and XOR.
*/
#define sylvan_not(a) (((BDD)a)^sylvan_complement)
static inline BDD
sylvan_not(BDD a)
{
return a ^ sylvan_complement;
}
TASK_DECL_4(BDD, sylvan_ite, BDD, BDD, BDD, BDDVAR);
#define sylvan_ite(a,b,c) (CALL(sylvan_ite,a,b,c,0))
TASK_DECL_3(BDD, sylvan_and, BDD, BDD, BDDVAR);
@ -68,6 +78,13 @@ TASK_DECL_3(BDD, sylvan_xor, BDD, BDD, BDDVAR);
#define sylvan_diff(a,b) sylvan_and(a,sylvan_not(b))
#define sylvan_less(a,b) sylvan_and(sylvan_not(a),b)
/* Create a BDD representing just <var> or the negation of <var> */
static inline BDD
sylvan_nithvar(uint32_t var)
{
return sylvan_not(sylvan_ithvar(var));
}
/**
* Existential and universal quantification.
*/
@ -265,7 +282,11 @@ sylvan_fprint(FILE *f, BDD bdd)
sylvan_serialize_totext(f);
}
#define sylvan_print(dd) sylvan_fprint(stdout, dd)
static void __attribute__((unused))
sylvan_print(BDD bdd)
{
return sylvan_fprint(stdout, bdd);
}
#include "sylvan_bdd_storm.h"

27
resources/3rdparty/sylvan/src/sylvan_bdd_storm.c

@ -12,7 +12,6 @@ TASK_IMPL_3(BDD, sylvan_existsRepresentative, BDD, a, BDD, variables, BDDVAR, pr
if (aRegular == sylvan_false) {
if (aIsNegated) {
if (sylvan_set_isempty(variables)) {
//printf("return in preprocessing...2\n");
return sylvan_true;
} else {
//printf("return in preprocessing...3\n");
@ -35,18 +34,22 @@ TASK_IMPL_3(BDD, sylvan_existsRepresentative, BDD, a, BDD, variables, BDDVAR, pr
return a;
}
} else if (sylvan_set_isempty(variables)) {
//printf("return in preprocessing...4\n");
return a;
}
BDD result;
if (cache_get3(CACHE_MTBDD_ABSTRACT_REPRESENTATIVE, a, variables, (size_t)2, &result)) {
sylvan_stats_count(MTBDD_ABSTRACT_CACHED);
return result;
}
/* From now on, f and cube are non-constant. */
bddnode_t na = MTBDD_GETNODE(a);
BDDVAR level = bddnode_getvariable(na);
bddnode_t nv = MTBDD_GETNODE(variables);
BDDVAR vv = bddnode_getvariable(nv);
//printf("a level %i and cube level %i\n", level, vv);
/* Abstract a variable that does not appear in f. */
if (level > vv) {
BDD _v = sylvan_set_next(variables);
@ -64,7 +67,6 @@ TASK_IMPL_3(BDD, sylvan_existsRepresentative, BDD, a, BDD, variables, BDDVAR, pr
}
sylvan_deref(res);
//printf("return after abstr. var that does not appear in f...\n");
return res1;
}
@ -128,13 +130,14 @@ TASK_IMPL_3(BDD, sylvan_existsRepresentative, BDD, a, BDD, variables, BDDVAR, pr
return sylvan_invalid;
}
// cuddCacheInsert2(manager, Cudd_bddExistAbstractRepresentative, f, cube, res);
// TODO: CACHING HERE
/* Store in cache */
if (cache_put3(CACHE_MTBDD_ABSTRACT_REPRESENTATIVE, a, variables, (size_t)2, res)) {
sylvan_stats_count(MTBDD_ABSTRACT_CACHEDPUT);
}
sylvan_deref(res1Inf);
sylvan_deref(res2Inf);
//printf("return properly computed result...\n");
return res;
} else { /* if (level == vv) */
BDD res1 = CALL(sylvan_existsRepresentative, aLow, variables, level);
@ -162,7 +165,11 @@ TASK_IMPL_3(BDD, sylvan_existsRepresentative, BDD, a, BDD, variables, BDDVAR, pr
sylvan_deref(res1);
sylvan_deref(res2);
//printf("return of last case...\n");
/* Store in cache */
if (cache_put3(CACHE_MTBDD_ABSTRACT_REPRESENTATIVE, a, variables, (size_t)2, res)) {
sylvan_stats_count(MTBDD_ABSTRACT_CACHEDPUT);
}
return res;
}

8
resources/3rdparty/sylvan/src/sylvan_bdd_storm.h

@ -1,6 +1,14 @@
#ifdef __cplusplus
extern "C" {
#endif
#define bdd_isnegated(dd) ((dd & sylvan_complement) ? 1 : 0)
#define bdd_regular(dd) (dd & ~sylvan_complement)
#define bdd_isterminal(dd) (dd == sylvan_false || dd == sylvan_true)
TASK_DECL_3(BDD, sylvan_existsRepresentative, BDD, BDD, BDDVAR);
#define sylvan_existsRepresentative(a, vars) (CALL(sylvan_existsRepresentative, a, vars, 0))
#ifdef __cplusplus
}
#endif

13
resources/3rdparty/sylvan/src/sylvan_cache.c

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,19 +15,20 @@
* limitations under the License.
*/
#include <sylvan_int.h>
#include <errno.h> // for errno
#include <stdio.h> // for fprintf
#include <stdint.h> // for uint32_t etc
#include <stdlib.h> // for exit
#include <string.h> // for strerror
#include <sys/mman.h> // for mmap
#include <sylvan_cache.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#ifndef CACHE_MASK
#define CACHE_MASK 1
#endif
#ifndef compiler_barrier
#define compiler_barrier() { asm volatile("" ::: "memory"); }
#endif

14
resources/3rdparty/sylvan/src/sylvan_cache.h

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -15,21 +15,15 @@
* limitations under the License.
*/
#include <sylvan_config.h>
/* Do not include this file directly. Instead, include sylvan_int.h */
#include <stdint.h> // for uint32_t etc
#ifndef CACHE_H
#define CACHE_H
#ifndef SYLVAN_CACHE_H
#define SYLVAN_CACHE_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#ifndef CACHE_MASK
#define CACHE_MASK 1
#endif
/**
* Operation cache
*

2
resources/3rdparty/sylvan/src/sylvan_common.c

@ -1,6 +1,6 @@
/*
* Copyright 2011-2016 Formal Methods and Tools, University of Twente
* Copyright 2016 Tom van Dijk, Johannes Kepler University Linz
* Copyright 2016-2017 Tom van Dijk, Johannes Kepler University Linz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

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

|||||||
100:0
Loading…
Cancel
Save