diff --git a/.gitignore b/.gitignore index a3ffbfa22..06524d5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ ipch/ obj/ # The build Dir -build/ \ No newline at end of file +build//CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eb520c60..349fcf7f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,8 @@ project (MRMC-cpp CXX C) set (MRMC_CPP_VERSION_MAJOR 1) set (MRMC_CPP_VERSION_MINOR 0) +set (CMAKE_CXX_FLAGS "-g") + # configure a header file to pass some of the CMake settings # to the source code configure_file ( @@ -17,30 +19,107 @@ configure_file ( # so that we will find TutorialConfig.h include_directories("${PROJECT_BINARY_DIR}") -#add_executable(MRMC-cpp src/mrmc-cpp.cpp) - -FILE(GLOB_RECURSE MRMCSources ${PROJECT_SOURCE_DIR}/src/*.cpp) +# Main Sources FILE(GLOB_RECURSE MRMCHeaders ${PROJECT_SOURCE_DIR}/src/*.h) - +FILE(GLOB_RECURSE MRMCSources ${PROJECT_SOURCE_DIR}/src/*.cpp) +# Test Sources +# Note that the tests also need the source files, except the main file! +FILE(GLOB_RECURSE MRMCTestHeaders ${PROJECT_SOURCE_DIR}/test/*.h) +FILE(GLOB_RECURSE MRMCTestSources ${PROJECT_SOURCE_DIR}/test/*.cpp ${PROJECT_SOURCE_DIR}/src/*/*.cpp) +# Main Grouping SOURCE_GROUP(Headers FILES ${MRMCHeaders}) SOURCE_GROUP(Sources FILES ${MRMCSources}) - -ADD_EXECUTABLE(MRMC-cpp ${MRMCSources} ${MRMCHeaders}) +# Test Grouping +SOURCE_GROUP(Headers FILES ${MRMCTestHeaders}) +SOURCE_GROUP(Sources FILES ${MRMCTestSources}) # Add base folder for better inclusion pathes include_directories("${PROJECT_SOURCE_DIR}") include_directories("${PROJECT_SOURCE_DIR}/src") +# temp search path for Pantheios/STLSoft +message(STATUS "CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}") +set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) +message(STATUS "CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}") + # external packages FIND_PACKAGE(GTest REQUIRED) +FIND_PACKAGE(Threads REQUIRED) +SET(Boost_USE_STATIC_LIBS ON) +SET(Boost_USE_MULTITHREADED ON) +SET(Boost_USE_STATIC_RUNTIME OFF) FIND_PACKAGE(Boost REQUIRED) FIND_PACKAGE(Doxygen REQUIRED) -FIND_PACKAGE(Threads REQUIRED) - +FIND_PACKAGE(STLSoft REQUIRED) + +#set(PANTHEIOS_USE_DYNAMIC_RUNTIME ON) +FIND_PACKAGE(Pantheios REQUIRED COMPONENTS SimpleFrontEnd File) + +# STLsoft headers +# include_directories("${PROJECT_SRC_DIR}/resources/3rdParty/stlsoft-1.9.114") +# Pantheios Logging library +# include_directories("${PROJECT_SRC_DIR}/resources/3rdParty/pantheios-1.0.1-beta213") + +if (STLSOFT_FOUND) + message(STATUS "STLSoft found") + INCLUDE_DIRECTORIES(${STLSOFT_INCLUDE_DIR}) +endif() +FIND_PACKAGE(STLSoft REQUIRED) + +#Dynamic runtime for Pantheios is configured for dll-files, hence only usable under Windows... +if (WIN32) + set(PANTHEIOS_USE_DYNAMIC_RUNTIME ON) +else() + set(PANTHEIOS_USE_DYNAMIC_RUNTIME OFF) +endif() +FIND_PACKAGE(Pantheios REQUIRED COMPONENTS SimpleFrontEnd File) + +# STLsoft headers +# include_directories("${PROJECT_SRC_DIR}/resources/3rdParty/stlsoft-1.9.114") +# Pantheios Logging library +# include_directories("${PROJECT_SRC_DIR}/resources/3rdParty/pantheios-1.0.1-beta213") + +if (STLSOFT_FOUND) + message(STATUS "STLSoft found") + INCLUDE_DIRECTORIES(${STLSOFT_INCLUDE_DIR}) +endif() + +IF (PANTHEIOS_FOUND) + message(STATUS "Pantheios found") + INCLUDE_DIRECTORIES(${PANTHEIOS_INCLUDE_DIR}) + LINK_DIRECTORIES(${PANTHEIOS_LIBRARY_DIRS}) +else() + message(STATUS "NO PANTHEIOS!") +ENDIF() + +IF (PANTHEIOS_FOUND) + message(STATUS "Pantheios found") + INCLUDE_DIRECTORIES(${PANTHEIOS_INCLUDE_DIR}) + LINK_DIRECTORIES(${PANTHEIOS_LIBRARY_DIRS}) +else() + message(STATUS "NO PANTHEIOS!") +ENDIF() + if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) + +if ((NOT Boost_LIBRARY_DIRS) OR ("${Boost_LIBRARY_DIRS}" STREQUAL "")) + set(Boost_LIBRARY_DIRS "${Boost_INCLUDE_DIRS}/stage/lib") + message(STATUS "Boost_LIBRARY_DIRS was empty, setting to ${Boost_LIBRARY_DIRS}") +endif () + +link_directories(${Boost_LIBRARY_DIRS}) + endif(Boost_FOUND) +# must be created AFTER Boost was added because of LINK_DIRECTORIES +ADD_EXECUTABLE(MRMC-cpp ${MRMCSources} ${MRMCHeaders}) +ADD_EXECUTABLE(MRMC-tests ${MRMCTestSources} ${MRMCTestHeaders}) + +# Add target link deps for Pantheios +target_link_libraries(MRMC-cpp ${PANTHEIOS_LIBRARIES}) +target_link_libraries(MRMC-tests ${PANTHEIOS_LIBRARIES}) + # add a target to generate API documentation with Doxygen if(DOXYGEN_FOUND) @@ -61,8 +140,6 @@ if (GTEST_FOUND) # For Visual Studio builds, defines Visual Studio project named RUN_TESTS. enable_testing() -add_executable(MRMC-tests ${PROJECT_SOURCE_DIR}/test/mrmc-tests.cpp) - include_directories(${GTEST_INCLUDE_DIRS}) target_link_libraries(MRMC-tests ${GTEST_LIBRARIES}) @@ -71,12 +148,13 @@ add_test( COMMAND MRMC-tests ) -# GTest needs pThreads, so it is linked into MRMC-tests. +endif(GTEST_FOUND) + + if (THREADS_FOUND) include_directories(${THREADS_INCLUDE_DIRS}) target_link_libraries (MRMC-tests ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (MRMC-cpp ${CMAKE_THREAD_LIBS_INIT}) -endif(THREADS_FOUND) - -endif(GTEST_FOUND) \ No newline at end of file +endif(THREADS_FOUND) \ No newline at end of file diff --git a/FindPantheios.cmake b/FindPantheios.cmake new file mode 100644 index 000000000..864d9044f --- /dev/null +++ b/FindPantheios.cmake @@ -0,0 +1,461 @@ +# Locate the Pantheois Logging Framework. +# +# Defines the following variables: +# +# PANTHEIOS_FOUND - Found the Pantheios Logging Framework +# PANTHEIOS_INCLUDE_DIRS - Include directories +# +# Accepts the following variables as input: +# +# PANTHEIOS_ROOT - (as a CMake or environment variable) +# The root directory of the pantheios install prefix +# +# PANTHEIOS_USE_DYNAMIC_RUNTIME +# +# If you want to use splitting, specify LRSplit and than preface the components with L and R, so e.g. LRSplit LFile RSyslog +# To use more than one BackEnd, specify NBackEnd followed by a list of components. NBackEnd requires the NFrontEnd. +# +# Possible Components for BackEnd: +# ACELogger +# COMErrorObject +# File +# FileCallback +# FPrintf +# FPrintfCallback +# Null +# Speech +# Syslog +# WindowsConsole +# WindowsConsoleCallback +# WindowsDebugger +# WindowsDebuggerCallback +# WindowsEventLog +# WindowsMessageBox +# WindowsSyslog +# WindowsSyslogCallback +# +# Possible components for FrontEnd: +# NoFrontEnd +# SimpleFrontEnd +# NFrontEnd +# +# + +#============================================================================= +# Copyright 2012 Philipp Berger +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) +# +# Credits: +# +# HUGE thanks to Michael Wild +# Additional thanks to: +# Mateusz Loskot +# Rolf Eike Beer + + + +# default for WideString option +set(PANTHEIOS_WIDESTRING 0) +# default for Front- and BackEnd +set(PANTHEIOS_FRONTEND "simple") +set(PANTHEIOS_BACKEND "file") +set(PANTHEIOS_BACKEND_L OFF) +set(PANTHEIOS_BACKEND_R OFF) +set(PANTHEIOS_BACKEND_LIST) + +# Use FIND_PACKAGE( Pantheios COMPONENTS ... ) to enable modules +if( Pantheios_FIND_COMPONENTS ) + list(FIND Pantheios_FIND_COMPONENTS "LRSplit" PANTHEIOS_use_lrsplit) + list(FIND Pantheios_FIND_COMPONENTS "NFrontEnd" PANTHEIOS_use_nfe) + list(FIND Pantheios_FIND_COMPONENTS "NBackEnd" PANTHEIOS_use_nbe) + list(FIND Pantheios_FIND_COMPONENTS "WideString" PANTHEIOS_use_ws) + + list(REMOVE_ITEM Pantheios_FIND_COMPONENTS "LRSplit" "NFrontEnd" "NBackEnd" "WideString") + + if (NOT PANTHEIOS_use_ws EQUAL -1) + # Use WideString + set(PANTHEIOS_WIDESTRING 1) + endif() + + if (NOT PANTHEIOS_use_lrsplit EQUAL -1) + # Found LRSplit + set(PANTHEIOS_BACKEND "lrsplit") + if (NOT PANTHEIOS_use_nbe EQUAL -1) + # Also found NBe + message(FATAL_ERROR "Pantheios: Use either LRSplit or NBackEnd, not both.") + endif() + if (NOT PANTHEIOS_use_nfe EQUAL -1) + # Also found NFe + message(FATAL_ERROR "Pantheios: Use either LRSplit or NFrontEnd, not both.") + endif() + + foreach( component ${Pantheios_FIND_COMPONENTS} ) + # LRSplit L BackEnds + string(SUBSTRING ${component} 0 1 _sub_comp_head) + string(LENGTH ${component} _length_comp) + math(EXPR _length_comp_tail "${_length_comp} - 1") + string(SUBSTRING ${component} 1 ${_length_comp_tail} _sub_comp_tail) + + if ((_sub_comp_tail STREQUAL "ACELogger") OR (_sub_comp_tail STREQUAL "COMErrorObject") OR (_sub_comp_tail STREQUAL "File") OR (_sub_comp_tail STREQUAL "FileCallback") OR (_sub_comp_tail STREQUAL "FPrintf") OR (_sub_comp_tail STREQUAL "FPrintfCallback") OR (_sub_comp_tail STREQUAL "Null") OR (_sub_comp_tail STREQUAL "Speech") OR (_sub_comp_tail STREQUAL "Syslog") OR (_sub_comp_tail STREQUAL "WindowsConsole") OR (_sub_comp_tail STREQUAL "WindowsConsoleCallback") OR (_sub_comp_tail STREQUAL "WindowsDebugger") OR (_sub_comp_tail STREQUAL "WindowsDebuggerCallback") OR (_sub_comp_tail STREQUAL "WindowsEventLog") OR (_sub_comp_tail STREQUAL "WindowsMessageBox") OR (_sub_comp_tail STREQUAL "WindowsSyslog") OR (_sub_comp_tail STREQUAL "WindowsSyslogCallback")) + if ((_sub_comp_head STREQUAL L) OR (_sub_comp_head STREQUAL R)) + message(STATUS "Pantheios: Setting LRSplit BackEnd ${_sub_comp_head} to ${_sub_comp_tail}") + string(TOLOWER ${_sub_comp_tail} _sub_comp_tail_low) + set(PANTHEIOS_BACKEND_${_sub_comp_head} "${_sub_comp_tail_low}") + else () + message(FATAL_ERROR "Pantheios: Internal Parsing Error") + endif() + + # FrontEnds + elseif (component STREQUAL "NoFrontEnd") + message(STATUS "Pantheios: Setting FrontEnd to NoFrontEnd") + set(PANTHEIOS_FRONTEND "null") + elseif (component STREQUAL "SimpleFrontEnd") + message(STATUS "Pantheios: Setting FrontEnd to SimpleFrontEnd") + set(PANTHEIOS_FRONTEND "simple") + + else () + message(FATAL_ERROR "Unknown Component: ${component}") + endif () + endforeach(component) + elseif (NOT PANTHEIOS_use_nbe EQUAL -1) + # Found NBackEnd + if (PANTHEIOS_use_nfe EQUAL -1) + message(FATAL_ERROR "Pantheios: Usage of NBackEnd requires the NFrontEnd.") + endif() + set(PANTHEIOS_BACKEND "N") + set(PANTHEIOS_FRONTEND "N") + + foreach( component ${Pantheios_FIND_COMPONENTS} ) + # Std BackEnds + if ((component STREQUAL "ACELogger") OR (component STREQUAL "COMErrorObject") OR (component STREQUAL "File") OR (component STREQUAL "FileCallback") OR (component STREQUAL "FPrintf") OR (component STREQUAL "FPrintfCallback") OR (component STREQUAL "Null") OR (component STREQUAL "Speech") OR (component STREQUAL "Syslog") OR (component STREQUAL "WindowsConsole") OR (component STREQUAL "WindowsConsoleCallback") OR (component STREQUAL "WindowsDebugger") OR (component STREQUAL "WindowsDebuggerCallback") OR (component STREQUAL "WindowsEventLog") OR (component STREQUAL "WindowsMessageBox") OR (component STREQUAL "WindowsSyslog") OR (component STREQUAL "WindowsSyslogCallback")) + message(STATUS "Pantheios: Adding BackEnd ${component}") + string(TOLOWER ${component} _low_comp) + list(APPEND PANTHEIOS_BACKEND_LIST ${_low_comp}) + else () + message(FATAL_ERROR "Unknown Component: ${component}") + endif () + endforeach(component) + else () + # Simple, one FE, one BE + foreach( component ${Pantheios_FIND_COMPONENTS} ) + if ((component STREQUAL "ACELogger") OR (component STREQUAL "COMErrorObject") OR (component STREQUAL "File") OR (component STREQUAL "FileCallback") OR (component STREQUAL "FPrintf") OR (component STREQUAL "FPrintfCallback") OR (component STREQUAL "Null") OR (component STREQUAL "Speech") OR (component STREQUAL "Syslog") OR (component STREQUAL "WindowsConsole") OR (component STREQUAL "WindowsConsoleCallback") OR (component STREQUAL "WindowsDebugger") OR (component STREQUAL "WindowsDebuggerCallback") OR (component STREQUAL "WindowsEventLog") OR (component STREQUAL "WindowsMessageBox") OR (component STREQUAL "WindowsSyslog") OR (component STREQUAL "WindowsSyslogCallback")) + message(STATUS "Pantheios: Setting BackEnd to ${component}") + string(TOLOWER ${component} _low_comp) + set(PANTHEIOS_BACKEND ${_low_comp}) + + # FrontEnds + elseif (component STREQUAL "NoFrontEnd") + message(STATUS "Pantheios: Setting FrontEnd to NoFrontEnd") + set(PANTHEIOS_FRONTEND "null") + elseif (component STREQUAL "SimpleFrontEnd") + message(STATUS "Pantheios: Setting FrontEnd to SimpleFrontEnd") + set(PANTHEIOS_FRONTEND "simple") + else () + message(FATAL_ERROR "Unknown Component: ${component}") + endif () + endforeach(component) + endif () +endif(Pantheios_FIND_COMPONENTS) + +if (PANTHEIOS_USE_DYNAMIC_RUNTIME) + set(PANTHEIOS_LIB_LINKTYPE "dll") +else () + set(PANTHEIOS_LIB_LINKTYPE "mt") +endif () + +if(PANTHEIOS_INCLUDE_DIR) + if (NOT PANTHEIOS_ROOT) + get_filename_component(PANTHEIOS_ROOT "${PANTHEIOS_INCLUDE_DIR}" PATH) + endif() + + get_filename_component(PANTHEIOS_ROOT_HINT "${PANTHEIOS_INCLUDE_DIR}" PATH) +endif() + +find_path(PANTHEIOS_INCLUDE_DIR pantheios/pantheios.h + PATH_SUFFIXES include + HINTS ${PANTHEIOS_ROOT} ${PANTHEIOS_ROOT_HINT} + ENV PANTHEIOS_ROOT +) + +# No idea what the stuff for ICC et. al. is, so I don't handle it here... +set(_P_COMP_TAG) +set(_P_OS_TAG) +set(_P_ARCH_TAG) +if(MSVC) + if(MSVC60) + set(_P_COMP_TAG vc6) + elseif(MSVC70) + set(_P_COMP_TAG vc7) + elseif(MSVC71) + set(_P_COMP_TAG vc71) + elseif(MSVC80) + set(_P_COMP_TAG vc8) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_P_ARCH_TAG .x64) + endif() + elseif(MSVC90) + set(_P_COMP_TAG vc9) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_P_ARCH_TAG .x64) + endif() + elseif(MSVC10) + set(_P_COMP_TAG vc10) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_P_ARCH_TAG .x64) + endif() + endif() +elseif(CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) + list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) + list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) + set(_P_COMP_TAG gcc${GCC_MAJOR}${GCC_MINOR}) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_P_ARCH_TAG .file64bit) + endif() +else() + message(FATAL_ERROR "Pantheios: Your compiler/environment is currently unsupported.") +endif() + +set(_P_LIB_TAG ${_P_COMP_TAG}${_P_OS_TAG}${_P_ARCH_TAG}) + +# Is this the right way? +set(PANTHEIOS_INCLUDE_DIRS ${PANTHEIOS_INCLUDE_DIR}) + +set(_P_REQUIRED_LIBVARS) +set(PANTHEIOS_LIBRARIES) +set(PANTHEIOS_LIBRARIES_DEBUG) +set(PANTHEIOS_LIBRARIES_RELEASE) + + +#core and util libraries +foreach(l core util) + find_library(PANTHEIOS_${l}_${PANTHEIOS_LIB_LINKTYPE}_DEBUG_LIBRARY + pantheios.1.${l}.${_P_LIB_TAG}.${PANTHEIOS_LIB_LINKTYPE}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + find_library(PANTHEIOS_${l}_${PANTHEIOS_LIB_LINKTYPE}_LIBRARY + pantheios.1.${l}.${_P_LIB_TAG}.${PANTHEIOS_LIB_LINKTYPE} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_${l}_${PANTHEIOS_LIB_LINKTYPE}_DEBUG_LIBRARY + PANTHEIOS_${l}_${PANTHEIOS_LIB_LINKTYPE}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_${l}_${PANTHEIOS_LIB_LINKTYPE}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_${l}_${PANTHEIOS_LIB_LINKTYPE}_LIBRARY} + ) +endforeach() + +# set PANTHEIOS_LIBRARY_DIRS +get_filename_component(PANTHEIOS_LIBRARY_DIRS ${PANTHEIOS_core_${PANTHEIOS_LIB_LINKTYPE}_LIBRARY} PATH) + + + +# backend libraries (split, sole, local, remote and common) +set(_P_LT ${PANTHEIOS_LIB_LINKTYPE}) +set(_P_BE ${PANTHEIOS_BACKEND}) + +find_library(PANTHEIOS_be_${_P_BE}_${_P_LT}_DEBUG_LIBRARY + pantheios.1.be.${_P_BE}.${_P_LIB_TAG}.${_P_LT}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT +) + +find_library(PANTHEIOS_be_${_P_BE}_${_P_LT}_LIBRARY + pantheios.1.be.${_P_BE}.${_P_LIB_TAG}.${_P_LT} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT +) + +list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_be_${_P_BE}_${_P_LT}_DEBUG_LIBRARY + PANTHEIOS_be_${_P_BE}_${_P_LT}_LIBRARY +) +list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_be_${_P_BE}_${_P_LT}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_be_${_P_BE}_${_P_LT}_LIBRARY} +) + +if (_P_BE STREQUAL N) + # N Backend, go through list + message(STATUS "Pantheios: Dbg: Lib-n") + + foreach (blib PANTHEIOS_BACKEND_LIST) + find_library(PANTHEIOS_bec_${blib}_${_P_LT}_DEBUG_LIBRARY + pantheios.1.bec.${blib}.${_P_LIB_TAG}.${_P_LT}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + find_library(PANTHEIOS_bec_${blib}_${_P_LT}_LIBRARY + pantheios.1.bec.${blib}.${_P_LIB_TAG}.${_P_LT} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_bec_${blib}_${_P_LT}_DEBUG_LIBRARY + PANTHEIOS_bec_${blib}_${_P_LT}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_bec_${blib}_${_P_LT}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_bec_${blib}_${_P_LT}_LIBRARY} + ) + endforeach() +elseif (_P_BE STREQUAL lrsplit) + # LRSplit + message(STATUS "Pantheios: Dbg: Lib-lrsplit") + + # Left side + foreach (t bec bel) + find_library(PANTHEIOS_${t}_${PANTHEIOS_BACKEND_L}_${_P_LT}_DEBUG_LIBRARY + pantheios.1.${t}.${PANTHEIOS_BACKEND_L}.${_P_LIB_TAG}.${_P_LT}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + find_library(PANTHEIOS_${t}_${PANTHEIOS_BACKEND_L}_${_P_LT}_LIBRARY + pantheios.1.${t}.${PANTHEIOS_BACKEND_L}.${_P_LIB_TAG}.${_P_LT} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_${t}_${PANTHEIOS_BACKEND_L}_${_P_LT}_DEBUG_LIBRARY + PANTHEIOS_${t}_${PANTHEIOS_BACKEND_L}_${_P_LT}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_${t}_${PANTHEIOS_BACKEND_L}_${_P_LT}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_${t}_${PANTHEIOS_BACKEND_L}_${_P_LT}_LIBRARY} + ) + endforeach() + # Right side + foreach (t bec ber) + find_library(PANTHEIOS_${t}_${PANTHEIOS_BACKEND_R}_${_P_LT}_DEBUG_LIBRARY + pantheios.1.${t}.${PANTHEIOS_BACKEND_R}.${_P_LIB_TAG}.${_P_LT}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + find_library(PANTHEIOS_${t}_${PANTHEIOS_BACKEND_R}_${_P_LT}_LIBRARY + pantheios.1.${t}.${PANTHEIOS_BACKEND_R}.${_P_LIB_TAG}.${_P_LT} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_${t}_${PANTHEIOS_BACKEND_R}_${_P_LT}_DEBUG_LIBRARY + PANTHEIOS_${t}_${PANTHEIOS_BACKEND_R}_${_P_LT}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_${t}_${PANTHEIOS_BACKEND_R}_${_P_LT}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_${t}_${PANTHEIOS_BACKEND_R}_${_P_LT}_LIBRARY} + ) + endforeach() +else () + # normal + message(STATUS "Pantheios: Dbg: Lib-normal") + foreach (t bec) + find_library(PANTHEIOS_${t}_${PANTHEIOS_BACKEND}_${_P_LT}_DEBUG_LIBRARY + pantheios.1.${t}.${PANTHEIOS_BACKEND}.${_P_LIB_TAG}.${_P_LT}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + find_library(PANTHEIOS_${t}_${PANTHEIOS_BACKEND}_${_P_LT}_LIBRARY + pantheios.1.${t}.${PANTHEIOS_BACKEND}.${_P_LIB_TAG}.${_P_LT} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_${t}_${PANTHEIOS_BACKEND}_${_P_LT}_DEBUG_LIBRARY + PANTHEIOS_${t}_${PANTHEIOS_BACKEND}_${_P_LT}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_${t}_${PANTHEIOS_BACKEND}_${_P_LT}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_${t}_${PANTHEIOS_BACKEND}_${_P_LT}_LIBRARY} + ) + endforeach() +endif() + +# frontent libraries +set(PANTHEIOS_fe_DEBUG_LIBRARY) +set(PANTHEIOS_fe_LIBRARY) +if(NOT PANTHEIOS_FRONTENT STREQUAL null) + set(_P_FE ${PANTHEIOS_FRONTEND}) + find_library(PANTHEIOS_${_P_FE}_${_P_LT}_DEBUG_LIBRARY + pantheios.1.fe.${_P_FE}.${_P_LIB_TAG}.${_P_LT}.debug + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + find_library(PANTHEIOS_${_P_FE}_${_P_LT}_LIBRARY + pantheios.1.fe.${_P_FE}.${_P_LIB_TAG}.${_P_LT} + PATH_SUFFIXES lib + HINTS ${PANTHEIOS_ROOT_HINT} ${PANTHEIOS_ROOT} + ENV PANTHEIOS_ROOT + ) + + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_${_P_FE}_${_P_LT}_DEBUG_LIBRARY + PANTHEIOS_${_P_FE}_${_P_LT}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_${_P_FE}_${_P_LT}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_${_P_FE}_${_P_LT}_LIBRARY} + ) +endif() + +# gcc needs the core library mentioned a second time at the end +# (see Pantheios FAQ Q/A8) +# At this point, the core has to be found already, +# so only the additions to the lists are repeated here... +if(CMAKE_COMPILER_IS_GNUCC) + list(APPEND _P_REQUIRED_LIBVARS + PANTHEIOS_core_${PANTHEIOS_LIB_LINKTYPE}_DEBUG_LIBRARY + PANTHEIOS_core_${PANTHEIOS_LIB_LINKTYPE}_LIBRARY + ) + list(APPEND PANTHEIOS_LIBRARIES + debug ${PANTHEIOS_core_${PANTHEIOS_LIB_LINKTYPE}_DEBUG_LIBRARY} + optimized ${PANTHEIOS_core_${PANTHEIOS_LIB_LINKTYPE}_LIBRARY} + ) +endif() + +# copy to NAME_LIBS +set(PANTHEIOS_LIBS ${PANTHEIOS_LIBRARIES}) + +# handle the QUIETLY and REQUIRED arguments and set Pantheios_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Pantheios + REQUIRED_VARS PANTHEIOS_INCLUDE_DIR ${_P_REQUIRED_LIBVARS} +) + +message(STATUS ${PANTHEIOS_INCLUDE_DIR} ${PANTHEIOS_LIBRARIES}) +mark_as_advanced(PANTHEIOS_INCLUDE_DIR PANTHEIOS_LIBRARIES) + diff --git a/FindSTLSoft.cmake b/FindSTLSoft.cmake new file mode 100644 index 000000000..5499ff851 --- /dev/null +++ b/FindSTLSoft.cmake @@ -0,0 +1,56 @@ +# Locate the STLSoft Headers. +# +# Defines the following variables: +# +# STLSOFT_FOUND - Found the Pantheios Logging Framework +# STLSOFT_INCLUDE_DIRS - Include directories +# +# Accepts the following variables as input: +# +# STLSOFT_ROOT - (as a CMake or environment variable) +# The root directory of the STLSoft install prefix +# +# + +#============================================================================= +# Copyright 2012 Philipp Berger +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) +# + + + + +if(STLSOFT_INCLUDE_DIR) + if (NOT STLSOFT_ROOT) + get_filename_component(STLSOFT_ROOT "${STLSOFT_INCLUDE_DIR}" PATH) + endif() + + get_filename_component(STLSOFT_ROOT_HINT "${STLSOFT_INCLUDE_DIR}" PATH) +endif() + +find_path(STLSOFT_INCLUDE_DIR stlsoft/stlsoft.h + PATH_SUFFIXES include + HINTS ${STLSOFT_ROOT} ${STLSOFT_ROOT_HINT} + ENV STLSOFT_ROOT +) +set(STLSOFT_INCLUDE_DIRS ${STLSOFT_INCLUDE_DIR}) + +# handle the QUIETLY and REQUIRED arguments and set STLSOFT_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(STLSoft + REQUIRED_VARS STLSOFT_INCLUDE_DIR +) + + +mark_as_advanced(STLSOFT_INCLUDE_DIR) + diff --git a/src/MRMCConfig.h.in b/MRMCConfig.h.in similarity index 100% rename from src/MRMCConfig.h.in rename to MRMCConfig.h.in diff --git a/resources/BUILD.txt b/resources/BUILD.txt new file mode 100644 index 000000000..e6e7d9769 --- /dev/null +++ b/resources/BUILD.txt @@ -0,0 +1,29 @@ +CMake + +Prerequisites: + Boost >= 1.49 + Build using the Boost Build system, for x64 use "bjam address-model=64" or "bjam.exe address-model=64 --build-type=complete" + You may use --toolset to specify the compiler, for ex. msvc-10.0, intel11.1, etc + Doxygen + Set DOXYGEN_EXECUTABLE to your doxygen executable, e.g. "C:/Program Files/doxygen/bin/doxygen.exe" + GTest >= 1.6.0 + Download, build using CMake + If you installed gtest to e.g. "C:/C++ Projects/gtest-1.6.0" + Set GTEST_INCLUDE_DIR to "C:/C++ Projects/gtest-1.6.0/include" + Set GTEST_LIBRARY to "C:/C++ Projects/gtest-1.6.0/build/Release/gtest.lib" + Set GTEST_LIBRARY_DEBUG to "C:/C++ Projects/gtest-1.6.0/build/Debug/gtest.lib" + Set GTEST_MAIN_LIBRARY to "C:/C++ Projects/gtest-1.6.0/build/Release/gtest_main.lib" + Set GTEST_MAIN_LIBRARY_DEBUG to "C:/C++ Projects/gtest-1.6.0/build/Debug/gtest_main.lib" + STLSoft + Download from http://www.stlsoft.org/ + Headers-Only, unpack to a location of your choice, e.g. "C:/C++ Projects/stlsoft" + Set STLSOFT_INCLUDE_DIR to "C:/C++ Projects/stlsoft/include" + Pantheios + Download from http://www.pantheios.org/ + Unpack and build following the provided instructions + If you installed Pantheios to e.g. "C:/C++ Projects/pantheios" + Set PANTHEIOS_INCLUDE_DIR to "C:/C++ Projects/pantheios/include" + The other fields should be auto completed after to next "Configure" round + +If no error occured during the last CMake Configure round, press Generate. +Now you can build MRMC-Cpp using the generated project/makefiles in the Build folder you selected. \ No newline at end of file diff --git a/resources/GUIDELINES-Doxygen.example.h b/resources/GUIDELINES-Doxygen.example.h new file mode 100644 index 000000000..12908fc01 --- /dev/null +++ b/resources/GUIDELINES-Doxygen.example.h @@ -0,0 +1,56 @@ +//! A test class. +/*! +A more elaborate class description. +*/ +class Test +{ +public: +//! An enum. +/*! More detailed enum description. */ +enum TEnum { +TVal1, /*!< Enum value TVal1. */ +TVal2, /*!< Enum value TVal2. */ +TVal3 /*!< Enum value TVal3. */ +} +//! Enum pointer. +/*! Details. */ +*enumPtr, +//! Enum variable. +/*! Details. */ +enumVar; +//! A constructor. +/*! +A more elaborate description of the constructor. +*/ +Test(); +//! A destructor. +/*! +A more elaborate description of the destructor. +*/ +~Test(); +//! A normal member taking two arguments and returning an integer value. +/*! +\param a an integer argument. +\param s a constant character pointer. +\return The test results +\sa Test(), ~Test(), testMeToo() and publicVar() +*/ +int testMe(int a,const char *s); +//! A pure virtual member. +/*! +\sa testMe() +\param c1 the first argument. +\param c2 the second argument. +*/ +virtual void testMeToo(char c1,char c2) = 0; +//! A public variable. +/*! +Details. +*/ +int publicVar; +//! A function variable. +/*! +Details. +*/ +int (*handler)(int a,int b); +}; \ No newline at end of file diff --git a/src/exceptions/invalid_argument.h b/src/exceptions/invalid_argument.h new file mode 100644 index 000000000..31db957a4 --- /dev/null +++ b/src/exceptions/invalid_argument.h @@ -0,0 +1,34 @@ +#ifndef MRMC_EXCEPTIONS_INVALID_ARGUMENT_H_ +#define MRMC_EXCEPTIONS_INVALID_ARGUMENT_H_ + +#include + +namespace mrmc { + +namespace exceptions { + +//!This exception is thrown when a parameter is invalid in this context +class invalid_argument : public std::exception +{ + public: +/* The Visual C++-Version of the exception class has constructors accepting + * a char*-constant; The GCC version does not have these + * + * As the "extended" constructor is used in the sparse matrix code, a dummy + * constructor is used under linux (which will ignore the parameter) + */ +#ifdef _WIN32 + invalid_argument() : exception("::mrmc::invalid_argument"){} + invalid_argument(const char * const s): exception(s) {} +#else + invalid_argument() : exception() {} + invalid_argument(const char * const s): exception() {} +#endif + virtual const char* what() const throw() + { return "mrmc::invalid_argument"; } +}; + +} // namespace exceptions + +} // namespace mrmc +#endif // MRMC_EXCEPTIONS_INVALID_ARGUMENT_H_ diff --git a/src/exceptions/invalid_state.h b/src/exceptions/invalid_state.h new file mode 100644 index 000000000..132c99644 --- /dev/null +++ b/src/exceptions/invalid_state.h @@ -0,0 +1,37 @@ +#ifndef MRMC_EXCEPTIONS_INVALID_STATE_H_ +#define MRMC_EXCEPTIONS_INVALID_STATE_H_ + +#include + +namespace mrmc { + +namespace exceptions { + +//!This exception is thrown when a memory request can't be +//!fulfilled. +class invalid_state : public std::exception +{ + public: +/* The Visual C++-Version of the exception class has constructors accepting + * a char*-constant; The GCC version does not have these + * + * As the "extended" constructor is used in the sparse matrix code, a dummy + * constructor is used under linux (which will ignore the parameter) + */ +#ifdef _WIN32 + invalid_state() : exception("::mrmc::invalid_state"){} + invalid_state(const char * const s): exception(s) {} +#else + invalid_state() : exception() {} + invalid_state(const char * const s): exception() {} + +#endif + virtual const char* what() const throw() + { return "mrmc::invalid_state"; } +}; + +} // namespace exceptions + +} // namespace mrmc + +#endif // MRMC_EXCEPTIONS_INVALID_STATE_H_ diff --git a/src/exceptions/out_of_range.h b/src/exceptions/out_of_range.h new file mode 100644 index 000000000..5b1bfaac9 --- /dev/null +++ b/src/exceptions/out_of_range.h @@ -0,0 +1,34 @@ +#ifndef MRMC_EXCEPTIONS_OUT_OF_RANGE_H_ +#define MRMC_EXCEPTIONS_OUT_OF_RANGE_H_ + +#include + +namespace mrmc { + +namespace exceptions { + +//!This exception is thrown when a parameter is not in the range of valid values +class out_of_range : public std::exception +{ + public: +/* The Visual C++-Version of the exception class has constructors accepting + * a char*-constant; The GCC version does not have these + * + * As the "extended" constructor is used in the sparse matrix code, a dummy + * constructor is used under linux (which will ignore the parameter) + */ +#ifdef _WIN32 + out_of_range() : exception("::mrmc::out_of_range"){} + out_of_range(const char * const s): exception(s) {} +#else + out_of_range() : exception() {} + out_of_range(const char * const s): exception() {} +#endif + virtual const char* what() const throw() + { return "mrmc::out_of_range"; } +}; + +} // namespace exceptions + +} // namespace mrmc +#endif // MRMC_EXCEPTIONS_OUT_OF_RANGE_H_ diff --git a/src/mrmc-cpp.cpp b/src/mrmc-cpp.cpp index c984076a3..aad1a2627 100644 --- a/src/mrmc-cpp.cpp +++ b/src/mrmc-cpp.cpp @@ -13,14 +13,54 @@ */ #include +#include + +#include +#include +PANTHEIOS_EXTERN_C PAN_CHAR_T const PANTHEIOS_FE_PROCESS_IDENTITY[] = "mrmc-cpp"; #include "MRMCConfig.h" + +#include "src/sparse/static_sparse_matrix.h" int main(int argc, char* argv[]) { - + // Logging init + pantheios_be_file_setFilePath("log.all"); + pantheios::log_INFORMATIONAL("MRMC-Cpp started."); + std::cout << "Hello, World." << std::endl; std::cout << "This is MRMC-Cpp Version " << MRMC_CPP_VERSION_MAJOR << "." << MRMC_CPP_VERSION_MINOR << std::endl; + mrmc::sparse::StaticSparseMatrix *ssm = new mrmc::sparse::StaticSparseMatrix(10, 10); + + ssm->initialize(); + ssm->addNextValue(2, 3, 1); + ssm->addNextValue(2, 4, 2); + ssm->addNextValue(2, 5, 3); + ssm->addNextValue(2, 6, 4); + ssm->addNextValue(2, 7, 5); + + ssm->addNextValue(3, 4, 6); + ssm->addNextValue(3, 5, 7); + ssm->addNextValue(3, 6, 8); + ssm->addNextValue(3, 7, 9); + ssm->addNextValue(3, 8, 10); + + ssm->finalize(); + + int target; + + for (int row = 1; row <= 10; ++row) { + for (int col = 1; col <= 10; ++col) { + if (ssm->getValue(row, col, &target)) { + printf(" T%i", target); + } else { + printf(" _%i", target); + } + } + printf("\n"); + } + return 0; } diff --git a/src/parser/read_tra_file.cpp b/src/parser/read_tra_file.cpp new file mode 100644 index 000000000..6c191c910 --- /dev/null +++ b/src/parser/read_tra_file.cpp @@ -0,0 +1,157 @@ +/* TODO: Include the proper description here, with reference to the original authors + * read_tra_file.cpp + * + * Created on: 15.08.2012 + * Author: Thomas Heinemann + */ + +#include "src/parser/read_tra_file.h" +#include "src/exceptions/file_IO_exception.h" +#include "src/exceptions/wrong_file_format.h" +#include "boost/integer/integer_mask.hpp" +#include +#include + +#include +#include +#include + +namespace mrmc { + +namespace parser{ + + +/*! +* This method does the first pass through the .tra file and computes +* the number of non zero elements that are not diagonal elements, +* which correspondents to the number of transitions that are not +* self-loops. +* (Diagonal elements are treated in a special way). +* +* @return The number of non-zero elements that are not on the diagonal +* @param p File stream to scan. Is expected to be opened, a NULL pointer will +* be rejected! +*/ +static uint_fast32_t make_first_pass(FILE* p) { + if(p==NULL) { + pantheios::log_ERROR("make_first_pass was called with NULL! (SHOULD NEVER HAPPEN)"); + throw exceptions::file_IO_exception ("make_first_pass: File not readable (this should be checked before calling this function!)"); + } + + char s[1024], states[7], transitions[12]; + int rows=0, row=0, col=0, non_zero=0; + double val=0.0; + + //Reading No. of states + if (fgets(s, 1024, p) != NULL) { + if (sscanf( s, "STATES %d", &rows) == 0) { + pantheios::log_WARNING(pantheios::integer(rows)); + throw mrmc::exceptions::wrong_file_format(); + } + } + + //Reading No. of transitions + if (fgets(s, 1024, p) != NULL) { + if (sscanf( s, "TRANSITIONS %d", &non_zero) == 0) { + throw mrmc::exceptions::wrong_file_format(); + } + } + + //Reading transitions (one per line) + //And increase number of transitions + while (NULL != fgets( s, 1024, p )) + { + if (sscanf( s, "%d%d%lf", &row, &col, &val ) != 3) { + throw mrmc::exceptions::wrong_file_format(); + } + //Diagonal elements are not counted into the result! + if(row == col) { + --non_zero; + } + } + return non_zero; +} + + + +/*!Reads a .tra file and produces a sparse matrix representing the described Markov Chain. + * @param *filename input .tra file's name. + * @return a pointer to a sparse matrix. + */ + +sparse::StaticSparseMatrix * read_tra_file(const char * filename) +{ + //TODO: Tidy this function up + comment(Thomas Heinemann, 15-08-2012) + FILE *p; + char s[1024]; + uint_fast32_t rows, row, col, nnz, non_zero; + double val = 0.0; + int count = 0; + sparse::StaticSparseMatrix *sp = NULL; + + p = fopen(filename, "r"); + if(p==NULL) { + pantheios::log_ERROR("File ", filename, " was not readable (Does it exist?)"); + throw exceptions::file_IO_exception("mrmc::read_tra_file: Error opening file! (Does it exist?)"); + } + non_zero = make_first_pass(p); + + //Set file reader back to the beginning + rewind(p); + + //Reading No. of states + if (fgets(s, 1024, p) != NULL) { + if (sscanf( s, "STATES %d", &rows) == 0) { + pantheios::log_WARNING(pantheios::integer(rows)); + throw mrmc::exceptions::wrong_file_format(); + } + } + + //Reading No. of transitions + if (fgets(s, 1024, p) != NULL) { + if (sscanf( s, "TRANSITIONS %d", &nnz) == 0) { + throw mrmc::exceptions::wrong_file_format(); + } + } + + pantheios::log_DEBUG("Creating matrix with ", + pantheios::integer(rows), " rows and ", + pantheios::integer(non_zero), " Non-Zero-Elements"); + /* Creating matrix + * Variable non_zero does NOT count any diagonal element, + * But all diagonal elements are allocated, so the number of allocated + * elements is non_zero + */ + sp = new sparse::StaticSparseMatrix(rows,non_zero); + sp->initialize(); + if ( NULL == sp ) { + //TODO: Throw exception (Thomas Heinemann, 15-08-2012) + return NULL; + } + + //Reading transitions (one per line) and saving the results in the matrix + while (NULL != fgets( s, 1024, p )) + { + if (sscanf( s, "%d%d%lf", &row, &col, &val) != 3) { + throw mrmc::exceptions::wrong_file_format(); + } + pantheios::log_DEBUG("Write value ", + pantheios::real(val), + " to position ", + pantheios::integer(row), " x ", + pantheios::integer(col)); + sp->addNextValue(row,col,val); + ++count; + } + + (void)fclose(p); + + pantheios::log_DEBUG("Written ", pantheios::integer(count), " Elements"); + pantheios::log_DEBUG("Finalizing Matrix"); + sp->finalize(); + return sp; +} + +} + +} diff --git a/src/parser/read_tra_file.h b/src/parser/read_tra_file.h new file mode 100644 index 000000000..20886d2f6 --- /dev/null +++ b/src/parser/read_tra_file.h @@ -0,0 +1,20 @@ +/* + * read_tra_file.h + * + * Created on: 15.08.2012 + * Author: Thomas Heinemann + */ + +#ifndef READ_TRA_FILE_H_ +#define READ_TRA_FILE_H_ +#include "src/sparse/static_sparse_matrix.h" +namespace mrmc{ +namespace parser { + +mrmc::sparse::StaticSparseMatrix * read_tra_file(const char * filename); + +} +} + + +#endif /* READ_TRA_FILE_H_ */ diff --git a/src/sparse/static_sparse_matrix.h b/src/sparse/static_sparse_matrix.h new file mode 100644 index 000000000..f57c49bde --- /dev/null +++ b/src/sparse/static_sparse_matrix.h @@ -0,0 +1,199 @@ +#ifndef MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_ +#define MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_ + +#include +#include "boost/integer/integer_mask.hpp" + +#include +#include + +#include "src/exceptions/invalid_state.h" +#include "src/exceptions/invalid_argument.h" +#include "src/exceptions/out_of_range.h" + +namespace mrmc { + +namespace sparse { + +//! A sparse Matrix for DTMCs with a constant number of non-zero entries on the non-diagonal fields. +/*! + The sparse matrix used for calculation on the DTMCs. + Adressing is NOT zero-based! The valid range for getValue and addNextValue is 1 to rows (first argument to constructor). + */ +template +class StaticSparseMatrix { + public: + + //! Constructor + /*! + \param rows Row-Count and therefor column-count of the symetric matrix + \param non_zero_entries The exact count of entries that will be submitted through addNextValue *excluding* those on the diagonal (A_{i,j} with i = j) + */ + StaticSparseMatrix(uint_fast32_t rows, uint_fast32_t non_zero_entries) { + current_size = 0; + storage_size = 0; + + row_count = rows; + non_zero_entry_count = non_zero_entries; + + //initialize(rows, non_zero_entries); + } + + ~StaticSparseMatrix() { + if (value_storage != NULL) { + free(value_storage); + } + if (column_indications != NULL) { + free(column_indications); + } + if (row_indications != NULL) { + free(row_indications); + } + if (diagonal_storage != NULL) { + free(diagonal_storage); + } + } + + //! Getter for saving matrix entry A_{row,col} to target + /*! + Getter function for the matrix. + \param row 1-based index of the requested row + \param col 1-based index of the requested column + \param target pointer to where the result will be stored + \return True iff the value was set, false otherwise. On false, 0 will be written to *target. + */ + inline bool getValue(uint_fast32_t row, uint_fast32_t col, T* const target) { + + if (row == col) { + // storage is row_count + 1 large for direct access without the -1 + *target = diagonal_storage[row]; + return true; + } + + if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) { + throw new mrmc::exceptions::out_of_range("mrmc::StaticSparseMatrix::getValue: row or col not in 1 .. rows"); + } + + uint_fast32_t row_start = row_indications[row - 1]; + uint_fast32_t row_end = row_indications[row]; + + while (row_start < row_end) { + if (column_indications[row_start] == col) { + *target = value_storage[row_start]; + return true; + } + if (column_indications[row_start] > col) { + break; + } + row_start++; + } + + *target = 0; + return false; + } + + //! Mandatory initialization of the matrix + /*! + Mandatory initialization of the matrix, must be called before using any other member function. + */ + void initialize() { + + if (row_count == 0) { + pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument for row_count = 0"); + throw new mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: Matrix with 0 rows is not reasonable"); + } + + if (((row_count * row_count) - row_count) < non_zero_entry_count) { + pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing invalid_argument: More non-zero entries than entries in target matrix"); + throw new mrmc::exceptions::invalid_argument("mrmc::StaticSparseMatrix::initialize: More non-zero entries than entries in target matrix"); + } + + storage_size = non_zero_entry_count; + last_row = 0; + + value_storage = static_cast(calloc(storage_size, sizeof(*value_storage))); + + column_indications = static_cast(calloc(storage_size, sizeof(*column_indications))); + + row_indications = static_cast(calloc(row_count + 1, sizeof(*row_indications))); + + // row_count + 1 so that access with 1-based indices can be direct without the overhead of a -1 each time + diagonal_storage = static_cast(calloc(row_count + 1, sizeof(*diagonal_storage))); + + if ((value_storage == NULL) || (column_indications == NULL) || (row_indications == NULL) || (diagonal_storage == NULL)) { + pantheios::log_ERROR("StaticSparseMatrix::initialize: Throwing bad_alloc: memory allocation failed"); +#ifdef __linux__ + throw new std::bad_alloc(); +#else + throw new std::bad_alloc("mrmc::StaticSparseMatrix::initialize: memory allocation failed"); +#endif + } + } + + //! Linear Setter for matrix entry A_{row, col} to value + /*! + Linear Setter function for matrix entry A_{row, col} to value. Must be called consecutively for each element in a row in ascending order of columns AND in ascending order of rows. + Diagonal entries may be set at any time. + */ + void addNextValue(const uint_fast32_t row, const uint_fast32_t col, const T value) { + if ((row > row_count) || (col > row_count) || (row == 0) || (col == 0)) { + pantheios::log_ERROR("StaticSparseMatrix::addNextValue: Throwing out_of_range: row or col not in 1 .. rows"); + throw new mrmc::exceptions::out_of_range("mrmc::StaticSparseMatrix::addNextValue: row or col not in 1 .. rows"); + } + + if (row == col) { + diagonal_storage[row] = value; + } else { + if (row != last_row) { + for (uint_fast32_t i = last_row; i < row; ++i) { + row_indications[i] = current_size; + } + last_row = row; + } + + value_storage[current_size] = value; + column_indications[current_size] = col; + + // Increment counter for stored elements + current_size++; + } + } + + void finalize() { + if (storage_size != current_size) { + pantheios::log_ERROR("StaticSparseMatrix::finalize: Throwing invalid_state: Wrong call count for addNextValue"); + throw new mrmc::exceptions::invalid_state("mrmc::StaticSparseMatrix::finalize: Wrong call count for addNextValue"); + } + + if (last_row != row_count) { + for (uint_fast32_t i = last_row; i < row_count; ++i) { + row_indications[i] = current_size; + } + } + + row_indications[row_count] = storage_size; + } + private: + uint_fast32_t storage_size; + uint_fast32_t current_size; + + uint_fast32_t row_count; + uint_fast32_t non_zero_entry_count; + uint_fast32_t last_row; + + /*! Array containing all non-zero values, apart from the diagonal entries */ + T* value_storage; + /*! Array containing all diagonal values */ + T* diagonal_storage; + + /*! Array containing the column number of the corresponding value_storage entry */ + uint_fast32_t* column_indications; + /*! Array containing the row boundarys of valueStorage */ + uint_fast32_t* row_indications; +}; + +} // namespace sparse + +} // namespace mrmc + +#endif // MRMC_SPARSE_STATIC_SPARSE_MATRIX_H_ diff --git a/test/mrmc-tests.cpp b/test/mrmc-tests.cpp index a382cf2f4..07493889a 100644 --- a/test/mrmc-tests.cpp +++ b/test/mrmc-tests.cpp @@ -2,11 +2,20 @@ #include "gtest/gtest.h" +#include +#include +#include + +PANTHEIOS_EXTERN_C PAN_CHAR_T const PANTHEIOS_FE_PROCESS_IDENTITY[] = "mrmc-cpp-tests"; + int main(int argc, char** argv) { - std::cout << "Hello, World." << std::endl; - std::cout << "MRMC Testing" << std::endl; + // Logging init + pantheios_be_file_setFilePath("log.tests.all"); + pantheios::log_INFORMATIONAL("MRMC-Cpp Test Suite started."); + pantheios_fe_simple_setSeverityCeiling(PANTHEIOS_SEV_DEBUG); + std::cout << "MRMC Testing Suite" << std::endl; testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file + return RUN_ALL_TESTS(); +} diff --git a/test/parser/read_tra_file_test.cpp b/test/parser/read_tra_file_test.cpp new file mode 100644 index 000000000..c700c95ab --- /dev/null +++ b/test/parser/read_tra_file_test.cpp @@ -0,0 +1,74 @@ +/* + * read_tra_file_test.cpp + * + * Created on: 16.08.2012 + * Author: Thomas Heinemann + */ + +#include "gtest/gtest.h" +#include "src/sparse/static_sparse_matrix.h" +#include "src/parser/read_tra_file.h" +#include "src/exceptions/file_IO_exception.h" +#include "src/exceptions/wrong_file_format.h" +#include + +TEST(ReadTraFileTest, NonExistingFileTest) { + pantheios::log_INFORMATIONAL("Started NonExistingFileTest"); + //No matter what happens, please don't create a file with the name "nonExistingFile.not"! :-) + ASSERT_THROW(mrmc::parser::read_tra_file("nonExistingFile.not"), mrmc::exceptions::file_IO_exception); +} + +/* The following test case is based on one of the original MRMC test cases + */ +TEST(ReadTraFileTest, ParseFileTest1) { + pantheios::log_INFORMATIONAL("Started ParseFileTest1"); + mrmc::sparse::StaticSparseMatrix *result; + ASSERT_NO_THROW(result = mrmc::parser::read_tra_file("test/parser/csl_general_input_01.tra")); + + double val = 0; + ASSERT_TRUE(result->getValue(1,1,&val)); + ASSERT_EQ(val,0.080645161290322580645161290322581); + + ASSERT_TRUE(result->getValue(1,2,&val)); + ASSERT_EQ(val,0.080645161290322580645161290322581); + + //Transition 1->3 was not set in the file, so it is not to appear in the matrix! + ASSERT_FALSE(result->getValue(1,3,&val)); + ASSERT_EQ(val,0); + + ASSERT_TRUE(result->getValue(2,1,&val)); + ASSERT_EQ(val,0.04032258064516129032258064516129); + + ASSERT_TRUE(result->getValue(2,2,&val)); + ASSERT_EQ(val,0.04032258064516129032258064516129); + + ASSERT_TRUE(result->getValue(2,3,&val)); + ASSERT_EQ(val,0.04032258064516129032258064516129); + + ASSERT_TRUE(result->getValue(2,4,&val)); + ASSERT_EQ(val,0.04032258064516129032258064516129); + + ASSERT_TRUE(result->getValue(3,2,&val)); + ASSERT_EQ(val,0.0806451612903225806451612903225812); + + ASSERT_TRUE(result->getValue(3,3,&val)); + ASSERT_EQ(val,0); + + ASSERT_TRUE(result->getValue(3,4,&val)); + ASSERT_EQ(val,0.080645161290322580645161290322581); + + ASSERT_TRUE(result->getValue(4,4,&val)); + ASSERT_EQ(val,0); +} + +TEST(ReadTraFileTest, WrongFormatTestHeader) { + pantheios::log_INFORMATIONAL("Started WrongFormatTestHeader"); + + ASSERT_THROW(mrmc::parser::read_tra_file("test/parser/wrong_format_header.tra"), mrmc::exceptions::wrong_file_format); +} + +TEST(ReadTraFileTest, WrongFormatTestTransition) { + pantheios::log_INFORMATIONAL("Started WrongFormatTestTransition"); + + ASSERT_THROW(mrmc::parser::read_tra_file("test/parser/wrong_format_transition.tra"), mrmc::exceptions::wrong_file_format); +} diff --git a/test/sparse/static_sparse_matrix.cpp b/test/sparse/static_sparse_matrix.cpp new file mode 100644 index 000000000..560211256 --- /dev/null +++ b/test/sparse/static_sparse_matrix.cpp @@ -0,0 +1,104 @@ +#include "gtest/gtest.h" +#include "src/sparse/static_sparse_matrix.h" +#include "src/exceptions/invalid_argument.h" + +TEST(StaticSparseMatrixTest, ZeroRowsTest) { + pantheios::log_INFORMATIONAL("Started ZeroRowsTest"); + mrmc::sparse::StaticSparseMatrix *ssm = new mrmc::sparse::StaticSparseMatrix(0, 50); + + ASSERT_THROW(ssm->initialize(), mrmc::exceptions::invalid_argument); + + delete ssm; +} + +TEST(StaticSparseMatrixTest, TooManyEntriesTest) { + mrmc::sparse::StaticSparseMatrix *ssm = new mrmc::sparse::StaticSparseMatrix(2, 10); + + ASSERT_THROW(ssm->initialize(), mrmc::exceptions::invalid_argument); + + delete ssm; +} + +TEST(StaticSparseMatrixTest, addNextValueTest) { + mrmc::sparse::StaticSparseMatrix *ssm = new mrmc::sparse::StaticSparseMatrix(5, 1); + + ASSERT_NO_THROW(ssm->initialize()); + + ASSERT_THROW(ssm->addNextValue(0, 1, 1), mrmc::exceptions::out_of_range); + ASSERT_THROW(ssm->addNextValue(1, 0, 1), mrmc::exceptions::out_of_range); + ASSERT_THROW(ssm->addNextValue(6, 1, 1), mrmc::exceptions::out_of_range); + ASSERT_THROW(ssm->addNextValue(1, 6, 1), mrmc::exceptions::out_of_range); + + delete ssm; +} + +TEST(StaticSparseMatrixTest, finalizeTest) { + mrmc::sparse::StaticSparseMatrix *ssm = new mrmc::sparse::StaticSparseMatrix(5, 5); + + ASSERT_NO_THROW(ssm->initialize()); + + ASSERT_NO_THROW(ssm->addNextValue(1, 2, 1)); + ASSERT_NO_THROW(ssm->addNextValue(1, 3, 1)); + ASSERT_NO_THROW(ssm->addNextValue(1, 4, 1)); + ASSERT_NO_THROW(ssm->addNextValue(1, 5, 1)); + + ASSERT_THROW(ssm->finalize(), mrmc::exceptions::invalid_state); + + delete ssm; +} + +TEST(StaticSparseMatrixTest, Test) { + // 25 rows, 50 non zero entries + mrmc::sparse::StaticSparseMatrix *ssm = new mrmc::sparse::StaticSparseMatrix(25, 50); + + int values[50] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49 + }; + int position_row[50] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, /* first row empty, one full row � 25 minus the diagonal entry */ + 4, 4, /* one empty row, then first and last column */ + 13, 13, 13, 13, /* a few empty rows, middle columns */ + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 /* second to last row */ + }; + int position_col[50] = { + 1, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, /* first row empty, one full row a 25 */ + 1, 25, /* one empty row, then first and last column */ + 16, 17, 18, 19, /* a few empty rows, middle columns */ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 /* second to last row */ + }; + + ASSERT_NO_THROW(ssm->initialize()); + + for (int i = 0; i < 50; ++i) { + ASSERT_NO_THROW(ssm->addNextValue(position_row[i], position_col[i], values[i])); + } + + ASSERT_NO_THROW(ssm->finalize()); + + int target; + for (int i = 0; i < 50; ++i) { + ASSERT_TRUE(ssm->getValue(position_row[i], position_col[i], &target)); + ASSERT_EQ(values[i], target); + } + + // test for a few of the empty rows + for (int row = 14; row < 24; ++row) { + for (int col = 1; col <= 25; ++col) { + target = 1; + ASSERT_FALSE(ssm->getValue(row, col, &target)); + ASSERT_EQ(0, target); + } + } + + delete ssm; +}