diff --git a/.github/actions/setup-amici-cpp/action.yml b/.github/actions/setup-amici-cpp/action.yml index 09ec9311bf..b5ee4808b8 100644 --- a/.github/actions/setup-amici-cpp/action.yml +++ b/.github/actions/setup-amici-cpp/action.yml @@ -18,6 +18,9 @@ runs: - run: echo "ENABLE_GCOV_COVERAGE=TRUE" >> $GITHUB_ENV shell: bash + - run: echo "PYTHONFAULTHANDLER=1" >> $GITHUB_ENV + shell: bash + - name: Set up Sonar tools uses: ./.github/actions/setup-sonar-tools diff --git a/.github/workflows/deploy_protected.yml b/.github/workflows/deploy_protected.yml index 5b32786c37..881a4eb77a 100644 --- a/.github/workflows/deploy_protected.yml +++ b/.github/workflows/deploy_protected.yml @@ -13,9 +13,25 @@ on: workflow_dispatch: jobs: + check-secret: + runs-on: ubuntu-latest + outputs: + secrets-defined: ${{ steps.secret-check.outputs.defined }} + steps: + - name: Check for Secret availability + id: secret-check + shell: bash + run: | + if [ "${{ secrets.DOCKER_USERNAME }}" != '' ]; then + echo "defined=true" >> $GITHUB_OUTPUT; + else + echo "defined=false" >> $GITHUB_OUTPUT; + fi + dockerhub: name: Deploy Dockerhub - if: github.event.pull_request.head.repo.fork == false + needs: [check-secret] + if: needs.check-secret.outputs.secrets-defined == 'true' runs-on: ubuntu-22.04 strategy: diff --git a/.github/workflows/test_petab_test_suite.yml b/.github/workflows/test_petab_test_suite.yml index 6301269e03..b6465d554b 100644 --- a/.github/workflows/test_petab_test_suite.yml +++ b/.github/workflows/test_petab_test_suite.yml @@ -57,7 +57,7 @@ jobs: - name: Install petab run: | - source ./build/venv/bin/activate \ + source ./venv/bin/activate \ && pip3 install wheel pytest shyaml pytest-cov pysb # retrieve test models @@ -65,19 +65,19 @@ jobs: run: | git clone --depth 1 --branch main \ https://github.com/PEtab-dev/petab_test_suite \ - && source ./build/venv/bin/activate \ + && source ./venv/bin/activate \ && cd petab_test_suite && pip3 install -e . - name: Run PEtab-related unit tests run: | - source ./build/venv/bin/activate \ + source ./venv/bin/activate \ && pytest --cov-report=xml:coverage.xml \ --cov=./ python/tests/test_*petab*.py python/tests/petab/ # run test models - name: Run PEtab test suite run: | - source ./build/venv/bin/activate \ + source ./venv/bin/activate \ && AMICI_PARALLEL_COMPILE="" pytest -v \ --cov-report=xml:coverage.xml \ --cov-append \ diff --git a/.github/workflows/test_python_cplusplus.yml b/.github/workflows/test_python_cplusplus.yml index fb90476eb8..f729d47867 100644 --- a/.github/workflows/test_python_cplusplus.yml +++ b/.github/workflows/test_python_cplusplus.yml @@ -18,6 +18,13 @@ jobs: python-version: [ "3.9" ] steps: + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/.cache/pooch + key: ${{ runner.os }}-py${{ matrix.python-version }}-${{ github.job }} + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: @@ -38,11 +45,11 @@ jobs: run: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source build/venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" + run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" - name: Python tests (part 1) run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pytest \ --ignore-glob=*petab* \ --ignore-glob=*test_splines.py \ @@ -57,7 +64,7 @@ jobs: - name: Python tests splines if: ${{ github.base_ref == 'master' || github.event.merge_group.base_ref == 'master'}} run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pytest \ --cov=amici \ --cov-report=xml:"${AMICI_DIR}/build/coverage_py.xml" \ @@ -131,7 +138,7 @@ jobs: - name: Python tests run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pytest \ --cov=amici \ --cov-report=xml:"${AMICI_DIR}/build/coverage_py.xml" \ @@ -207,7 +214,7 @@ jobs: - name: Install notebook dependencies run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && pip install jax[cpu] - name: example notebooks @@ -244,7 +251,7 @@ jobs: run: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source build/venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" + run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" - name: cppcheck run: scripts/run-cppcheck.sh @@ -265,6 +272,13 @@ jobs: runs-on: macos-latest steps: + - name: Cache + uses: actions/cache@v3 + with: + path: | + ~/Library/Caches/pooch + key: ${{ runner.os }}-py${{ matrix.python-version }}-${{ github.job }} + - name: Set up Python uses: actions/setup-python@v5 with: @@ -282,7 +296,7 @@ jobs: scripts/installAmiciSource.sh - name: Check OpenMP support - run: source build/venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" + run: source venv/bin/activate && python -c "import amici; import sys; sys.exit(not amici.compiledWithOpenMP())" - name: Get BioNetGen run: scripts/buildBNGL.sh diff --git a/.github/workflows/test_python_ver_matrix.yml b/.github/workflows/test_python_ver_matrix.yml index 5f9d96d295..414daadccc 100644 --- a/.github/workflows/test_python_ver_matrix.yml +++ b/.github/workflows/test_python_ver_matrix.yml @@ -50,20 +50,16 @@ jobs: - name: Install python package run: scripts/installAmiciSource.sh - # until https://github.com/dateutil/dateutil >2.8.2 is released https://github.com/dateutil/dateutil/issues/1314 - - run: source build/venv/bin/activate && pip3 install git+https://github.com/dateutil/dateutil.git@296d419fe6bf3b22897f8f210735ac9c4e1cb796 - if: matrix.python-version == '3.12' - # install pysb before sympy to allow for sympy>=1.12 (https://github.com/pysb/pysb/commit/e83937cb8c74afc9b2fa96595b68464946745f33) - - run: source build/venv/bin/activate && pip3 install git+https://github.com/pysb/pysb + - run: source venv/bin/activate && pip3 install git+https://github.com/pysb/pysb # until sympy>1.12 is released - - run: source build/venv/bin/activate && pip3 install git+https://github.com/sympy/sympy.git@master + - run: source venv/bin/activate && pip3 install git+https://github.com/sympy/sympy.git@master if: matrix.python-version == '3.12' - name: Python tests run: | - source build/venv/bin/activate \ + source venv/bin/activate \ && python3 -m pytest \ --durations=10 \ --ignore-glob=*petab* \ diff --git a/.github/workflows/test_sbml_semantic_test_suite.yml b/.github/workflows/test_sbml_semantic_test_suite.yml index ddc78e1b89..3c0b3bd149 100644 --- a/.github/workflows/test_sbml_semantic_test_suite.yml +++ b/.github/workflows/test_sbml_semantic_test_suite.yml @@ -9,7 +9,7 @@ on: paths: - .github/workflows/test_sbml_semantic_test_suite.yml - python/sdist/amici/de_export.py - - python/sdist/amici/de_model.py + - python/sdist/amici/de_model_components.py - python/sdist/amici/sbml_import.py - python/sdist/amici/import_utils.py - scripts/run-SBMLTestsuite.sh diff --git a/.gitignore b/.gitignore index 60b9ff5031..4dc2884415 100644 --- a/.gitignore +++ b/.gitignore @@ -202,3 +202,4 @@ CS_Signalling_ERBB_RAS_AKT/ cache_fiddy/* debug/* tests/benchmark-models/cache_fiddy/* +venv/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c1fd68c5c..ec825fa325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,76 @@ ## v0.X Series +### v0.23.0 (2024-03-07) + +**Features** + +* SBML `InitialAssignment` are no longer absorbed into other model expressions, + but are available as parameters or expressions (`w`) in the amici model + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2304, + https://github.com/AMICI-dev/AMICI/pull/2305, + https://github.com/AMICI-dev/AMICI/pull/2345, + https://github.com/AMICI-dev/AMICI/pull/2359 +* Upgraded to SuiteSparse 7.6 + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2316 +* Model expressions `w` are now split into static and dynamic expressions, + and only evaluated as needed + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2303 +* Exposed additional solver settings: + * `Solver.setMaxConvFails()`: maximum number of non-linear solver + convergence failures + * `Solver.setMaxNonlinIters()`: maximum number of non-linear solver + iterations + * `Solver.setMaxStepSize()`: maximum step size + * `Solver.setConstraints()`: for setting (non)negativity/positivity + constraints on state variables + + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2335, + https://github.com/AMICI-dev/AMICI/pull/2360, + https://github.com/AMICI-dev/AMICI/pull/2340 +* Improved output for debugging simulation failures: + `ReturnData.{xdot,J}` now contain the respective + values from the timepoint of failure, not the last output timepoint. + NaN/Inf warnings now always include the timepoint at which the issue + occurred. Note that C++ stacktraces are now only logged for debug builds. + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2349, + https://github.com/AMICI-dev/AMICI/pull/2347, + https://github.com/AMICI-dev/AMICI/pull/2366 +* Updated dataframes import/export to include parameter values and scales + by @FFroehlich in https://github.com/AMICI-dev/AMICI/pull/2351 + +**Fixes** + +* CMake: Updated BLAS detection and some minor fixes + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2318 + and https://github.com/AMICI-dev/AMICI/pull/2357 +* Deterministic ordering of source files in generated `CMakeLists.txt` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2322 +* Fixed size check in `Model::setStateIsNonNegative` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2332 +* Fixed uncaught C++ exception in `runAmiciSimulation` that may crash Python + in case of invalid values for standard deviations + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2338 +* Fixed missing import in `amici/petab/petab_import.py` + by @plakrisenko in https://github.com/AMICI-dev/AMICI/pull/2342 +* Fixed `ReturnDataView` `AttributeError: messages` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2341 +* Added a missing return code constant `LSETUP_FAIL` + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2353 +* Fixed in-place building of model wheels + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2352 +* Made is-zero-checks compatible with the upcoming sympy>1.12 + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2350 +* Fixed issues with paths containing blanks for sundials + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2361 +* Added `amici.petab.conditions` to the API documentation + by @PaulJonasJost in https://github.com/AMICI-dev/AMICI/pull/2364 +* Improved type annotations in swig-wrappers + by @dweindl in https://github.com/AMICI-dev/AMICI/pull/2344, + https://github.com/AMICI-dev/AMICI/pull/2365 + +**Full Changelog**: https://github.com/AMICI-dev/AMICI/compare/v0.22.0...v0.23.0 + ### v0.22.0 (2024-02-23) **Features** diff --git a/CMakeLists.txt b/CMakeLists.txt index 032a9fb084..744847930d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,7 @@ endif() # find dependencies include(GNUInstallDirs) +include(AmiciFindBLAS) find_package(OpenMP) find_package(Boost COMPONENTS chrono) @@ -142,49 +143,6 @@ message(STATUS "Found SUNDIALS: ${SUNDIALS_DIR}") set(GSL_LITE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/gsl") -# AMICI requires BLAS, currently Intel MKL, CBLAS or MATLAB BLAS can be used. -# The latter is not supported via CMake yet. -set(BLAS - "CBLAS" - CACHE STRING "BLAS library to use") -set_property(CACHE BLAS PROPERTY STRINGS "CBLAS" "MKL" "ACCELERATE") -if(${BLAS} STREQUAL "MKL" OR DEFINED ENV{MKLROOT}) - if(DEFINED ENV{MKLROOT}) - # This is set by Environment Modules - message(STATUS "Using MKL_INCDIR and MKL_LIB from environment module") - set(BLAS - "MKL" - CACHE STRING "BLAS library to use" FORCE) - set(BLAS_INCLUDE_DIRS - "$ENV{MKL_INCDIR}" - CACHE STRING "" FORCE) - set(BLAS_LIBRARIES - "$ENV{MKL_LIB}" - CACHE STRING "" FORCE) - else() - set(BLAS_INCLUDE_DIRS - "" - CACHE STRING "") - set(BLAS_LIBRARIES - -lmkl - CACHE STRING "") - endif() -elseif(NOT DEFINED ENV{BLAS_LIBS} AND NOT DEFINED ENV{BLAS_CFLAGS}) - # if nothing is specified via environment variables, let's try FindBLAS - find_package(BLAS) - if(NOT BLAS_FOUND) - # Nothing specified by the user and FindBLAS didn't find anything; let's try - # if cblas is available on the system paths. - set(BLAS_INCLUDE_DIRS - "" - CACHE STRING "") - set(BLAS_LIBRARIES - -lcblas - CACHE STRING "") - endif() -endif() -add_compile_definitions(AMICI_BLAS_${BLAS}) - # Add target to create version file add_custom_target( version @@ -259,16 +217,6 @@ set(AMICI_SRC_LIST add_library(${PROJECT_NAME} ${AMICI_SRC_LIST}) -# legacy python package environment variables: -if(DEFINED ENV{BLAS_CFLAGS}) - target_compile_options(${PROJECT_NAME} PRIVATE "$ENV{BLAS_CFLAGS}") -endif() -if(DEFINED ENV{BLAS_LIBS}) - # Note that, on Windows, at least for ninja, this will only work with dashes - # instead of slashes in any linker options - target_link_libraries(${PROJECT_NAME} PUBLIC "$ENV{BLAS_LIBS}") -endif() - set(AMICI_CXX_OPTIONS "" CACHE STRING "C++ options for libamici (semicolon-separated)") @@ -289,10 +237,6 @@ target_include_directories( $ PRIVATE ${SUNDIALS_PRIVATE_INCLUDE_DIRS}) -if(NOT "${BLAS_INCLUDE_DIRS}" STREQUAL "") - target_include_directories(${PROJECT_NAME} PUBLIC ${BLAS_INCLUDE_DIRS}) -endif() - if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}" OR CMAKE_BUILD_TYPE MATCHES "Debug") @@ -328,11 +272,11 @@ target_link_libraries( SUNDIALS::sunnonlinsolfixedpoint_static SUNDIALS::cvodes_static SUNDIALS::idas_static - ${BLAS_LIBRARIES} $<$:Boost::chrono> $<$:OpenMP::OpenMP_CXX> ${CMAKE_DL_LIBS} PRIVATE + BLAS::BLAS $<$:SUNDIALS::sundials_sunlinsolsuperlumt> ) @@ -431,9 +375,11 @@ install( EXPORT AmiciTargets DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Amici" NAMESPACE Upstream::) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Amici) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/AmiciConfigVersion.cmake + ${CMAKE_CURRENT_LIST_DIR}/cmake/AmiciFindBLAS.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Amici) install(DIRECTORY ThirdParty/gsl/gsl TYPE INCLUDE) # When running from setup.py, this is a symlink we need to dereference @@ -441,6 +387,9 @@ get_filename_component(_swig_realpath "swig" REALPATH) install(DIRECTORY "${_swig_realpath}" DESTINATION ${CMAKE_INSTALL_DATADIR}/amici) +configure_file(cmake/AmiciFindBLAS.cmake + ${CMAKE_CURRENT_BINARY_DIR}/AmiciFindBLAS.cmake COPYONLY) + # Register package? if(EXPORT_PACKAGE) export(PACKAGE Amici) diff --git a/ThirdParty/SuiteSparse/.gitignore b/ThirdParty/SuiteSparse/.gitignore index d0d4223fd7..82b356ef4c 100644 --- a/ThirdParty/SuiteSparse/.gitignore +++ b/ThirdParty/SuiteSparse/.gitignore @@ -127,6 +127,7 @@ CSparse/Tcov/cov.sort CSparse/Tcov/cover.out CSparse/Tcov/covs.out CSparse/Tcov/cs_*.c +CSparse/Tcov/csparse_version.c CSparse/Tcov/cstcov_test CSparse/Tcov/*.out CSparse/Tcov/cs_demo1 @@ -138,6 +139,7 @@ CXSparse/Tcov/cov.sort CXSparse/Tcov/cover.out CXSparse/Tcov/covs.out CXSparse/Tcov/cs_*.c +CXSparse/Tcov/cxsparse_version.c CXSparse/Tcov/*.out CXSparse/Tcov/cs_demo1_ci CXSparse/Tcov/cs_demo1_cl @@ -168,7 +170,9 @@ SPQR/Tcov/gpu_results.txt SPQR/Tcov/gpuqrengine_demo SPQR/Tcov/qrdemo_gpu SPQR/Tcov/qrtest +SPQR/Tcov/qrtest32 SPQR/Tcov/qrtest_out.txt +SPQR/Tcov/qrtest_out32.txt SPQR/Tcov/troll.m SPQR/Tcov/cov.out diff --git a/ThirdParty/SuiteSparse/AMD/CMakeLists.txt b/ThirdParty/SuiteSparse/AMD/CMakeLists.txt index 4fdf61499f..3253759112 100644 --- a/ThirdParty/SuiteSparse/AMD/CMakeLists.txt +++ b/ThirdParty/SuiteSparse/AMD/CMakeLists.txt @@ -2,7 +2,7 @@ # SuiteSparse/AMD/CMakeLists.txt: cmake for AMD #------------------------------------------------------------------------------- -# Copyright (c) 1996-2022, Timothy A. Davis, Patrick Amestoy, Iain Duff. +# Copyright (c) 1996-2023, Timothy A. Davis, Patrick Amestoy, Iain Duff. # All Rights Reserved. # SPDX-License-Identifier: BSD-3-clause @@ -10,12 +10,12 @@ # get the version #------------------------------------------------------------------------------- -cmake_minimum_required ( VERSION 3.19 ) +cmake_minimum_required ( VERSION 3.22 ) -set ( AMD_DATE "Jan 17, 2023" ) -set ( AMD_VERSION_MAJOR 3 ) -set ( AMD_VERSION_MINOR 0 ) -set ( AMD_VERSION_SUB 3 ) +set ( AMD_DATE "Jan 10, 2024" ) +set ( AMD_VERSION_MAJOR 3 CACHE STRING "" FORCE ) +set ( AMD_VERSION_MINOR 3 CACHE STRING "" FORCE ) +set ( AMD_VERSION_SUB 1 CACHE STRING "" FORCE ) message ( STATUS "Building AMD version: v" ${AMD_VERSION_MAJOR}. @@ -23,41 +23,38 @@ message ( STATUS "Building AMD version: v" ${AMD_VERSION_SUB} " (" ${AMD_DATE} ")" ) #------------------------------------------------------------------------------- -# SuiteSparse policies +# define the project #------------------------------------------------------------------------------- -set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules - ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) - -include ( SuiteSparsePolicy ) +project ( AMD + VERSION "${AMD_VERSION_MAJOR}.${AMD_VERSION_MINOR}.${AMD_VERSION_SUB}" + LANGUAGES C ) #------------------------------------------------------------------------------- -# define the project +# SuiteSparse policies #------------------------------------------------------------------------------- -if ( WIN32 ) - # disable Fortran in AMD when compiling on Windows - set ( NFORTRAN true ) -endif ( ) +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${PROJECT_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) + +include ( SuiteSparsePolicy ) -if ( NOT NFORTRAN ) +if ( SUITESPARSE_HAS_FORTRAN ) # Fortan is available and enabled - project ( amd - VERSION "${AMD_VERSION_MAJOR}.${AMD_VERSION_MINOR}.${AMD_VERSION_SUB}" - LANGUAGES C Fortran ) -else ( ) - # no Fortran compiler available; do not compile Source/*.f or Demo/*.f - project ( amd - VERSION "${AMD_VERSION_MAJOR}.${AMD_VERSION_MINOR}.${AMD_VERSION_SUB}" - LANGUAGES C ) + enable_language ( Fortran ) endif ( ) #------------------------------------------------------------------------------- # find library dependencies #------------------------------------------------------------------------------- -find_package ( SuiteSparse_config 7.0.0 REQUIRED ) +if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) + find_package ( SuiteSparse_config 7.5.0 + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_package ( SuiteSparse_config 7.5.0 REQUIRED ) + endif ( ) +endif ( ) #------------------------------------------------------------------------------- # configure files @@ -72,59 +69,91 @@ configure_file ( "Config/amd_version.tex.in" "${PROJECT_SOURCE_DIR}/Doc/amd_vers # include directories #------------------------------------------------------------------------------- -include_directories ( Source Include ${SUITESPARSE_CONFIG_INCLUDE_DIR} ) +include_directories ( Source Include ) #------------------------------------------------------------------------------- # dynamic amd library properties #------------------------------------------------------------------------------- -if ( NOT NFORTRAN ) +if ( SUITESPARSE_HAS_FORTRAN ) file ( GLOB AMD_SOURCES "Source/*.c" "Source/*.f" ) else ( ) file ( GLOB AMD_SOURCES "Source/*.c" ) endif ( ) -add_library ( amd SHARED ${AMD_SOURCES} ) -set_target_properties ( amd PROPERTIES - VERSION ${AMD_VERSION_MAJOR}.${AMD_VERSION_MINOR}.${AMD_VERSION_SUB} - C_STANDARD_REQUIRED 11 - SOVERSION ${AMD_VERSION_MAJOR} - PUBLIC_HEADER "Include/amd.h" - WINDOWS_EXPORT_ALL_SYMBOLS ON ) +if ( BUILD_SHARED_LIBS ) + add_library ( AMD SHARED ${AMD_SOURCES} ) + set_target_properties ( AMD PROPERTIES + VERSION ${AMD_VERSION_MAJOR}.${AMD_VERSION_MINOR}.${AMD_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + OUTPUT_NAME amd + SOVERSION ${AMD_VERSION_MAJOR} + PUBLIC_HEADER "Include/amd.h" + WINDOWS_EXPORT_ALL_SYMBOLS ON ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( AMD PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( AMD + INTERFACE $ + $ ) +endif ( ) #------------------------------------------------------------------------------- # static amd library properties #------------------------------------------------------------------------------- -if ( NOT NSTATIC ) - add_library ( amd_static STATIC ${AMD_SOURCES} ) - set_target_properties ( amd_static PROPERTIES - VERSION ${AMD_VERSION_MAJOR}.${AMD_VERSION_MINOR}.${AMD_VERSION_SUB} - C_STANDARD_REQUIRED 11 +if ( BUILD_STATIC_LIBS ) + add_library ( AMD_static STATIC ${AMD_SOURCES} ) + set_target_properties ( AMD_static PROPERTIES + C_STANDARD 11 + C_STANDARD_REQUIRED ON OUTPUT_NAME amd - SOVERSION ${AMD_VERSION_MAJOR} ) + PUBLIC_HEADER "Include/amd.h" ) if ( MSVC ) - set_target_properties ( amd_static PROPERTIES + set_target_properties ( AMD_static PROPERTIES OUTPUT_NAME amd_static ) endif ( ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( AMD_static PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( AMD_static + INTERFACE $ + $ ) + endif ( ) #------------------------------------------------------------------------------- # add the library dependencies #------------------------------------------------------------------------------- -# suitesparseconfig: -target_link_libraries ( amd PUBLIC ${SUITESPARSE_CONFIG_LIBRARIES} ) -if ( NOT NSTATIC ) - target_link_libraries ( amd_static PUBLIC ${SUITESPARSE_CONFIG_STATIC} ) +# SuiteSparseConfig: +if ( BUILD_SHARED_LIBS ) + target_link_libraries ( AMD PRIVATE SuiteSparse::SuiteSparseConfig ) + target_include_directories ( AMD PUBLIC + "$" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + if ( TARGET SuiteSparse::SuiteSparseConfig_static ) + target_link_libraries ( AMD_static PUBLIC SuiteSparse::SuiteSparseConfig_static ) + else ( ) + target_link_libraries ( AMD_static PUBLIC SuiteSparse::SuiteSparseConfig ) + endif ( ) endif ( ) # libm: if ( NOT WIN32 ) - target_link_libraries ( amd PUBLIC m ) - if ( NOT NSTATIC ) - target_link_libraries ( amd_static PUBLIC m ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( AMD PRIVATE m ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + set ( AMD_STATIC_LIBS "${AMD_STATIC_LIBS} -lm" ) + target_link_libraries ( AMD_static PUBLIC m ) endif ( ) endif ( ) @@ -132,25 +161,99 @@ endif ( ) # AMD installation location #------------------------------------------------------------------------------- -install ( TARGETS amd - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} - RUNTIME DESTINATION ${SUITESPARSE_BINDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) -install ( FILES ${CMAKE_SOURCE_DIR}/cmake_modules/FindAMD.cmake - DESTINATION ${SUITESPARSE_LIBDIR}/cmake/SuiteSparse - COMPONENT Development ) -if ( NOT NSTATIC ) - install ( TARGETS amd_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) +include ( CMakePackageConfigHelpers ) + +if ( BUILD_SHARED_LIBS ) + install ( TARGETS AMD + EXPORT AMDTargets + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + install ( TARGETS AMD_static + EXPORT AMDTargets + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) + +# create (temporary) export target file during build +export ( EXPORT AMDTargets + NAMESPACE SuiteSparse:: + FILE ${CMAKE_CURRENT_BINARY_DIR}/AMDTargets.cmake ) + +# install export target, config and version files for find_package +install ( EXPORT AMDTargets + NAMESPACE SuiteSparse:: + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/AMD ) + +# generate config file to be used in common build tree +set ( SUITESPARSE_IN_BUILD_TREE ON ) +configure_package_config_file ( + Config/AMDConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/AMDConfig.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/AMDConfig.cmake ) + +# generate config file to be installed +set ( SUITESPARSE_IN_BUILD_TREE OFF ) +configure_package_config_file ( + Config/AMDConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/target/AMDConfig.cmake + INSTALL_DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/AMD ) + +write_basic_package_version_file ( + ${CMAKE_CURRENT_BINARY_DIR}/AMDConfigVersion.cmake + COMPATIBILITY SameMajorVersion ) + +install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/target/AMDConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/AMDConfigVersion.cmake + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/AMD ) + +#------------------------------------------------------------------------------- +# create pkg-config file +#------------------------------------------------------------------------------- + +if ( NOT MSVC ) + set ( prefix "${CMAKE_INSTALL_PREFIX}" ) + set ( exec_prefix "\${prefix}" ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_LIBDIR SUITESPARSE_LIBDIR_IS_ABSOLUTE ) + if (SUITESPARSE_LIBDIR_IS_ABSOLUTE) + set ( libdir "${SUITESPARSE_LIBDIR}") + else ( ) + set ( libdir "\${exec_prefix}/${SUITESPARSE_LIBDIR}") + endif ( ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_INCLUDEDIR SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE ) + if (SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE) + set ( includedir "${SUITESPARSE_INCLUDEDIR}") + else ( ) + set ( includedir "\${prefix}/${SUITESPARSE_INCLUDEDIR}") + endif ( ) + if ( BUILD_SHARED_LIBS ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + endif ( ) + configure_file ( + Config/AMD.pc.in + AMD.pc.out + @ONLY + NEWLINE_STYLE LF ) + file ( GENERATE + OUTPUT AMD.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/AMD.pc.out + NEWLINE_STYLE LF ) + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/AMD.pc + DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) endif ( ) #------------------------------------------------------------------------------- # Demo library and programs #------------------------------------------------------------------------------- -option ( DEMO "ON: Build the demo programs. OFF (default): do not build the demo programs." off ) -if ( DEMO ) +if ( SUITESPARSE_DEMOS ) #--------------------------------------------------------------------------- # demo library @@ -166,19 +269,30 @@ if ( DEMO ) add_executable ( amd_l_demo "Demo/amd_l_demo.c" ) add_executable ( amd_demo2 "Demo/amd_demo2.c" ) add_executable ( amd_simple "Demo/amd_simple.c" ) - if ( NOT NFORTRAN ) + if ( SUITESPARSE_HAS_FORTRAN ) add_executable ( amd_f77demo "Demo/amd_f77demo.f" ) add_executable ( amd_f77simple "Demo/amd_f77simple.f" ) endif ( ) # Libraries required for Demo programs - target_link_libraries ( amd_demo PUBLIC amd ) - target_link_libraries ( amd_l_demo PUBLIC amd ) - target_link_libraries ( amd_demo2 PUBLIC amd ) - target_link_libraries ( amd_simple PUBLIC amd ) - if ( NOT NFORTRAN ) - target_link_libraries ( amd_f77demo PUBLIC amd ) - target_link_libraries ( amd_f77simple PUBLIC amd ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( amd_demo PUBLIC AMD ) + target_link_libraries ( amd_l_demo PUBLIC AMD ) + target_link_libraries ( amd_demo2 PUBLIC AMD ) + target_link_libraries ( amd_simple PUBLIC AMD ) + if ( SUITESPARSE_HAS_FORTRAN ) + target_link_libraries ( amd_f77demo PUBLIC AMD ) + target_link_libraries ( amd_f77simple PUBLIC AMD ) + endif ( ) + else ( ) + target_link_libraries ( amd_demo PUBLIC AMD_static ) + target_link_libraries ( amd_l_demo PUBLIC AMD_static ) + target_link_libraries ( amd_demo2 PUBLIC AMD_static ) + target_link_libraries ( amd_simple PUBLIC AMD_static ) + if ( SUITESPARSE_HAS_FORTRAN ) + target_link_libraries ( amd_f77demo PUBLIC AMD_static ) + target_link_libraries ( amd_f77simple PUBLIC AMD_static ) + endif ( ) endif ( ) else ( ) @@ -192,4 +306,3 @@ endif ( ) #------------------------------------------------------------------------------- include ( SuiteSparseReport ) - diff --git a/ThirdParty/SuiteSparse/AMD/Config/AMD.pc.in b/ThirdParty/SuiteSparse/AMD/Config/AMD.pc.in new file mode 100644 index 0000000000..e5b509861f --- /dev/null +++ b/ThirdParty/SuiteSparse/AMD/Config/AMD.pc.in @@ -0,0 +1,17 @@ +# AMD, Copyright (c) 1996-2023, Timothy A. Davis. +# All Rights Reserved. +# SPDX-License-Identifier: BSD-3-Clause + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: AMD +URL: https://github.com/DrTimothyAldenDavis/SuiteSparse +Description: Routines for permuting sparse matrices prior to factorization in SuiteSparse +Version: @AMD_VERSION_MAJOR@.@AMD_VERSION_MINOR@.@AMD_VERSION_SUB@ +Requires.private: SuiteSparse_config +Libs: -L${libdir} -l@SUITESPARSE_LIB_BASE_NAME@ +Libs.private: @AMD_STATIC_LIBS@ +Cflags: -I${includedir} diff --git a/ThirdParty/SuiteSparse/AMD/Config/AMDConfig.cmake.in b/ThirdParty/SuiteSparse/AMD/Config/AMDConfig.cmake.in new file mode 100644 index 0000000000..d21e050171 --- /dev/null +++ b/ThirdParty/SuiteSparse/AMD/Config/AMDConfig.cmake.in @@ -0,0 +1,152 @@ +#------------------------------------------------------------------------------- +# SuiteSparse/AMD/cmake_modules/AMDConfig.cmake +#------------------------------------------------------------------------------- + +# The following copyright and license applies to just this file only, not to +# the library itself: +# AMDConfig.cmake, Copyright (c) 2023, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: BSD-3-clause + +#------------------------------------------------------------------------------- + +# Finds the AMD include file and compiled library. +# The following targets are defined: +# SuiteSparse::AMD - for the shared library (if available) +# SuiteSparse::AMD_static - for the static library (if available) + +# For backward compatibility the following variables are set: + +# AMD_INCLUDE_DIR - where to find amd.h +# AMD_LIBRARY - dynamic AMD library +# AMD_STATIC - static AMD library +# AMD_LIBRARIES - libraries when using AMD +# AMD_FOUND - true if AMD found + +# Set ``CMAKE_MODULE_PATH`` to the parent folder where this module file is +# installed. + +#------------------------------------------------------------------------------- + +@PACKAGE_INIT@ + +set ( AMD_DATE "@AMD_DATE@" ) +set ( AMD_VERSION_MAJOR @AMD_VERSION_MAJOR@ ) +set ( AMD_VERSION_MINOR @AMD_VERSION_MINOR@ ) +set ( AMD_VERSION_PATCH @AMD_VERSION_SUB@ ) +set ( AMD_VERSION "@AMD_VERSION_MAJOR@.@AMD_VERSION_MINOR@.@AMD_VERSION_SUB@" ) + +# Check for dependent targets +include ( CMakeFindDependencyMacro ) + +# Look for SuiteSparse_config target +if ( @SUITESPARSE_IN_BUILD_TREE@ ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + # First check in a common build tree + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT SuiteSparse_config_FOUND ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) + endif ( ) +else ( ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) +endif ( ) +if ( NOT SuiteSparse_config_FOUND ) + set ( AMD_FOUND OFF ) + return ( ) +endif ( ) + + +# Import target +include ( ${CMAKE_CURRENT_LIST_DIR}/AMDTargets.cmake ) + +# The following is only for backward compatibility with FindAMD. + +set ( _target_shared SuiteSparse::AMD ) +set ( _target_static SuiteSparse::AMD_static ) +set ( _var_prefix "AMD" ) + +if ( NOT @BUILD_SHARED_LIBS@ AND NOT TARGET ${_target_shared} ) + # make sure there is always an import target without suffix ) + add_library ( ${_target_shared} ALIAS ${_target_static} ) +endif ( ) + +get_target_property ( ${_var_prefix}_INCLUDE_DIR ${_target_shared} INTERFACE_INCLUDE_DIRECTORIES ) +if ( ${_var_prefix}_INCLUDE_DIR ) + # First item in SuiteSparse targets contains the "main" header directory. + list ( GET ${_var_prefix}_INCLUDE_DIR 0 ${_var_prefix}_INCLUDE_DIR ) +endif ( ) +get_target_property ( ${_var_prefix}_LIBRARY ${_target_shared} IMPORTED_IMPLIB ) +if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} IMPORTED_LOCATION ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) +endif ( ) +if ( TARGET ${_target_static} ) + get_target_property ( ${_var_prefix}_STATIC ${_target_static} IMPORTED_LOCATION ) +endif ( ) + +# Check for most common build types +set ( _config_types "Debug" "Release" "RelWithDebInfo" "MinSizeRel" "None" ) + +get_property ( _isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) +if ( _isMultiConfig ) + # For multi-configuration generators (e.g., Visual Studio), prefer those + # configurations. + list ( PREPEND _config_types ${CMAKE_CONFIGURATION_TYPES} ) +else ( ) + # For single-configuration generators, prefer the current configuration. + list ( PREPEND _config_types ${CMAKE_BUILD_TYPE} ) +endif ( ) + +list ( REMOVE_DUPLICATES _config_types ) + +foreach ( _config ${_config_types} ) + string ( TOUPPER ${_config} _uc_config ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_IMPLIB_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( TARGET ${_target_static} AND NOT ${_var_prefix}_STATIC ) + get_target_property ( _library_chk ${_target_static} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_STATIC ${_library_chk} ) + endif ( ) + endif ( ) +endforeach ( ) + +set ( AMD_LIBRARIES ${AMD_LIBRARY} ) + +macro ( suitesparse_check_exist _var _files ) + # ignore generator expressions + string ( GENEX_STRIP "${_files}" _files2 ) + + foreach ( _file ${_files2} ) + if ( NOT EXISTS "${_file}" ) + message ( FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist!" ) + endif ( ) + endforeach () +endmacro ( ) + +suitesparse_check_exist ( AMD_INCLUDE_DIR ${AMD_INCLUDE_DIR} ) +suitesparse_check_exist ( AMD_LIBRARY ${AMD_LIBRARY} ) + +message ( STATUS "AMD version: ${AMD_VERSION}" ) +message ( STATUS "AMD include: ${AMD_INCLUDE_DIR}") +message ( STATUS "AMD library: ${AMD_LIBRARY}") +message ( STATUS "AMD static: ${AMD_STATIC}") diff --git a/ThirdParty/SuiteSparse/AMD/Config/amd.h.in b/ThirdParty/SuiteSparse/AMD/Config/amd.h.in index f2a6916654..3192e11391 100644 --- a/ThirdParty/SuiteSparse/AMD/Config/amd.h.in +++ b/ThirdParty/SuiteSparse/AMD/Config/amd.h.in @@ -2,7 +2,7 @@ // AMD/Include/amd.h: approximate minimum degree ordering //------------------------------------------------------------------------------ -// AMD, Copyright (c) 1996-2022, Timothy A. Davis, Patrick R. Amestoy, and +// AMD, Copyright (c) 1996-2024, Timothy A. Davis, Patrick R. Amestoy, and // Iain S. Duff. All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause @@ -35,13 +35,13 @@ #ifndef AMD_H #define AMD_H +#include "SuiteSparse_config.h" + /* make it easy for C++ programs to include AMD */ #ifdef __cplusplus extern "C" { #endif -#include "SuiteSparse_config.h" - int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED, * AMD_INVALID, or AMD_OUT_OF_MEMORY */ ( @@ -313,6 +313,14 @@ void amd_l_control (double Control [ ]) ; void amd_info (double Info [ ]) ; void amd_l_info (double Info [ ]) ; +// amd_version: return AMD version. The version array is returned with +// version [0..2] = {AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION} +void amd_version (int version [3]) ; + +#ifdef __cplusplus +} +#endif + #define AMD_CONTROL 5 /* size of Control array */ #define AMD_INFO 20 /* size of Info array */ @@ -379,11 +387,13 @@ void amd_l_info (double Info [ ]) ; #define AMD_SUB_VERSION @AMD_VERSION_MINOR@ #define AMD_SUBSUB_VERSION @AMD_VERSION_SUB@ -#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION) +#define AMD_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define AMD_VERSION AMD_VERSION_CODE(@AMD_VERSION_MAJOR@,@AMD_VERSION_MINOR@) -#ifdef __cplusplus -} +#define AMD__VERSION SUITESPARSE__VERCODE(@AMD_VERSION_MAJOR@,@AMD_VERSION_MINOR@,@AMD_VERSION_SUB@) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,5,0)) +#error "AMD @AMD_VERSION_MAJOR@.@AMD_VERSION_MINOR@.@AMD_VERSION_SUB@ requires SuiteSparse_config 7.5.0 or later" #endif #endif diff --git a/ThirdParty/SuiteSparse/AMD/Doc/AMD_UserGuide.tex b/ThirdParty/SuiteSparse/AMD/Doc/AMD_UserGuide.tex index 2e5e1edef3..794a29cde7 100644 --- a/ThirdParty/SuiteSparse/AMD/Doc/AMD_UserGuide.tex +++ b/ThirdParty/SuiteSparse/AMD/Doc/AMD_UserGuide.tex @@ -46,7 +46,7 @@ \end{abstract} %------------------------------------------------------------------------------ -AMD Copyright\copyright 1996-2022 by Timothy A. +AMD Copyright\copyright 1996-2023 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. AMD is available under alternate licences; contact T. Davis for details. @@ -202,8 +202,8 @@ \section{Using AMD in a C program} \label{Cversion} %------------------------------------------------------------------------------ -The C-callable AMD library consists of seven user-callable routines and one -include file. There are two versions of each of the routines, with +The C-callable AMD library consists of eight user-callable routines and one +include file. There are two versions of seven of the routines, with \verb'int32_t' and \verb'int64_t' integers. The routines with prefix {\tt amd\_l\_} use \verb'int64_t' integer arguments; the others use @@ -303,6 +303,8 @@ \section{Using AMD in a C program} but it destroys the matrix on output. Additional workspace must be passed. Refer to the source file {\tt AMD/Source/amd\_2.c} for a description. +\item \verb'amd_version': returns the AMD version. + \end{itemize} The nonzero pattern of the matrix $\m{A}$ is represented in compressed column @@ -480,6 +482,16 @@ \section{Synopsis of C-callable routines} \end{verbatim} } +The \verb'amd_version' function uses plain \verb'int': + +{\footnotesize +\begin{verbatim} +#include "amd.h" +int version [3] ; +amd_version (version) ; +\end{verbatim} +} + %------------------------------------------------------------------------------ \section{Using AMD in a Fortran program} %------------------------------------------------------------------------------ diff --git a/ThirdParty/SuiteSparse/AMD/Doc/ChangeLog b/ThirdParty/SuiteSparse/AMD/Doc/ChangeLog index 97dbc0d871..3828f5ab22 100644 --- a/ThirdParty/SuiteSparse/AMD/Doc/ChangeLog +++ b/ThirdParty/SuiteSparse/AMD/Doc/ChangeLog @@ -1,3 +1,25 @@ +Jan 10, 2024: version 3.3.1 + + * minor updates to build system + +Dec 30, 2023: version 3.3.0 + + * major change to build system: by Markus Mützel + * revised test for integer overflow: for CHOLMOD 5.1.0 tests + * amd_version: added to return version of AMD + +Sept 18, 2023: version 3.2.1 + + * cmake update: add "None" build type, from Antonio Rojas, for Arch Linux + +Sept 8, 2023: version 3.2.0 + + * cmake updates: SuiteSparse:: namespace by Markus Muetzel + +June 16, 2023: version 3.0.4 + + * cmake build system updates: update by Markus Muetzel + Jan 17, 2023: version 3.0.3 * NFORTRAN: option added to disable Fortran entirely diff --git a/ThirdParty/SuiteSparse/AMD/Doc/amd_version.tex b/ThirdParty/SuiteSparse/AMD/Doc/amd_version.tex index e24c8cda6a..31528c9f32 100644 --- a/ThirdParty/SuiteSparse/AMD/Doc/amd_version.tex +++ b/ThirdParty/SuiteSparse/AMD/Doc/amd_version.tex @@ -1,2 +1,2 @@ % version of SuiteSparse/AMD -\date{VERSION 3.0.3, Jan 17, 2023} +\date{VERSION 3.3.1, Jan 10, 2024} diff --git a/ThirdParty/SuiteSparse/AMD/Include/amd.h b/ThirdParty/SuiteSparse/AMD/Include/amd.h index 94aa96f113..188ee5a67f 100644 --- a/ThirdParty/SuiteSparse/AMD/Include/amd.h +++ b/ThirdParty/SuiteSparse/AMD/Include/amd.h @@ -2,7 +2,7 @@ // AMD/Include/amd.h: approximate minimum degree ordering //------------------------------------------------------------------------------ -// AMD, Copyright (c) 1996-2022, Timothy A. Davis, Patrick R. Amestoy, and +// AMD, Copyright (c) 1996-2024, Timothy A. Davis, Patrick R. Amestoy, and // Iain S. Duff. All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause @@ -35,13 +35,13 @@ #ifndef AMD_H #define AMD_H +#include "SuiteSparse_config.h" + /* make it easy for C++ programs to include AMD */ #ifdef __cplusplus extern "C" { #endif -#include "SuiteSparse_config.h" - int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED, * AMD_INVALID, or AMD_OUT_OF_MEMORY */ ( @@ -313,6 +313,14 @@ void amd_l_control (double Control [ ]) ; void amd_info (double Info [ ]) ; void amd_l_info (double Info [ ]) ; +// amd_version: return AMD version. The version array is returned with +// version [0..2] = {AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION} +void amd_version (int version [3]) ; + +#ifdef __cplusplus +} +#endif + #define AMD_CONTROL 5 /* size of Control array */ #define AMD_INFO 20 /* size of Info array */ @@ -374,16 +382,18 @@ void amd_l_info (double Info [ ]) ; * Versions 1.1 and earlier of AMD do not include a #define'd version number. */ -#define AMD_DATE "Jan 17, 2023" +#define AMD_DATE "Jan 10, 2024" #define AMD_MAIN_VERSION 3 -#define AMD_SUB_VERSION 0 -#define AMD_SUBSUB_VERSION 3 +#define AMD_SUB_VERSION 3 +#define AMD_SUBSUB_VERSION 1 -#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION) +#define AMD_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define AMD_VERSION AMD_VERSION_CODE(3,3) -#ifdef __cplusplus -} +#define AMD__VERSION SUITESPARSE__VERCODE(3,3,1) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,5,0)) +#error "AMD 3.3.1 requires SuiteSparse_config 7.5.0 or later" #endif #endif diff --git a/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h b/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h index 85d43930b6..b5649cbc94 100644 --- a/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h +++ b/ThirdParty/SuiteSparse/AMD/Include/amd_internal.h @@ -2,7 +2,7 @@ // AMD/Include/amd_internal.h: internal definitions for AMD //------------------------------------------------------------------------------ -// AMD, Copyright (c) 1996-2022, Timothy A. Davis, Patrick R. Amestoy, and +// AMD, Copyright (c) 1996-2023, Timothy A. Davis, Patrick R. Amestoy, and // Iain S. Duff. All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause @@ -37,12 +37,9 @@ #define NDEBUG #endif -/* - To enable debugging, uncomment the following line: -#undef NDEBUG -*/ +// To enable debugging, uncomment the following line: +// #undef NDEBUG -#define SUITESPARSE_LIBRARY #include "amd.h" /* ------------------------------------------------------------------------- */ diff --git a/ThirdParty/SuiteSparse/AMD/Makefile b/ThirdParty/SuiteSparse/AMD/Makefile index ad08cc1d1a..15da7ceab0 100644 --- a/ThirdParty/SuiteSparse/AMD/Makefile +++ b/ThirdParty/SuiteSparse/AMD/Makefile @@ -36,36 +36,36 @@ default: library # default is to install only in /usr/local library: - ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . --config Release -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=1 .. && cmake --build . --config Release -j${JOBS} ) # install only in /usr/local (default) global: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=0 .. && cmake --build . --config Release -j${JOBS} ) debug: - ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . --config Debug -j${JOBS} ) all: library demos: library - ( cd build && cmake $(CMAKE_OPTIONS) -DDEMO=1 .. && cmake --build . -j${JOBS} ) - ./build/amd_demo > build/amd_demo.out - - diff --strip-trailing-cr Demo/amd_demo.out build/amd_demo.out - ./build/amd_l_demo > build/amd_l_demo.out - - diff --strip-trailing-cr Demo/amd_l_demo.out build/amd_l_demo.out - ./build/amd_demo2 > build/amd_demo2.out - - diff --strip-trailing-cr Demo/amd_demo2.out build/amd_demo2.out - ./build/amd_simple > build/amd_simple.out - - diff --strip-trailing-cr Demo/amd_simple.out build/amd_simple.out + ( cd build && cmake $(CMAKE_OPTIONS) -DSUITESPARSE_DEMOS=1 .. && cmake --build . --config Release -j${JOBS} ) + ./build/amd_demo > build/amd_demo.out && ( command -v d2u && d2u ./build/amd_demo.out || true ) + - diff Demo/amd_demo.out build/amd_demo.out + ./build/amd_l_demo > build/amd_l_demo.out && ( command -v d2u && d2u ./build/amd_l_demo.out || true ) + - diff Demo/amd_l_demo.out build/amd_l_demo.out + ./build/amd_demo2 > build/amd_demo2.out && ( command -v d2u && d2u ./build/amd_demo2.out || true ) + - diff Demo/amd_demo2.out build/amd_demo2.out + ./build/amd_simple > build/amd_simple.out && ( command -v d2u && d2u ./build/amd_simple.out || true ) + - diff Demo/amd_simple.out build/amd_simple.out # Fortran demos will fail if no Fortran compiler is available - - ./build/amd_f77simple > build/amd_f77simple.out - - diff --strip-trailing-cr Demo/amd_f77simple.out build/amd_f77simple.out - - ./build/amd_f77demo > build/amd_f77demo.out - - diff --strip-trailing-cr Demo/amd_f77demo.out build/amd_f77demo.out + - ./build/amd_f77simple > build/amd_f77simple.out && ( command -v d2u && d2u ./build/amd_f77simple.out || true ) + - diff Demo/amd_f77simple.out build/amd_f77simple.out + - ./build/amd_f77demo > build/amd_f77demo.out && ( command -v d2u && d2u ./build/amd_f77demo.out || true ) + - diff Demo/amd_f77demo.out build/amd_f77demo.out # just compile after running cmake; do not run cmake again remake: diff --git a/ThirdParty/SuiteSparse/AMD/Source/amd_order.c b/ThirdParty/SuiteSparse/AMD/Source/amd_order.c index 1dcc15a009..9df32164e0 100644 --- a/ThirdParty/SuiteSparse/AMD/Source/amd_order.c +++ b/ThirdParty/SuiteSparse/AMD/Source/amd_order.c @@ -71,9 +71,9 @@ int AMD_order return (AMD_INVALID) ; } - /* check if n or nz will cause size_t overflow */ - if (((size_t) n) >= SIZE_T_MAX / sizeof (Int) - || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int)) + /* check if n or nz will cause integer overflow */ + if (((size_t) n) >= Int_MAX / sizeof (Int) + || ((size_t) nz) >= Int_MAX / sizeof (Int)) { if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; /* problem too large */ @@ -89,8 +89,9 @@ int AMD_order } /* allocate two size-n integer workspaces */ - Len = SuiteSparse_malloc (n, sizeof (Int)) ; - Pinv = SuiteSparse_malloc (n, sizeof (Int)) ; + size_t nn = (size_t) n ; + Len = SuiteSparse_malloc (nn, sizeof (Int)) ; + Pinv = SuiteSparse_malloc (nn, sizeof (Int)) ; mem += n ; mem += n ; if (!Len || !Pinv) @@ -106,7 +107,7 @@ int AMD_order { /* sort the input matrix and remove duplicate entries */ AMD_DEBUG1 (("Matrix is jumbled\n")) ; - Rp = SuiteSparse_malloc (n+1, sizeof (Int)) ; + Rp = SuiteSparse_malloc (nn+1, sizeof (Int)) ; Ri = SuiteSparse_malloc (nz, sizeof (Int)) ; mem += (n+1) ; mem += MAX (nz,1) ; @@ -152,8 +153,8 @@ int AMD_order slen += nzaat/5 ; /* add elbow room */ for (i = 0 ; ok && i < 7 ; i++) { - ok = ((slen + n) > slen) ; /* check for size_t overflow */ - slen += n ; /* size-n elbow room, 6 size-n work */ + ok = ((slen + nn) > slen) ; /* check for size_t overflow */ + slen += nn ; /* size-n elbow room, 6 size-n work */ } mem += slen ; ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */ diff --git a/ThirdParty/SuiteSparse/AMD/Source/amd_version.c b/ThirdParty/SuiteSparse/AMD/Source/amd_version.c new file mode 100644 index 0000000000..7d045f3516 --- /dev/null +++ b/ThirdParty/SuiteSparse/AMD/Source/amd_version.c @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// AMD/Source/amd_version: return AMD version +//------------------------------------------------------------------------------ + +// AMD, Copyright (c) 1996-2023, Timothy A. Davis, Patrick R. Amestoy, and +// Iain S. Duff. All Rights Reserved. +// SPDX-License-Identifier: BSD-3-clause + +//------------------------------------------------------------------------------ + +#include "amd_internal.h" + +void amd_version (int version [3]) +{ + version [0] = AMD_MAIN_VERSION ; + version [1] = AMD_SUB_VERSION ; + version [2] = AMD_SUBSUB_VERSION ; +} + diff --git a/ThirdParty/SuiteSparse/AMD/cmake_modules/FindAMD.cmake b/ThirdParty/SuiteSparse/AMD/cmake_modules/FindAMD.cmake deleted file mode 100644 index 1b135e05a7..0000000000 --- a/ThirdParty/SuiteSparse/AMD/cmake_modules/FindAMD.cmake +++ /dev/null @@ -1,129 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/AMD/cmake_modules/FindAMD.cmake -#------------------------------------------------------------------------------- - -# The following copyright and license applies to just this file only, not to -# the library itself: -# FindAMD.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# Finds the AMD include file and compiled library and sets: - -# AMD_INCLUDE_DIR - where to find amd.h -# AMD_LIBRARY - dynamic AMD library -# AMD_STATIC - static AMD library -# AMD_LIBRARIES - libraries when using AMD -# AMD_FOUND - true if AMD found - -# set ``AMD_ROOT`` to an AMD installation root to -# tell this module where to look. - -# All the Find*.cmake files in SuiteSparse are installed by 'make install' into -# /usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the -# ${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands -# in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: -# -# set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} -# ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) - -#------------------------------------------------------------------------------- - -# include files for AMD -find_path ( AMD_INCLUDE_DIR - NAMES amd.h - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/AMD - HINTS ${CMAKE_SOURCE_DIR}/../AMD - PATH_SUFFIXES include Include -) - -# dynamic AMD library (or static if no dynamic library was built) -find_library ( AMD_LIBRARY - NAMES amd amd_static - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/AMD - HINTS ${CMAKE_SOURCE_DIR}/../AMD - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( MSVC ) - set ( STATIC_NAME amd_static ) -else ( ) - set ( STATIC_NAME amd ) - set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) -endif ( ) - -# static AMD library -find_library ( AMD_STATIC - NAMES ${STATIC_NAME} - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/AMD - HINTS ${CMAKE_SOURCE_DIR}/../AMD - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) -endif ( ) - -# get version of the library from the dynamic library name -get_filename_component ( AMD_LIBRARY ${AMD_LIBRARY} REALPATH ) -get_filename_component ( AMD_FILENAME ${AMD_LIBRARY} NAME ) -string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - AMD_VERSION - ${AMD_FILENAME} -) - -# set ( AMD_VERSION "" ) -if ( EXISTS "${AMD_INCLUDE_DIR}" AND NOT AMD_VERSION ) - # if the version does not appear in the filename, read the include file - file ( STRINGS ${AMD_INCLUDE_DIR}/amd.h AMD_MAJOR_STR - REGEX "define AMD_MAIN_VERSION" ) - file ( STRINGS ${AMD_INCLUDE_DIR}/amd.h AMD_MINOR_STR - REGEX "define AMD_SUB_VERSION" ) - file ( STRINGS ${AMD_INCLUDE_DIR}/amd.h AMD_PATCH_STR - REGEX "define AMD_SUBSUB_VERSION" ) - message ( STATUS "major: ${AMD_MAJOR_STR}" ) - message ( STATUS "minor: ${AMD_MINOR_STR}" ) - message ( STATUS "patch: ${AMD_PATCH_STR}" ) - string ( REGEX MATCH "[0-9]+" AMD_MAJOR ${AMD_MAJOR_STR} ) - string ( REGEX MATCH "[0-9]+" AMD_MINOR ${AMD_MINOR_STR} ) - string ( REGEX MATCH "[0-9]+" AMD_PATCH ${AMD_PATCH_STR} ) - set (AMD_VERSION "${AMD_MAJOR}.${AMD_MINOR}.${AMD_PATCH}") -endif ( ) - -set ( AMD_LIBRARIES ${AMD_LIBRARY} ) - -include (FindPackageHandleStandardArgs) - -find_package_handle_standard_args ( AMD - REQUIRED_VARS AMD_LIBRARY AMD_INCLUDE_DIR - VERSION_VAR AMD_VERSION -) - -mark_as_advanced ( - AMD_INCLUDE_DIR - AMD_LIBRARY - AMD_STATIC - AMD_LIBRARIES -) - -if ( AMD_FOUND ) - message ( STATUS "AMD version: ${AMD_VERSION}" ) - message ( STATUS "AMD include: ${AMD_INCLUDE_DIR}") - message ( STATUS "AMD library: ${AMD_LIBRARY}") - message ( STATUS "AMD static: ${AMD_STATIC}") -else ( ) - message ( STATUS "AMD not found" ) - set ( AMD_INCLUDE_DIR "" ) - set ( AMD_LIBRARIES "" ) - set ( AMD_LIBRARY "" ) - set ( AMD_STATIC "" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/BTF/CMakeLists.txt b/ThirdParty/SuiteSparse/BTF/CMakeLists.txt index ce4ecf45a9..059bb80c25 100644 --- a/ThirdParty/SuiteSparse/BTF/CMakeLists.txt +++ b/ThirdParty/SuiteSparse/BTF/CMakeLists.txt @@ -2,7 +2,7 @@ # SuiteSparse/BTF/CMakeLists.txt: cmake for BTF #------------------------------------------------------------------------------- -# BTF, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +# BTF, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. # Author: Timothy A. Davis. # SPDX-License-Identifier: LGPL-2.1+ @@ -10,12 +10,12 @@ # get the version #------------------------------------------------------------------------------- -cmake_minimum_required ( VERSION 3.19 ) +cmake_minimum_required ( VERSION 3.22 ) -set ( BTF_DATE "Jan 17, 2023" ) -set ( BTF_VERSION_MAJOR 2 ) -set ( BTF_VERSION_MINOR 0 ) -set ( BTF_VERSION_SUB 3 ) +set ( BTF_DATE "Jan 10, 2024" ) +set ( BTF_VERSION_MAJOR 2 CACHE STRING "" FORCE ) +set ( BTF_VERSION_MINOR 3 CACHE STRING "" FORCE ) +set ( BTF_VERSION_SUB 1 CACHE STRING "" FORCE ) message ( STATUS "Building BTF version: v" ${BTF_VERSION_MAJOR}. @@ -23,28 +23,33 @@ message ( STATUS "Building BTF version: v" ${BTF_VERSION_SUB} " (" ${BTF_DATE} ")" ) #------------------------------------------------------------------------------- -# SuiteSparse policies +# define the project #------------------------------------------------------------------------------- -set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules - ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) - -include ( SuiteSparsePolicy ) +project ( BTF + VERSION "${BTF_VERSION_MAJOR}.${BTF_VERSION_MINOR}.${BTF_VERSION_SUB}" + LANGUAGES C ) #------------------------------------------------------------------------------- -# define the project +# SuiteSparse policies #------------------------------------------------------------------------------- -project ( btf - VERSION "${BTF_VERSION_MAJOR}.${BTF_VERSION_MINOR}.${BTF_VERSION_SUB}" - LANGUAGES C ) +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${PROJECT_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) + +include ( SuiteSparsePolicy ) #------------------------------------------------------------------------------- # find library dependencies #------------------------------------------------------------------------------- -find_package ( SuiteSparse_config 7.0.0 REQUIRED ) +if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) + find_package ( SuiteSparse_config 7.5.0 + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_package ( SuiteSparse_config 7.5.0 REQUIRED ) + endif ( ) +endif ( ) #------------------------------------------------------------------------------- # configure files @@ -57,7 +62,7 @@ configure_file ( "Config/btf.h.in" "${PROJECT_SOURCE_DIR}/Include/btf.h" # include directories #------------------------------------------------------------------------------- -include_directories ( Source Include ${SUITESPARSE_CONFIG_INCLUDE_DIR} ) +include_directories ( Source Include ) #------------------------------------------------------------------------------- # dynamic btf library properties @@ -65,49 +70,76 @@ include_directories ( Source Include ${SUITESPARSE_CONFIG_INCLUDE_DIR} ) file ( GLOB BTF_SOURCES "Source/*.c" ) -add_library ( btf SHARED ${BTF_SOURCES} ) +if ( BUILD_SHARED_LIBS ) + add_library ( BTF SHARED ${BTF_SOURCES} ) + + set_target_properties ( BTF PROPERTIES + VERSION ${BTF_VERSION_MAJOR}.${BTF_VERSION_MINOR}.${BTF_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + OUTPUT_NAME btf + SOVERSION ${BTF_VERSION_MAJOR} + PUBLIC_HEADER "Include/btf.h" + WINDOWS_EXPORT_ALL_SYMBOLS ON) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( BTF PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) -set_target_properties ( btf PROPERTIES - VERSION ${BTF_VERSION_MAJOR}.${BTF_VERSION_MINOR}.${BTF_VERSION_SUB} - C_STANDARD_REQUIRED 11 - SOVERSION ${BTF_VERSION_MAJOR} - PUBLIC_HEADER "Include/btf.h" - WINDOWS_EXPORT_ALL_SYMBOLS ON) + target_include_directories ( BTF + INTERFACE $ + $ ) +endif ( ) #------------------------------------------------------------------------------- # static btf library properties #------------------------------------------------------------------------------- -if ( NOT NSTATIC ) - add_library ( btf_static STATIC ${BTF_SOURCES} ) +if ( BUILD_STATIC_LIBS ) + add_library ( BTF_static STATIC ${BTF_SOURCES} ) - set_target_properties ( btf_static PROPERTIES - VERSION ${BTF_VERSION_MAJOR}.${BTF_VERSION_MINOR}.${BTF_VERSION_SUB} - C_STANDARD_REQUIRED 11 + set_target_properties ( BTF_static PROPERTIES + C_STANDARD 11 + C_STANDARD_REQUIRED ON OUTPUT_NAME btf - SOVERSION ${BTF_VERSION_MAJOR} ) + PUBLIC_HEADER "Include/btf.h" ) if ( MSVC ) - set_target_properties ( btf_static PROPERTIES + set_target_properties ( BTF_static PROPERTIES OUTPUT_NAME btf_static ) endif ( ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( BTF_static PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( BTF_static + INTERFACE $ + $ ) endif ( ) #------------------------------------------------------------------------------- # add the library dependencies #------------------------------------------------------------------------------- -# suitesparseconfig: -target_link_libraries ( btf PUBLIC ${SUITESPARSE_CONFIG_LIBRARIES} ) -if ( NOT NSTATIC ) - target_link_libraries ( btf_static PUBLIC ${SUITESPARSE_CONFIG_STATIC} ) +# SuiteSparseConfig: +if ( BUILD_SHARED_LIBS ) + target_include_directories ( BTF PUBLIC + "$" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + target_include_directories ( BTF_static PUBLIC + "$" ) endif ( ) # libm: if ( NOT WIN32 ) - target_link_libraries ( btf PUBLIC m ) - if ( NOT NSTATIC ) - target_link_libraries ( btf_static PUBLIC m ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( BTF PRIVATE m ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + set ( BTF_STATIC_LIBS "${BTF_STATIC_LIBS} -lm" ) + target_link_libraries ( BTF_static PUBLIC m ) endif ( ) endif ( ) @@ -115,17 +147,92 @@ endif ( ) # BTF installation location #------------------------------------------------------------------------------- -install ( TARGETS btf - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} - RUNTIME DESTINATION ${SUITESPARSE_BINDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) -install ( FILES ${CMAKE_SOURCE_DIR}/cmake_modules/FindBTF.cmake - DESTINATION ${SUITESPARSE_LIBDIR}/cmake/SuiteSparse - COMPONENT Development ) -if ( NOT NSTATIC ) - install ( TARGETS btf_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) +include ( CMakePackageConfigHelpers ) + +if ( BUILD_SHARED_LIBS ) + install ( TARGETS BTF + EXPORT BTFTargets + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + install ( TARGETS BTF_static + EXPORT BTFTargets + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) + +# create (temporary) export target file during build +export ( EXPORT BTFTargets + NAMESPACE SuiteSparse:: + FILE ${CMAKE_CURRENT_BINARY_DIR}/BTFTargets.cmake ) + +# install export target, config and version files for find_package +install ( EXPORT BTFTargets + NAMESPACE SuiteSparse:: + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/BTF ) + +# generate config file to be used in common build tree +set ( SUITESPARSE_IN_BUILD_TREE ON ) +configure_package_config_file ( + Config/BTFConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/BTFConfig.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/BTFConfig.cmake ) + +# generate config file to be installed +set ( SUITESPARSE_IN_BUILD_TREE OFF ) +configure_package_config_file ( + Config/BTFConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/target/BTFConfig.cmake + INSTALL_DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/BTF ) + +write_basic_package_version_file ( + ${CMAKE_CURRENT_BINARY_DIR}/BTFConfigVersion.cmake + COMPATIBILITY SameMajorVersion ) + +install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/target/BTFConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/BTFConfigVersion.cmake + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/BTF ) + +#------------------------------------------------------------------------------- +# create pkg-config file +#------------------------------------------------------------------------------- + +if ( NOT MSVC ) + set ( prefix "${CMAKE_INSTALL_PREFIX}" ) + set ( exec_prefix "\${prefix}" ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_LIBDIR SUITESPARSE_LIBDIR_IS_ABSOLUTE ) + if (SUITESPARSE_LIBDIR_IS_ABSOLUTE) + set ( libdir "${SUITESPARSE_LIBDIR}") + else ( ) + set ( libdir "\${exec_prefix}/${SUITESPARSE_LIBDIR}") + endif ( ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_INCLUDEDIR SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE ) + if (SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE) + set ( includedir "${SUITESPARSE_INCLUDEDIR}") + else ( ) + set ( includedir "\${prefix}/${SUITESPARSE_INCLUDEDIR}") + endif ( ) + if ( BUILD_SHARED_LIBS ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + endif ( ) + configure_file ( + Config/BTF.pc.in + BTF.pc.out + @ONLY + NEWLINE_STYLE LF ) + file ( GENERATE + OUTPUT BTF.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/BTF.pc.out + NEWLINE_STYLE LF ) + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/BTF.pc + DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) endif ( ) #------------------------------------------------------------------------------- @@ -133,4 +240,3 @@ endif ( ) #------------------------------------------------------------------------------- include ( SuiteSparseReport ) - diff --git a/ThirdParty/SuiteSparse/BTF/Config/BTF.pc.in b/ThirdParty/SuiteSparse/BTF/Config/BTF.pc.in new file mode 100644 index 0000000000..13de408ff6 --- /dev/null +++ b/ThirdParty/SuiteSparse/BTF/Config/BTF.pc.in @@ -0,0 +1,16 @@ +# BTF, Copyright (c) 2004-2023, Timothy A. Davis. +# All Rights Reserved. +# SPDX-License-Identifier: LGPL-2.1-or-later + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: BTF +URL: https://github.com/DrTimothyAldenDavis/SuiteSparse +Description: Software package for permuting a matrix into block upper triangular form in SuiteSparse +Version: @BTF_VERSION_MAJOR@.@BTF_VERSION_MINOR@.@BTF_VERSION_SUB@ +Libs: -L${libdir} -l@SUITESPARSE_LIB_BASE_NAME@ +Libs.private: @BTF_STATIC_LIBS@ +Cflags: -I${includedir} diff --git a/ThirdParty/SuiteSparse/BTF/Config/BTFConfig.cmake.in b/ThirdParty/SuiteSparse/BTF/Config/BTFConfig.cmake.in new file mode 100644 index 0000000000..4fdca7a1ec --- /dev/null +++ b/ThirdParty/SuiteSparse/BTF/Config/BTFConfig.cmake.in @@ -0,0 +1,152 @@ +#------------------------------------------------------------------------------- +# SuiteSparse/BTF/cmake_modules/BTFConfig.cmake +#------------------------------------------------------------------------------- + +# The following copyright and license applies to just this file only, not to +# the library itself: +# BTFConfig.cmake, Copyright (c) 2023, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: BSD-3-clause + +#------------------------------------------------------------------------------- + +# Finds the BTF include file and compiled library. +# The following targets are defined: +# SuiteSparse::BTF - for the shared library (if available) +# SuiteSparse::BTF_static - for the static library (if available) + +# For backward compatibility the following variables are set: + +# BTF_INCLUDE_DIR - where to find btf.h +# BTF_LIBRARY - dynamic BTF library +# BTF_STATIC - static BTF library +# BTF_LIBRARIES - libraries when using BTF +# BTF_FOUND - true if BTF found + +# Set ``CMAKE_MODULE_PATH`` to the parent folder where this module file is +# installed. + +#------------------------------------------------------------------------------- + +@PACKAGE_INIT@ + +set ( BTF_DATE "@BTF_DATE@" ) +set ( BTF_VERSION_MAJOR @BTF_VERSION_MAJOR@ ) +set ( BTF_VERSION_MINOR @BTF_VERSION_MINOR@ ) +set ( BTF_VERSION_SUB @BTF_VERSION_SUB@ ) +set ( BTF_VERSION "@BTF_VERSION_MAJOR@.@BTF_VERSION_MINOR@.@BTF_VERSION_SUB@" ) + +# Check for dependent targets +include ( CMakeFindDependencyMacro ) + +# Look for SuiteSparse_config target +if ( @SUITESPARSE_IN_BUILD_TREE@ ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + # First check in a common build tree + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT SuiteSparse_config_FOUND ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) + endif ( ) +else ( ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) +endif ( ) +if ( NOT SuiteSparse_config_FOUND ) + set ( BTF_FOUND OFF ) + return ( ) +endif ( ) + + +# Import target +include ( ${CMAKE_CURRENT_LIST_DIR}/BTFTargets.cmake ) + +# The following is only for backward compatibility with FindBTF. + +set ( _target_shared SuiteSparse::BTF ) +set ( _target_static SuiteSparse::BTF_static ) +set ( _var_prefix "BTF" ) + +if ( NOT @BUILD_SHARED_LIBS@ AND NOT TARGET ${_target_shared} ) + # make sure there is always an import target without suffix ) + add_library ( ${_target_shared} ALIAS ${_target_static} ) +endif ( ) + +get_target_property ( ${_var_prefix}_INCLUDE_DIR ${_target_shared} INTERFACE_INCLUDE_DIRECTORIES ) +if ( ${_var_prefix}_INCLUDE_DIR ) + # First item in SuiteSparse targets contains the "main" header directory. + list ( GET ${_var_prefix}_INCLUDE_DIR 0 ${_var_prefix}_INCLUDE_DIR ) +endif ( ) +get_target_property ( ${_var_prefix}_LIBRARY ${_target_shared} IMPORTED_IMPLIB ) +if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} IMPORTED_LOCATION ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) +endif ( ) +if ( TARGET ${_target_static} ) + get_target_property ( ${_var_prefix}_STATIC ${_target_static} IMPORTED_LOCATION ) +endif ( ) + +# Check for most common build types +set ( _config_types "Debug" "Release" "RelWithDebInfo" "MinSizeRel" "None" ) + +get_property ( _isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) +if ( _isMultiConfig ) + # For multi-configuration generators (e.g., Visual Studio), prefer those + # configurations. + list ( PREPEND _config_types ${CMAKE_CONFIGURATION_TYPES} ) +else ( ) + # For single-configuration generators, prefer the current configuration. + list ( PREPEND _config_types ${CMAKE_BUILD_TYPE} ) +endif ( ) + +list ( REMOVE_DUPLICATES _config_types ) + +foreach ( _config ${_config_types} ) + string ( TOUPPER ${_config} _uc_config ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_IMPLIB_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( TARGET ${_target_static} AND NOT ${_var_prefix}_STATIC ) + get_target_property ( _library_chk ${_target_static} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_STATIC ${_library_chk} ) + endif ( ) + endif ( ) +endforeach ( ) + +set ( BTF_LIBRARIES ${BTF_LIBRARY} ) + +macro ( suitesparse_check_exist _var _files ) + # ignore generator expressions + string ( GENEX_STRIP "${_files}" _files2 ) + + foreach ( _file ${_files2} ) + if ( NOT EXISTS "${_file}" ) + message ( FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist!" ) + endif ( ) + endforeach () +endmacro ( ) + +suitesparse_check_exist ( BTF_INCLUDE_DIR ${BTF_INCLUDE_DIR} ) +suitesparse_check_exist ( BTF_LIBRARY ${BTF_LIBRARY} ) + +message ( STATUS "BTF version: ${BTF_VERSION}" ) +message ( STATUS "BTF include: ${BTF_INCLUDE_DIR}" ) +message ( STATUS "BTF library: ${BTF_LIBRARY}" ) +message ( STATUS "BTF static: ${BTF_STATIC}" ) diff --git a/ThirdParty/SuiteSparse/BTF/Config/btf.h.in b/ThirdParty/SuiteSparse/BTF/Config/btf.h.in index 01fda8fd8d..a5985db8af 100644 --- a/ThirdParty/SuiteSparse/BTF/Config/btf.h.in +++ b/ThirdParty/SuiteSparse/BTF/Config/btf.h.in @@ -2,7 +2,7 @@ // BTF/Include/btf.h: include file for BTF //------------------------------------------------------------------------------ -// BTF, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// BTF, Copyright (c) 2004-2024, University of Florida. All Rights Reserved. // Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ @@ -90,13 +90,13 @@ #ifndef _BTF_H #define _BTF_H +#include "SuiteSparse_config.h" + /* make it easy for C++ programs to include BTF */ #ifdef __cplusplus extern "C" { #endif -#include "SuiteSparse_config.h" - int32_t btf_maxtrans /* returns # of columns matched */ ( /* --- input, not modified: --- */ @@ -218,6 +218,16 @@ int32_t btf_order /* returns number of blocks found */ int64_t btf_l_order (int64_t, int64_t *, int64_t *, double , double *, int64_t *, int64_t *, int64_t *, int64_t *, int64_t *) ; +//------------------------------------------------------------------------------ +// btf_version: return BTF version +//------------------------------------------------------------------------------ + +void btf_version (int version [3]) ; + +#ifdef __cplusplus +} +#endif + /* ========================================================================== */ /* === BTF marking of singular columns ====================================== */ @@ -247,7 +257,7 @@ int64_t btf_l_order (int64_t, int64_t *, int64_t *, double , double *, * * This also works during compile-time: * - * #if (BTF >= BTF_VERSION_CODE (1,2)) + * #if (BTF_VERSION >= BTF_VERSION_CODE (1,2)) * printf ("This is version 1.2 or later\n") ; * #else * printf ("This is an early version\n") ; @@ -259,10 +269,13 @@ int64_t btf_l_order (int64_t, int64_t *, int64_t *, double , double *, #define BTF_SUB_VERSION @BTF_VERSION_MINOR@ #define BTF_SUBSUB_VERSION @BTF_VERSION_SUB@ -#define BTF_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define BTF_VERSION BTF_VERSION_CODE(BTF_MAIN_VERSION,BTF_SUB_VERSION) +#define BTF_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define BTF_VERSION BTF_VERSION_CODE(@BTF_VERSION_MAJOR@,@BTF_VERSION_MINOR@) -#ifdef __cplusplus -} +#define BTF__VERSION SUITESPARSE__VERCODE(@BTF_VERSION_MAJOR@,@BTF_VERSION_MINOR@,@BTF_VERSION_SUB@) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,5,0)) +#error "BTF @BTF_VERSION_MAJOR@.@BTF_VERSION_MINOR@.@BTF_VERSION_SUB@ requires SuiteSparse_config 7.5.0 or later" #endif + #endif diff --git a/ThirdParty/SuiteSparse/BTF/Doc/ChangeLog b/ThirdParty/SuiteSparse/BTF/Doc/ChangeLog index d984d8a694..d857cbc6ed 100644 --- a/ThirdParty/SuiteSparse/BTF/Doc/ChangeLog +++ b/ThirdParty/SuiteSparse/BTF/Doc/ChangeLog @@ -1,3 +1,24 @@ +Jan 10, 2024: version 2.3.1 + + * minor updates to build system + +Dec 30, 2023: version 2.3.0 + + * major change to build system: by Markus Mützel + * btf_version: added to return version of BTF + +Sept 18, 2023: version 2.2.1 + + * cmake update: add "None" build type, from Antonio Rojas, for Arch Linux + +Sept 8, 2023: version 2.2.0 + + * cmake updates: SuiteSparse:: namespace by Markus Muetzel + +June 16, 2023: version 2.0.4 + + * cmake build system updates: update by Markus Muetzel + Jan 17, 2023: version 2.0.3 * SuiteSparse_config: now v7.0.0 diff --git a/ThirdParty/SuiteSparse/BTF/Include/btf.h b/ThirdParty/SuiteSparse/BTF/Include/btf.h index 58cb94d7e3..c152e879aa 100644 --- a/ThirdParty/SuiteSparse/BTF/Include/btf.h +++ b/ThirdParty/SuiteSparse/BTF/Include/btf.h @@ -2,7 +2,7 @@ // BTF/Include/btf.h: include file for BTF //------------------------------------------------------------------------------ -// BTF, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// BTF, Copyright (c) 2004-2024, University of Florida. All Rights Reserved. // Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ @@ -90,13 +90,13 @@ #ifndef _BTF_H #define _BTF_H +#include "SuiteSparse_config.h" + /* make it easy for C++ programs to include BTF */ #ifdef __cplusplus extern "C" { #endif -#include "SuiteSparse_config.h" - int32_t btf_maxtrans /* returns # of columns matched */ ( /* --- input, not modified: --- */ @@ -218,6 +218,16 @@ int32_t btf_order /* returns number of blocks found */ int64_t btf_l_order (int64_t, int64_t *, int64_t *, double , double *, int64_t *, int64_t *, int64_t *, int64_t *, int64_t *) ; +//------------------------------------------------------------------------------ +// btf_version: return BTF version +//------------------------------------------------------------------------------ + +void btf_version (int version [3]) ; + +#ifdef __cplusplus +} +#endif + /* ========================================================================== */ /* === BTF marking of singular columns ====================================== */ @@ -247,22 +257,25 @@ int64_t btf_l_order (int64_t, int64_t *, int64_t *, double , double *, * * This also works during compile-time: * - * #if (BTF >= BTF_VERSION_CODE (1,2)) + * #if (BTF_VERSION >= BTF_VERSION_CODE (1,2)) * printf ("This is version 1.2 or later\n") ; * #else * printf ("This is an early version\n") ; * #endif */ -#define BTF_DATE "Jan 17, 2023" +#define BTF_DATE "Jan 10, 2024" #define BTF_MAIN_VERSION 2 -#define BTF_SUB_VERSION 0 -#define BTF_SUBSUB_VERSION 3 +#define BTF_SUB_VERSION 3 +#define BTF_SUBSUB_VERSION 1 -#define BTF_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define BTF_VERSION BTF_VERSION_CODE(BTF_MAIN_VERSION,BTF_SUB_VERSION) +#define BTF_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define BTF_VERSION BTF_VERSION_CODE(2,3) -#ifdef __cplusplus -} +#define BTF__VERSION SUITESPARSE__VERCODE(2,3,1) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,5,0)) +#error "BTF 2.3.1 requires SuiteSparse_config 7.5.0 or later" #endif + #endif diff --git a/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h b/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h index 15b1b04452..96acda9015 100644 --- a/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h +++ b/ThirdParty/SuiteSparse/BTF/Include/btf_internal.h @@ -2,7 +2,7 @@ // BTF/Include/btf_internsl.h: internal include file for BTF //------------------------------------------------------------------------------ -// BTF, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// BTF, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. // Author: Timothy A. Davis. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/ThirdParty/SuiteSparse/BTF/Makefile b/ThirdParty/SuiteSparse/BTF/Makefile index f86ddabfde..5e9baae9f5 100644 --- a/ThirdParty/SuiteSparse/BTF/Makefile +++ b/ThirdParty/SuiteSparse/BTF/Makefile @@ -36,18 +36,18 @@ default: library # default is to install only in /usr/local library: - ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . --config Release -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=1 .. && cmake --build . --config Release -j${JOBS} ) # install only in /usr/local (default) global: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=0 .. && cmake --build . --config Release -j${JOBS} ) debug: - ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . --config Debug -j${JOBS} ) all: library diff --git a/ThirdParty/SuiteSparse/BTF/Source/btf_version.c b/ThirdParty/SuiteSparse/BTF/Source/btf_version.c new file mode 100644 index 0000000000..151f24d79d --- /dev/null +++ b/ThirdParty/SuiteSparse/BTF/Source/btf_version.c @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// BTF/Source/btf_version: return BTF version +//------------------------------------------------------------------------------ + +// BTF, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. +// Author: Timothy A. Davis. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +#include "btf.h" + +void btf_version (int version [3]) +{ + version [0] = BTF_MAIN_VERSION ; + version [1] = BTF_SUB_VERSION ; + version [2] = BTF_SUBSUB_VERSION ; +} + diff --git a/ThirdParty/SuiteSparse/BTF/cmake_modules/FindBTF.cmake b/ThirdParty/SuiteSparse/BTF/cmake_modules/FindBTF.cmake deleted file mode 100644 index b5e6153ed4..0000000000 --- a/ThirdParty/SuiteSparse/BTF/cmake_modules/FindBTF.cmake +++ /dev/null @@ -1,129 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/BTF/cmake_modules/FindBTF.cmake -#------------------------------------------------------------------------------- - -# The following copyright and license applies to just this file only, not to -# the library itself: -# FindBTF.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# Finds the BTF include file and compiled library and sets: - -# BTF_INCLUDE_DIR - where to find btf.h -# BTF_LIBRARY - dynamic BTF library -# BTF_STATIC - static BTF library -# BTF_LIBRARIES - libraries when using BTF -# BTF_FOUND - true if BTF found - -# set ``BTF_ROOT`` to a BTF installation root to -# tell this module where to look. - -# All the Find*.cmake files in SuiteSparse are installed by 'make install' into -# /usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the -# ${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands -# in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: -# -# set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} -# ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) - -#------------------------------------------------------------------------------- - -# include files for BTF -find_path ( BTF_INCLUDE_DIR - NAMES btf.h - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/BTF - HINTS ${CMAKE_SOURCE_DIR}/../BTF - PATH_SUFFIXES include Include -) - -# dynamic BTF library (or static if no dynamic library was built) -find_library ( BTF_LIBRARY - NAMES btf btf_static - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/BTF - HINTS ${CMAKE_SOURCE_DIR}/../BTF - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( MSVC ) - set ( STATIC_NAME btf_static ) -else ( ) - set ( STATIC_NAME btf ) - set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) -endif ( ) - -# static BTF library -find_library ( BTF_STATIC - NAMES ${STATIC_NAME} - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/BTF - HINTS ${CMAKE_SOURCE_DIR}/../BTF - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) -endif ( ) - -# get version of the library from the dynamic library name -get_filename_component ( BTF_LIBRARY ${BTF_LIBRARY} REALPATH ) -get_filename_component ( BTF_FILENAME ${BTF_LIBRARY} NAME ) -string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - BTF_VERSION - ${BTF_FILENAME} -) - -# set ( BTF_VERSION "" ) -if ( EXISTS "${BTF_INCLUDE_DIR}" AND NOT BTF_VERSION ) - # if the version does not appear in the filename, read the include file - file ( STRINGS ${BTF_INCLUDE_DIR}/btf.h BTF_MAJOR_STR - REGEX "define BTF_MAIN_VERSION" ) - file ( STRINGS ${BTF_INCLUDE_DIR}/btf.h BTF_MINOR_STR - REGEX "define BTF_SUB_VERSION" ) - file ( STRINGS ${BTF_INCLUDE_DIR}/btf.h BTF_PATCH_STR - REGEX "define BTF_SUBSUB_VERSION" ) - message ( STATUS "major: ${BTF_MAJOR_STR}" ) - message ( STATUS "minor: ${BTF_MINOR_STR}" ) - message ( STATUS "patch: ${BTF_PATCH_STR}" ) - string ( REGEX MATCH "[0-9]+" BTF_MAJOR ${BTF_MAJOR_STR} ) - string ( REGEX MATCH "[0-9]+" BTF_MINOR ${BTF_MINOR_STR} ) - string ( REGEX MATCH "[0-9]+" BTF_PATCH ${BTF_PATCH_STR} ) - set (BTF_VERSION "${BTF_MAJOR}.${BTF_MINOR}.${BTF_PATCH}") -endif ( ) - -set ( BTF_LIBRARIES ${BTF_LIBRARY} ) - -include (FindPackageHandleStandardArgs) - -find_package_handle_standard_args ( BTF - REQUIRED_VARS BTF_LIBRARY BTF_INCLUDE_DIR - VERSION_VAR BTF_VERSION -) - -mark_as_advanced ( - BTF_INCLUDE_DIR - BTF_LIBRARY - BTF_STATIC - BTF_LIBRARIES -) - -if ( BTF_FOUND ) - message ( STATUS "BTF version: ${BTF_VERSION}" ) - message ( STATUS "BTF include: ${BTF_INCLUDE_DIR}" ) - message ( STATUS "BTF library: ${BTF_LIBRARY}" ) - message ( STATUS "BTF static: ${BTF_STATIC}" ) -else ( ) - message ( STATUS "BTF not found" ) - set ( BTF_INCLUDE_DIR "" ) - set ( BTF_LIBRARIES "" ) - set ( BTF_LIBRARY "" ) - set ( BTF_STATIC "" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/CMakeLists.txt b/ThirdParty/SuiteSparse/CMakeLists.txt new file mode 100644 index 0000000000..0a23a5a480 --- /dev/null +++ b/ThirdParty/SuiteSparse/CMakeLists.txt @@ -0,0 +1,540 @@ +#------------------------------------------------------------------------------- +# SuiteSparse/CMakeLists.txt: root CMake build rules +#------------------------------------------------------------------------------- + +# Copyright (c) 2023-2024, Timothy A. Davis, All Rights Reserved. +# Just this particular file is under the Apache-2.0 license; each package has +# its own license. +# SPDX-License-Identifier: Apache-2.0 + +# This file and most packages in SuiteSparse require cmake 3.22 or later. Some +# packages can be built as stand-alone packages with their own CMakeLists.txt +# files, with older versions of cmake (GraphBLAS, LAGraph, and CSparse): +# +# GraphBLAS and LAGraph: 3.20 +# CSparse: 3.13 +# GraphBLAS jitifyer (for end user JIT kernels): 3.13 +# +# Other CMakeLists.txt files inside SuiteSparse are from dependent packages +# (LAGraph/deps/json_h, GraphBLAS/cpu_features, and CHOLMOD/SuiteSparse_metis +# which is a slightly revised copy of METIS 5.0.1) but none of those +# CMakeLists.txt files are used to build any package in SuiteSparse. +cmake_minimum_required ( VERSION 3.22 ) + +project ( "SuiteSparse" ) + +#------------------------------------------------------------------------------- +# SuiteSparse policies +#------------------------------------------------------------------------------- + +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${PROJECT_SOURCE_DIR}/SuiteSparse_config/cmake_modules ) + +#------------------------------------------------------------------------------- +# build options +#------------------------------------------------------------------------------- + +# lower-case list of all projects that can be built by this root CMake file +set ( SUITESPARSE_ALL_PROJECTS + "suitesparse_config;mongoose;amd;btf;camd;ccolamd;colamd;cholmod;cxsparse;ldl;klu;umfpack;paru;rbio;spqr;spex;graphblas;lagraph" ) + +# lower-case list of extra projects that can be built by this root CMake file +set ( SUITESPARSE_EXTRA_PROJECTS + "csparse" ) + +# lower-case list of known projects that can be built by this root CMake file +set ( SUITESPARSE_KNOWN_PROJECTS "${SUITESPARSE_ALL_PROJECTS};${SUITESPARSE_EXTRA_PROJECTS}" ) + +set ( SUITESPARSE_ENABLE_PROJECTS "all" CACHE STRING + "Semicolon-separated list of SuiteSparse projects to be built (${SUITESPARSE_KNOWN_PROJECTS}, or \"all\")" ) + +# expand "all" early on +if ( "all" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + set ( SUITESPARSE_ENABLE_PROJECTS "${SUITESPARSE_ENABLE_PROJECTS};${SUITESPARSE_ALL_PROJECTS}" ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "all" ) + list ( REMOVE_DUPLICATES SUITESPARSE_ENABLE_PROJECTS ) +endif ( ) + +# check for unknown projects in list +foreach ( proj ${SUITESPARSE_ENABLE_PROJECTS} ) + if ( NOT "${proj}" IN_LIST SUITESPARSE_KNOWN_PROJECTS ) + message ( FATAL_ERROR "${proj} is not a known project: ${SUITESPARSE_KNOWN_PROJECTS}." ) + endif ( ) +endforeach ( ) + +# CHOLMOD options affecting dependencies +option ( CHOLMOD_CAMD "ON (default): use CAMD/CCOLAMD. OFF: do not use CAMD/CCOLAMD" ON ) + +# KLU options affecting dependencies +option ( KLU_USE_CHOLMOD "ON (default): use CHOLMOD in KLU. OFF: do not use CHOLMOD in KLU" ON ) + +# UMFPACK options affecting dependencies +option ( UMFPACK_USE_CHOLMOD "ON (default): use CHOLMOD in UMFPACK. OFF: do not use CHOLMOD in UMFPACK" ON ) + +# overwrite BUILD_STATIC_LIBS specifically for GraphBLAS because building the +# library takes a long time +option ( GRAPHBLAS_BUILD_STATIC_LIBS "OFF (default): Do not build static libraries for GraphBLAS project. ON: Use same value of BUILD_STATIC_LIBS for GraphBLAS like in the other projects" OFF ) + +# options to build with libraries installed on the system instead of building +# dependencies automatically +option ( SUITESPARSE_USE_SYSTEM_BTF "ON: use BTF libraries installed on the build system. OFF (default): Automatically build BTF as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_CHOLMOD "ON: use CHOLMOD libraries installed on the build system. OFF (default): Automatically build CHOLMOD as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_AMD "ON: use AMD libraries installed on the build system. OFF (default): Automatically build AMD as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_COLAMD "ON: use COLAMD libraries installed on the build system. OFF (default): Automatically build COLAMD as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_CAMD "ON: use CAMD libraries installed on the build system. OFF (default): Automatically build CAMD as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_CCOLAMD "ON: use CCOLAMD libraries installed on the build system. OFF (default): Automatically build CCOLAMD as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_GRAPHBLAS "ON: use GraphBLAS libraries installed on the build system. OFF (default): Automatically build GraphBLAS as dependency if needed." OFF ) +option ( SUITESPARSE_USE_SYSTEM_SUITESPARSE_CONFIG "ON: use SuiteSparse_config libraries installed on the build system. OFF (default): Automatically build SuiteSparse_config as dependency if needed." OFF ) + +#------------------------------------------------------------------------------- +# global variables +#------------------------------------------------------------------------------- + +# Set to indicate that we are building from a root CMake file. +# That will change the directory layout and (imported) target names (namespace!) +# during the build process. +set ( SUITESPARSE_ROOT_CMAKELISTS ON ) + +#------------------------------------------------------------------------------- +# common SuiteSparse modules +#------------------------------------------------------------------------------- + +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${CMAKE_SOURCE_DIR}/SuiteSparse_config/cmake_modules ) + +include ( SuiteSparsePolicy ) + +#------------------------------------------------------------------------------- +# check/add project dependencies +#------------------------------------------------------------------------------- + +if ( SUITESPARSE_USE_SYSTEM_GRAPHBLAS ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "graphblas" ) + find_package ( GraphBLAS 9.0.1 REQUIRED ) +else ( ) + if ( "lagraph" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # LAGraph requires GraphBLAS. + if ( NOT "graphblas" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"graphblas\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "graphblas" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_BTF ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "btf" ) + find_package ( BTF 2.3.1 REQUIRED ) +else ( ) + if ( "klu" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # KLU requires BTF. + if ( NOT "btf" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"btf\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "btf" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_CHOLMOD ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "cholmod" ) + find_package ( CHOLMOD 5.2.0 REQUIRED ) +else ( ) + if ( ( KLU_USE_CHOLMOD AND "klu" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + OR ( UMFPACK_USE_CHOLMOD AND "umfpack" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + OR "spqr" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "paru" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # SPQR and ParU both require CHOLMOD. KLU and UMFPACK can optionally + # use CHOLMOD. Add CHOLMOD to the list of projects, if it has been + # requested by SPQR, ParU, KLU, or UMFPACK, if not already there. + if ( NOT "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"cholmod\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "cholmod" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_AMD ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "amd" ) + find_package ( AMD 3.3.1 REQUIRED ) +else ( ) + if ( "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "ldl" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "umfpack" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "spex" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # CHOLMOD, LDL, UMFPACK, and SPEX require AMD. + if ( NOT "amd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"amd\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "amd" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_COLAMD ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "colamd" ) + find_package ( COLAMD 3.3.2 REQUIRED ) +else ( ) + if ( "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "spex" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # CHOLMOD and SPEX require COLAMD. + if ( NOT "colamd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"colamd\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "colamd" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_CAMD ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "camd" ) + find_package ( CAMD 3.3.1 REQUIRED ) +else ( ) + if ( CHOLMOD_CAMD AND "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # CHOLMOD can optionally use CAMD. + if ( NOT SUITESPARSE_USE_SYSTEM_CAMD AND NOT "camd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"camd\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "camd" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_CCOLAMD ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "ccolamd" ) + find_package ( CCOLAMD 3.3.2 REQUIRED ) +else ( ) + if ( CHOLMOD_CAMD AND "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # CHOLMOD can optionally use CCOLAMD. + if ( NOT "ccolamd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"ccolamd\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "ccolamd" ) + endif ( ) + endif ( ) +endif ( ) + +if ( SUITESPARSE_USE_SYSTEM_SUITESPARSE_CONFIG ) + list ( REMOVE_ITEM SUITESPARSE_ENABLE_PROJECTS "suitesparse_config" ) + find_package ( SuiteSparse_config 7.6.0 REQUIRED ) +else ( ) + if ( "mongoose" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "amd" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "btf" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "camd" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "ccolamd" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "colamd" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "cxsparse" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "ldl" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "klu" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "umfpack" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "paru" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "rbio" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "spqr" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "spex" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + # All but CSparse, GraphBLAS, and LAGraph require SuiteSparse_config. + if ( NOT "suitesparse_config" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + message ( STATUS "Adding \"suitesparse_config\" to the list of built targets." ) + list ( APPEND SUITESPARSE_ENABLE_PROJECTS "suitesparse_config" ) + endif ( ) + endif ( ) +endif ( ) + + +if ( CMAKE_VERSION VERSION_LESS 3.24 ) + # work around missing GLOBAL option of find_package in older CMake versions + # If SuiteSparse is included as a sub-project in other projects, they might + # need to manually import the OpenMP targets for older CMake versions, too. + if ( "suitesparse_config" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "graphblas" IN_LIST SUITESPARSE_ENABLE_PROJECTS + OR "paru" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + find_package ( OpenMP COMPONENTS C ) + endif ( ) + if ( "paru" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + find_package ( OpenMP COMPONENTS CXX ) + endif ( ) +endif ( ) + + +#------------------------------------------------------------------------------- +# include selected projects +#------------------------------------------------------------------------------- + +if ( "suitesparse_config" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "SuiteSparse_config" ) + if ( TARGET SuiteSparseConfig ) + add_library ( SuiteSparse::SuiteSparseConfig ALIAS SuiteSparseConfig ) + else ( ) + add_library ( SuiteSparse::SuiteSparseConfig ALIAS SuiteSparseConfig_static ) + endif ( ) + if ( TARGET SuiteSparseConfig_static ) + add_library ( SuiteSparse::SuiteSparseConfig_static ALIAS SuiteSparseConfig_static ) + endif ( ) +endif ( ) + +if ( "mongoose" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "Mongoose" ) + if ( TARGET Mongoose ) + add_library ( SuiteSparse::Mongoose ALIAS Mongoose ) + else ( ) + add_library ( SuiteSparse::Mongoose ALIAS Mongoose_static ) + endif ( ) + if ( TARGET Mongoose_static ) + add_library ( SuiteSparse::Mongoose_static ALIAS Mongoose_static ) + endif ( ) +endif ( ) + +if ( "amd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "AMD" ) + if ( TARGET AMD ) + add_library ( SuiteSparse::AMD ALIAS AMD ) + else ( ) + add_library ( SuiteSparse::AMD ALIAS AMD_static ) + endif ( ) + if ( TARGET AMD_static ) + add_library ( SuiteSparse::AMD_static ALIAS AMD_static ) + endif ( ) +endif ( ) + +if ( "btf" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "BTF" ) + if ( TARGET BTF ) + add_library ( SuiteSparse::BTF ALIAS BTF ) + else ( ) + add_library ( SuiteSparse::BTF ALIAS BTF_static ) + endif ( ) + if ( TARGET BTF_static ) + add_library ( SuiteSparse::BTF_static ALIAS BTF_static ) + endif ( ) +endif ( ) + +if ( "camd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "CAMD" ) + if ( TARGET CAMD ) + add_library ( SuiteSparse::CAMD ALIAS CAMD ) + else ( ) + add_library ( SuiteSparse::CAMD ALIAS CAMD_static ) + endif ( ) + if ( TARGET CAMD_static ) + add_library ( SuiteSparse::CAMD_static ALIAS CAMD_static ) + endif ( ) +endif ( ) + +if ( "ccolamd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "CCOLAMD" ) + if ( TARGET CCOLAMD ) + add_library ( SuiteSparse::CCOLAMD ALIAS CCOLAMD ) + else ( ) + add_library ( SuiteSparse::CCOLAMD ALIAS CCOLAMD_static ) + endif ( ) + if ( TARGET CCOLAMD_static ) + add_library ( SuiteSparse::CCOLAMD_static ALIAS CCOLAMD_static ) + endif ( ) +endif ( ) + +if ( "colamd" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "COLAMD" ) + if ( TARGET COLAMD ) + add_library ( SuiteSparse::COLAMD ALIAS COLAMD ) + else ( ) + add_library ( SuiteSparse::COLAMD ALIAS COLAMD_static ) + endif ( ) + if ( TARGET COLAMD_static ) + add_library ( SuiteSparse::COLAMD_static ALIAS COLAMD_static ) + endif ( ) +endif ( ) + +if ( "cholmod" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "CHOLMOD" ) + if ( TARGET CHOLMOD ) + add_library ( SuiteSparse::CHOLMOD ALIAS CHOLMOD ) + else ( ) + add_library ( SuiteSparse::CHOLMOD ALIAS CHOLMOD_static ) + endif ( ) + if ( TARGET CHOLMOD_static ) + add_library ( SuiteSparse::CHOLMOD_static ALIAS CHOLMOD_static ) + endif ( ) + if ( TARGET CHOLMOD_CUDA ) + add_library ( SuiteSparse::CHOLMOD_CUDA ALIAS CHOLMOD_CUDA ) + elseif ( TARGET CHOLMOD_CUDA_static ) + add_library ( SuiteSparse::CHOLMOD_CUDA ALIAS CHOLMOD_CUDA_static ) + endif ( ) + if ( TARGET CHOLMOD_CUDA_static ) + add_library ( SuiteSparse::CHOLMOD_CUDA_static ALIAS CHOLMOD_CUDA_static ) + endif ( ) +endif ( ) + +if ( "cxsparse" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "CXSparse" ) + if ( TARGET CXSparse ) + add_library ( SuiteSparse::CXSparse ALIAS CXSparse ) + else ( ) + add_library ( SuiteSparse::CXSparse ALIAS CXSparse_static ) + endif ( ) + if ( TARGET CXSparse_static ) + add_library ( SuiteSparse::CXSparse_static ALIAS CXSparse_static ) + endif ( ) +endif ( ) + +if ( "ldl" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "LDL" ) + if ( TARGET LDL ) + add_library ( SuiteSparse::LDL ALIAS LDL ) + else ( ) + add_library ( SuiteSparse::LDL ALIAS LDL_static ) + endif ( ) + if ( TARGET LDL_static ) + add_library ( SuiteSparse::LDL_static ALIAS LDL_static ) + endif ( ) +endif ( ) + +if ( "klu" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "KLU" ) + if ( TARGET KLU ) + add_library ( SuiteSparse::KLU ALIAS KLU ) + else ( ) + add_library ( SuiteSparse::KLU ALIAS KLU_static ) + endif ( ) + if ( TARGET KLU_static ) + add_library ( SuiteSparse::KLU_static ALIAS KLU_static ) + endif ( ) +endif ( ) + +if ( "umfpack" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "UMFPACK" ) + if ( TARGET UMFPACK ) + add_library ( SuiteSparse::UMFPACK ALIAS UMFPACK ) + else ( ) + add_library ( SuiteSparse::UMFPACK ALIAS UMFPACK_static ) + endif ( ) + if ( TARGET UMFPACK_static ) + add_library ( SuiteSparse::UMFPACK_static ALIAS UMFPACK_static ) + endif ( ) +endif ( ) + +if ( "paru" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "ParU" ) + if ( TARGET ParU ) + add_library ( SuiteSparse::ParU ALIAS ParU ) + else ( ) + add_library ( SuiteSparse::ParU ALIAS ParU_static ) + endif ( ) + if ( TARGET ParU_static ) + add_library ( SuiteSparse::ParU_static ALIAS ParU_static ) + endif ( ) +endif ( ) + +if ( "rbio" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "RBio" ) + if ( TARGET RBio ) + add_library ( SuiteSparse::RBio ALIAS RBio ) + else ( ) + add_library ( SuiteSparse::RBio ALIAS RBio_static ) + endif ( ) + if ( TARGET RBio_static ) + add_library ( SuiteSparse::RBio_static ALIAS RBio_static ) + endif ( ) +endif ( ) + +if ( "spqr" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "SPQR" ) + if ( TARGET SPQR ) + add_library ( SuiteSparse::SPQR ALIAS SPQR ) + else ( ) + add_library ( SuiteSparse::SPQR ALIAS SPQR_static ) + endif ( ) + if ( TARGET SPQR_static ) + add_library ( SuiteSparse::SPQR_static ALIAS SPQR_static ) + endif ( ) +endif ( ) + +if ( "spex" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "SPEX" ) + if ( TARGET SPEX ) + add_library ( SuiteSparse::SPEX ALIAS SPEX ) + else ( ) + add_library ( SuiteSparse::SPEX ALIAS SPEX_static ) + endif ( ) + if ( TARGET SPEX_static ) + add_library ( SuiteSparse::SPEX_static ALIAS SPEX_static ) + endif ( ) +endif ( ) + +if ( "graphblas" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "GraphBLAS" ) + if ( TARGET GraphBLAS ) + add_library ( SuiteSparse::GraphBLAS ALIAS GraphBLAS ) + else ( ) + add_library ( SuiteSparse::GraphBLAS ALIAS GraphBLAS_static ) + endif ( ) + if ( TARGET GraphBLAS_static ) + add_library ( SuiteSparse::GraphBLAS_static ALIAS GraphBLAS_static ) + endif ( ) +endif ( ) + +if ( "lagraph" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "LAGraph" ) + if ( TARGET LAGraph ) + add_library ( SuiteSparse::LAGraph ALIAS LAGraph ) + else ( ) + add_library ( SuiteSparse::LAGraph ALIAS LAGraph_static ) + endif ( ) + if ( TARGET LAGraph_static ) + add_library ( SuiteSparse::LAGraph_static ALIAS LAGraph_static ) + endif ( ) +endif ( ) + +if ( "csparse" IN_LIST SUITESPARSE_ENABLE_PROJECTS ) + add_subdirectory ( "CSparse" ) + if ( TARGET CSparse ) + add_library ( SuiteSparse::CSparse ALIAS CSparse ) + else ( ) + add_library ( SuiteSparse::CSparse ALIAS CSparse_static ) + endif ( ) + if ( TARGET CSparse_static ) + add_library ( SuiteSparse::CSparse_static ALIAS CSparse_static ) + endif ( ) +endif ( ) + +#------------------------------------------------------------------------------- +# report status +#------------------------------------------------------------------------------- + +include ( SuiteSparseReport ) + +#------------------------------------------------------------------------------- +# enable testing facilities +#------------------------------------------------------------------------------- + +# Currently, only LAGraph, Mongoose, and CHOLMOD have ctests. + +# FIXME: convert more of the existing demos to ctests. + +# Most packages have a ./Tcov folder with a full statement coverage test, +# but these are not imported into cmake yet. + +# Most packages also have a ./Demo folder, with shorter examples. These would +# be nice to add as quick ctests. + +# CHOLMOD/Tcov takes about 20 minutes to run. It is also a full coverage +# test of AMD, CAMD, COLAMD, and CCOLAMD, however. The current CHOLMOD +# ctest is based on a few ./Demo programs. It's fast but not a full coverate +# test. + +# The CSparse/CXSparse Tcov tests are very fast and would be good candidates to +# add. + +include ( CTest ) + +#------------------------------------------------------------------------------- +# rule to remove all files in build directory +#------------------------------------------------------------------------------- + +file ( GLOB SUITESPARSE_BUILT_FILES ${PROJECT_BINARY_DIR}/* ) +file ( REAL_PATH ${PROJECT_SOURCE_DIR} _real_project_source_dir ) +file ( REAL_PATH ${PROJECT_BINARY_DIR} _real_project_binary_dir ) +if ( _real_project_source_dir STREQUAL _real_project_binary_dir ) + add_custom_target ( purge + COMMENT "The target 'purge' is a no-op for in-tree builds. Consider building out of the source tree." ) +else ( ) + add_custom_target ( purge + COMMAND ${CMAKE_COMMAND} -E echo "Removing files..." + COMMAND ${CMAKE_COMMAND} -E rm -rf ${SUITESPARSE_BUILT_FILES} + COMMENT "Purge all files in the build tree" ) +endif ( ) diff --git a/ThirdParty/SuiteSparse/COLAMD/CMakeLists.txt b/ThirdParty/SuiteSparse/COLAMD/CMakeLists.txt index 0f9603c950..39ac72edac 100644 --- a/ThirdParty/SuiteSparse/COLAMD/CMakeLists.txt +++ b/ThirdParty/SuiteSparse/COLAMD/CMakeLists.txt @@ -2,19 +2,19 @@ # SuiteSparse/COLAMD/CMakeLists.txt: cmake for COLAMD #------------------------------------------------------------------------------- -# Copyright (c) 1998-2023, Timothy A. Davis. All Rights Reserved. +# Copyright (c) 1998-2024, Timothy A. Davis. All Rights Reserved. # SPDX-License-Identifier: BSD-3-clause #------------------------------------------------------------------------------- # get the version #------------------------------------------------------------------------------- -cmake_minimum_required ( VERSION 3.19 ) +cmake_minimum_required ( VERSION 3.22 ) -set ( COLAMD_DATE "Jan 17, 2023" ) -set ( COLAMD_VERSION_MAJOR 3 ) -set ( COLAMD_VERSION_MINOR 0 ) -set ( COLAMD_VERSION_SUB 3 ) +set ( COLAMD_DATE "Jan 20, 2024" ) +set ( COLAMD_VERSION_MAJOR 3 CACHE STRING "" FORCE ) +set ( COLAMD_VERSION_MINOR 3 CACHE STRING "" FORCE ) +set ( COLAMD_VERSION_SUB 2 CACHE STRING "" FORCE ) message ( STATUS "Building COLAMD version: v" ${COLAMD_VERSION_MAJOR}. @@ -22,28 +22,33 @@ message ( STATUS "Building COLAMD version: v" ${COLAMD_VERSION_SUB} " (" ${COLAMD_DATE} ")" ) #------------------------------------------------------------------------------- -# SuiteSparse policies +# define the project #------------------------------------------------------------------------------- -set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules - ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) - -include ( SuiteSparsePolicy ) +project ( COLAMD + VERSION "${COLAMD_VERSION_MAJOR}.${COLAMD_VERSION_MINOR}.${COLAMD_VERSION_SUB}" + LANGUAGES C ) #------------------------------------------------------------------------------- -# define the project +# SuiteSparse policies #------------------------------------------------------------------------------- -project ( colamd - VERSION "${COLAMD_VERSION_MAJOR}.${COLAMD_VERSION_MINOR}.${COLAMD_VERSION_SUB}" - LANGUAGES C ) +set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + ${PROJECT_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) + +include ( SuiteSparsePolicy ) #------------------------------------------------------------------------------- # find library dependencies #------------------------------------------------------------------------------- -find_package ( SuiteSparse_config 7.0.0 REQUIRED ) +if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) + find_package ( SuiteSparse_config 7.6.0 + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_package ( SuiteSparse_config 7.6.0 REQUIRED ) + endif ( ) +endif ( ) #------------------------------------------------------------------------------- # configure files @@ -57,7 +62,7 @@ configure_file ( "Config/colamd.h.in" # include directories #------------------------------------------------------------------------------- -include_directories ( Source Include ${SUITESPARSE_CONFIG_INCLUDE_DIR} ) +include_directories ( Source Include ) #------------------------------------------------------------------------------- # dynamic colamd library properties @@ -65,48 +70,79 @@ include_directories ( Source Include ${SUITESPARSE_CONFIG_INCLUDE_DIR} ) file ( GLOB COLAMD_SOURCES "Source/*.c" ) -add_library ( colamd SHARED ${COLAMD_SOURCES} ) +if ( BUILD_SHARED_LIBS ) + add_library ( COLAMD SHARED ${COLAMD_SOURCES} ) + + set_target_properties ( COLAMD PROPERTIES + VERSION ${COLAMD_VERSION_MAJOR}.${COLAMD_VERSION_MINOR}.${COLAMD_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + OUTPUT_NAME colamd + SOVERSION ${COLAMD_VERSION_MAJOR} + PUBLIC_HEADER "Include/colamd.h" + WINDOWS_EXPORT_ALL_SYMBOLS ON ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( COLAMD PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) -set_target_properties ( colamd PROPERTIES - VERSION ${COLAMD_VERSION_MAJOR}.${COLAMD_VERSION_MINOR}.${COLAMD_VERSION_SUB} - C_STANDARD_REQUIRED 11 - SOVERSION ${COLAMD_VERSION_MAJOR} - PUBLIC_HEADER "Include/colamd.h" - WINDOWS_EXPORT_ALL_SYMBOLS ON ) + target_include_directories ( COLAMD + INTERFACE $ + $ ) +endif ( ) #------------------------------------------------------------------------------- # static colamd library properties #------------------------------------------------------------------------------- -if ( NOT NSTATIC ) - add_library ( colamd_static STATIC ${COLAMD_SOURCES} ) +if ( BUILD_STATIC_LIBS ) + add_library ( COLAMD_static STATIC ${COLAMD_SOURCES} ) - set_target_properties ( colamd_static PROPERTIES - VERSION ${COLAMD_VERSION_MAJOR}.${COLAMD_VERSION_MINOR}.${COLAMD_VERSION_SUB} + set_target_properties ( COLAMD_static PROPERTIES OUTPUT_NAME colamd - C_STANDARD_REQUIRED 11 - SOVERSION ${COLAMD_VERSION_MAJOR} ) + C_STANDARD 11 + C_STANDARD_REQUIRED ON + PUBLIC_HEADER "Include/colamd.h" ) if ( MSVC ) - set_target_properties ( colamd_static PROPERTIES + set_target_properties ( COLAMD_static PROPERTIES OUTPUT_NAME colamd_static ) endif ( ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( COLAMD_static PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( COLAMD_static + INTERFACE $ + $ ) endif ( ) #------------------------------------------------------------------------------- # add the library dependencies #------------------------------------------------------------------------------- -target_link_libraries ( colamd PUBLIC ${SUITESPARSE_CONFIG_LIBRARY} ) -if ( NOT NSTATIC ) - target_link_libraries ( colamd_static PUBLIC ${SUITESPARSE_CONFIG_STATIC} ) +if ( BUILD_SHARED_LIBS ) + target_link_libraries ( COLAMD PRIVATE SuiteSparse::SuiteSparseConfig ) + target_include_directories ( COLAMD PUBLIC + "$" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + if ( TARGET SuiteSparse::SuiteSparseConfig_static ) + target_link_libraries ( COLAMD_static PUBLIC SuiteSparse::SuiteSparseConfig_static ) + else ( ) + target_link_libraries ( COLAMD_static PUBLIC SuiteSparse::SuiteSparseConfig ) + endif ( ) endif ( ) # libm: if ( NOT WIN32 ) - target_link_libraries ( colamd PUBLIC m ) - if ( NOT NSTATIC ) - target_link_libraries ( colamd_static PUBLIC m ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( COLAMD PRIVATE m ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + set ( COLAMD_STATIC_LIBS "${COLAMD_STATIC_LIBS} -lm" ) + target_link_libraries ( COLAMD_static PUBLIC m ) endif ( ) endif ( ) @@ -114,25 +150,99 @@ endif ( ) # COLAMD installation location #------------------------------------------------------------------------------- -install ( TARGETS colamd - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} - RUNTIME DESTINATION ${SUITESPARSE_BINDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) -install ( FILES ${CMAKE_SOURCE_DIR}/cmake_modules/FindCOLAMD.cmake - DESTINATION ${SUITESPARSE_LIBDIR}/cmake/SuiteSparse - COMPONENT Development ) -if ( NOT NSTATIC ) - install ( TARGETS colamd_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) +include ( CMakePackageConfigHelpers ) + +if ( BUILD_SHARED_LIBS ) + install ( TARGETS COLAMD + EXPORT COLAMDTargets + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + install ( TARGETS COLAMD_static + EXPORT COLAMDTargets + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) + +# create (temporary) export target file during build +export ( EXPORT COLAMDTargets + NAMESPACE SuiteSparse:: + FILE ${CMAKE_CURRENT_BINARY_DIR}/COLAMDTargets.cmake ) + +# install export target, config and version files for find_package +install ( EXPORT COLAMDTargets + NAMESPACE SuiteSparse:: + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/COLAMD ) + +# generate config file to be used in common build tree +set ( SUITESPARSE_IN_BUILD_TREE ON ) +configure_package_config_file ( + Config/COLAMDConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/COLAMDConfig.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/COLAMDConfig.cmake ) + +# generate config file to be installed +set ( SUITESPARSE_IN_BUILD_TREE OFF ) +configure_package_config_file ( + Config/COLAMDConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/target/COLAMDConfig.cmake + INSTALL_DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/COLAMD ) + +write_basic_package_version_file ( + ${CMAKE_CURRENT_BINARY_DIR}/COLAMDConfigVersion.cmake + COMPATIBILITY SameMajorVersion ) + +install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/target/COLAMDConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/COLAMDConfigVersion.cmake + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/COLAMD ) + +#------------------------------------------------------------------------------- +# create pkg-config file +#------------------------------------------------------------------------------- + +if ( NOT MSVC ) + set ( prefix "${CMAKE_INSTALL_PREFIX}" ) + set ( exec_prefix "\${prefix}" ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_LIBDIR SUITESPARSE_LIBDIR_IS_ABSOLUTE ) + if (SUITESPARSE_LIBDIR_IS_ABSOLUTE) + set ( libdir "${SUITESPARSE_LIBDIR}") + else ( ) + set ( libdir "\${exec_prefix}/${SUITESPARSE_LIBDIR}") + endif ( ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_INCLUDEDIR SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE ) + if (SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE) + set ( includedir "${SUITESPARSE_INCLUDEDIR}") + else ( ) + set ( includedir "\${prefix}/${SUITESPARSE_INCLUDEDIR}") + endif ( ) + if ( BUILD_SHARED_LIBS ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + endif ( ) + configure_file ( + Config/COLAMD.pc.in + COLAMD.pc.out + @ONLY + NEWLINE_STYLE LF ) + file ( GENERATE + OUTPUT COLAMD.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/COLAMD.pc.out + NEWLINE_STYLE LF ) + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/COLAMD.pc + DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) endif ( ) #------------------------------------------------------------------------------- # Demo library and programs #------------------------------------------------------------------------------- -option ( DEMO "ON: Build the demo programs. OFF (default): do not build the demo programs." off ) -if ( DEMO ) +if ( SUITESPARSE_DEMOS ) #--------------------------------------------------------------------------- # demo library @@ -148,8 +258,13 @@ if ( DEMO ) add_executable ( colamd_l_example "Demo/colamd_l_example.c" ) # Libraries required for Demo programs - target_link_libraries ( colamd_example PUBLIC colamd ) - target_link_libraries ( colamd_l_example PUBLIC colamd ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( colamd_example PUBLIC COLAMD ) + target_link_libraries ( colamd_l_example PUBLIC COLAMD ) + else ( ) + target_link_libraries ( colamd_example PUBLIC COLAMD_static ) + target_link_libraries ( colamd_l_example PUBLIC COLAMD_static ) + endif ( ) else ( ) @@ -162,4 +277,3 @@ endif ( ) #------------------------------------------------------------------------------- include ( SuiteSparseReport ) - diff --git a/ThirdParty/SuiteSparse/COLAMD/Config/COLAMD.pc.in b/ThirdParty/SuiteSparse/COLAMD/Config/COLAMD.pc.in new file mode 100644 index 0000000000..5444c608f8 --- /dev/null +++ b/ThirdParty/SuiteSparse/COLAMD/Config/COLAMD.pc.in @@ -0,0 +1,17 @@ +# COLAMD, Copyright (c) 1998-2023, Timothy A. Davis. +# All Rights Reserved. +# SPDX-License-Identifier: BSD-3-Clause + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: COLAMD +URL: https://github.com/DrTimothyAldenDavis/SuiteSparse +Description: Routines for column approximate minimum degree ordering algorithm in SuiteSparse +Version: @COLAMD_VERSION_MAJOR@.@COLAMD_VERSION_MINOR@.@COLAMD_VERSION_SUB@ +Requires.private: SuiteSparse_config +Libs: -L${libdir} -l@SUITESPARSE_LIB_BASE_NAME@ +Libs.private: @COLAMD_STATIC_LIBS@ +Cflags: -I${includedir} diff --git a/ThirdParty/SuiteSparse/COLAMD/Config/COLAMDConfig.cmake.in b/ThirdParty/SuiteSparse/COLAMD/Config/COLAMDConfig.cmake.in new file mode 100644 index 0000000000..7bb4701f49 --- /dev/null +++ b/ThirdParty/SuiteSparse/COLAMD/Config/COLAMDConfig.cmake.in @@ -0,0 +1,152 @@ +#------------------------------------------------------------------------------- +# SuiteSparse/COLAMD/cmake_modules/COLAMDConfig.cmake +#------------------------------------------------------------------------------- + +# The following copyright and license applies to just this file only, not to +# the library itself: +# COLAMDConfig.cmake, Copyright (c) 2023, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: BSD-3-clause + +#------------------------------------------------------------------------------- + +# Finds the COLAMD include file and compiled library. +# The following targets are defined: +# SuiteSparse::COLAMD - for the shared library (if available) +# SuiteSparse::COLAMD_static - for the static library (if available) + +# For backward compatibility the following variables are set: + +# COLAMD_INCLUDE_DIR - where to find colamd.h +# COLAMD_LIBRARY - dynamic COLAMD library +# COLAMD_STATIC - static COLAMD library +# COLAMD_LIBRARIES - libraries when using COLAMD +# COLAMD_FOUND - true if COLAMD found + +# Set ``CMAKE_MODULE_PATH`` to the parent folder where this module file is +# installed. + +#------------------------------------------------------------------------------- + +@PACKAGE_INIT@ + +set ( COLAMD_DATE "@COLAMD_DATE@" ) +set ( COLAMD_VERSION_MAJOR @COLAMD_VERSION_MAJOR@ ) +set ( COLAMD_VERSION_MINOR @COLAMD_VERSION_MINOR@ ) +set ( COLAMD_VERSION_PATCH @COLAMD_VERSION_SUB@ ) +set ( COLAMD_VERSION "@COLAMD_VERSION_MAJOR@.@COLAMD_VERSION_MINOR@.@COLAMD_VERSION_SUB@" ) + +# Check for dependent targets +include ( CMakeFindDependencyMacro ) + +# Look for SuiteSparse_config target +if ( @SUITESPARSE_IN_BUILD_TREE@ ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + # First check in a common build tree + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT SuiteSparse_config_FOUND ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) + endif ( ) +else ( ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) +endif ( ) +if ( NOT SuiteSparse_config_FOUND ) + set ( COLAMD_FOUND OFF ) + return ( ) +endif ( ) + + +# Import target +include ( ${CMAKE_CURRENT_LIST_DIR}/COLAMDTargets.cmake ) + +# The following is only for backward compatibility with FindCOLAMD. + +set ( _target_shared SuiteSparse::COLAMD ) +set ( _target_static SuiteSparse::COLAMD_static ) +set ( _var_prefix "COLAMD" ) + +if ( NOT @BUILD_SHARED_LIBS@ AND NOT TARGET ${_target_shared} ) + # make sure there is always an import target without suffix ) + add_library ( ${_target_shared} ALIAS ${_target_static} ) +endif ( ) + +get_target_property ( ${_var_prefix}_INCLUDE_DIR ${_target_shared} INTERFACE_INCLUDE_DIRECTORIES ) +if ( ${_var_prefix}_INCLUDE_DIR ) + # First item in SuiteSparse targets contains the "main" header directory. + list ( GET ${_var_prefix}_INCLUDE_DIR 0 ${_var_prefix}_INCLUDE_DIR ) +endif ( ) +get_target_property ( ${_var_prefix}_LIBRARY ${_target_shared} IMPORTED_IMPLIB ) +if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} IMPORTED_LOCATION ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) +endif ( ) +if ( TARGET ${_target_static} ) + get_target_property ( ${_var_prefix}_STATIC ${_target_static} IMPORTED_LOCATION ) +endif ( ) + +# Check for most common build types +set ( _config_types "Debug" "Release" "RelWithDebInfo" "MinSizeRel" "None" ) + +get_property ( _isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) +if ( _isMultiConfig ) + # For multi-configuration generators (e.g., Visual Studio), prefer those + # configurations. + list ( PREPEND _config_types ${CMAKE_CONFIGURATION_TYPES} ) +else ( ) + # For single-configuration generators, prefer the current configuration. + list ( PREPEND _config_types ${CMAKE_BUILD_TYPE} ) +endif ( ) + +list ( REMOVE_DUPLICATES _config_types ) + +foreach ( _config ${_config_types} ) + string ( TOUPPER ${_config} _uc_config ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_IMPLIB_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( TARGET ${_target_static} AND NOT ${_var_prefix}_STATIC ) + get_target_property ( _library_chk ${_target_static} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_STATIC ${_library_chk} ) + endif ( ) + endif ( ) +endforeach ( ) + +set ( COLAMD_LIBRARIES ${COLAMD_LIBRARY} ) + +macro ( suitesparse_check_exist _var _files ) + # ignore generator expressions + string ( GENEX_STRIP "${_files}" _files2 ) + + foreach ( _file ${_files2} ) + if ( NOT EXISTS "${_file}" ) + message ( FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist!" ) + endif ( ) + endforeach () +endmacro ( ) + +suitesparse_check_exist ( COLAMD_INCLUDE_DIR ${COLAMD_INCLUDE_DIR} ) +suitesparse_check_exist ( COLAMD_LIBRARY ${COLAMD_LIBRARY} ) + +message ( STATUS "COLAMD version: ${COLAMD_VERSION}" ) +message ( STATUS "COLAMD include: ${COLAMD_INCLUDE_DIR}" ) +message ( STATUS "COLAMD library: ${COLAMD_LIBRARY}" ) +message ( STATUS "COLAMD static: ${COLAMD_STATIC}" ) diff --git a/ThirdParty/SuiteSparse/COLAMD/Config/colamd.h.in b/ThirdParty/SuiteSparse/COLAMD/Config/colamd.h.in index fb0450ac45..2d9a0c07f7 100644 --- a/ThirdParty/SuiteSparse/COLAMD/Config/colamd.h.in +++ b/ThirdParty/SuiteSparse/COLAMD/Config/colamd.h.in @@ -1,8 +1,8 @@ //------------------------------------------------------------------------------ -// COLAMD/Source/colamd.h: include file for COLAMD +// COLAMD/Include/colamd.h: include file for COLAMD //------------------------------------------------------------------------------ -// COLAMD, Copyright (c) 1998-2022, Timothy A. Davis and Stefan Larimore, +// COLAMD, Copyright (c) 1998-2024, Timothy A. Davis and Stefan Larimore, // All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause @@ -37,11 +37,6 @@ #ifndef COLAMD_H #define COLAMD_H -/* make it easy for C++ programs to include COLAMD */ -#ifdef __cplusplus -extern "C" { -#endif - /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ @@ -75,9 +70,14 @@ extern "C" { #define COLAMD_SUB_VERSION @COLAMD_VERSION_MINOR@ #define COLAMD_SUBSUB_VERSION @COLAMD_VERSION_SUB@ -#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define COLAMD_VERSION \ - COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) +#define COLAMD_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define COLAMD_VERSION COLAMD_VERSION_CODE(@COLAMD_VERSION_MAJOR@,@COLAMD_VERSION_MINOR@) + +#define COLAMD__VERSION SUITESPARSE__VERCODE(@COLAMD_VERSION_MAJOR@,@COLAMD_VERSION_MINOR@,@COLAMD_VERSION_SUB@) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,6,0)) +#error "COLAMD @COLAMD_VERSION_MAJOR@.@COLAMD_VERSION_MINOR@.@COLAMD_VERSION_SUB@ requires SuiteSparse_config 7.6.0 or later" +#endif /* ========================================================================== */ /* === Knob and statistics definitions ====================================== */ @@ -129,6 +129,11 @@ extern "C" { /* === Prototypes of user-callable routines ================================= */ /* ========================================================================== */ +/* make it easy for C++ programs to include COLAMD */ +#ifdef __cplusplus +extern "C" { +#endif + size_t colamd_recommended /* returns recommended value of Alen, */ /* or 0 if input arguments are erroneous */ ( @@ -229,6 +234,8 @@ void symamd_l_report int64_t stats [COLAMD_STATS] ) ; +void colamd_version (int version [3]) ; + #ifdef __cplusplus } #endif diff --git a/ThirdParty/SuiteSparse/COLAMD/Doc/ChangeLog b/ThirdParty/SuiteSparse/COLAMD/Doc/ChangeLog index f7a3dcf3c8..9904dacaf3 100644 --- a/ThirdParty/SuiteSparse/COLAMD/Doc/ChangeLog +++ b/ThirdParty/SuiteSparse/COLAMD/Doc/ChangeLog @@ -1,3 +1,28 @@ +Jan 20, 2024: version 3.3.2 + + * minor updates to build system + +Jan 10, 2024: version 3.3.1 + + * minor updates to build system + +Dec 30, 2023: version 3.3.0 + + * major change to build system: by Markus Mützel + * colamd_version: added to return version of COLAMD + +Sept 18, 2023: version 3.2.1 + + * cmake update: add "None" build type, from Antonio Rojas, for Arch Linux + +Sept 8, 2023: version 3.2.0 + + * cmake updates: SuiteSparse:: namespace by Markus Muetzel + +June 16, 2023: version 3.0.4 + + * cmake build system updates: update by Markus Muetzel + Jan 17, 2023: version 3.0.3 * SuiteSparse_config: now v7.0.0 diff --git a/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h b/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h index f258ef68ec..93c2c08eba 100644 --- a/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h +++ b/ThirdParty/SuiteSparse/COLAMD/Include/colamd.h @@ -1,8 +1,8 @@ //------------------------------------------------------------------------------ -// COLAMD/Source/colamd.h: include file for COLAMD +// COLAMD/Include/colamd.h: include file for COLAMD //------------------------------------------------------------------------------ -// COLAMD, Copyright (c) 1998-2022, Timothy A. Davis and Stefan Larimore, +// COLAMD, Copyright (c) 1998-2024, Timothy A. Davis and Stefan Larimore, // All Rights Reserved. // SPDX-License-Identifier: BSD-3-clause @@ -37,11 +37,6 @@ #ifndef COLAMD_H #define COLAMD_H -/* make it easy for C++ programs to include COLAMD */ -#ifdef __cplusplus -extern "C" { -#endif - /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ @@ -70,14 +65,19 @@ extern "C" { * Versions 2.3 and earlier of COLAMD do not include a #define'd version number. */ -#define COLAMD_DATE "Jan 17, 2023" +#define COLAMD_DATE "Jan 20, 2024" #define COLAMD_MAIN_VERSION 3 -#define COLAMD_SUB_VERSION 0 -#define COLAMD_SUBSUB_VERSION 3 +#define COLAMD_SUB_VERSION 3 +#define COLAMD_SUBSUB_VERSION 2 + +#define COLAMD_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define COLAMD_VERSION COLAMD_VERSION_CODE(3,3) -#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define COLAMD_VERSION \ - COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) +#define COLAMD__VERSION SUITESPARSE__VERCODE(3,3,2) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,6,0)) +#error "COLAMD 3.3.2 requires SuiteSparse_config 7.6.0 or later" +#endif /* ========================================================================== */ /* === Knob and statistics definitions ====================================== */ @@ -129,6 +129,11 @@ extern "C" { /* === Prototypes of user-callable routines ================================= */ /* ========================================================================== */ +/* make it easy for C++ programs to include COLAMD */ +#ifdef __cplusplus +extern "C" { +#endif + size_t colamd_recommended /* returns recommended value of Alen, */ /* or 0 if input arguments are erroneous */ ( @@ -229,6 +234,8 @@ void symamd_l_report int64_t stats [COLAMD_STATS] ) ; +void colamd_version (int version [3]) ; + #ifdef __cplusplus } #endif diff --git a/ThirdParty/SuiteSparse/COLAMD/Makefile b/ThirdParty/SuiteSparse/COLAMD/Makefile index 2c7de9ee43..787ee26f3b 100644 --- a/ThirdParty/SuiteSparse/COLAMD/Makefile +++ b/ThirdParty/SuiteSparse/COLAMD/Makefile @@ -36,27 +36,27 @@ default: library # default is to install only in /usr/local library: - ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . --config Release -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=1 .. && cmake --build . --config Release -j${JOBS} ) # install only in /usr/local (default) global: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=0 .. && cmake --build . --config Release -j${JOBS} ) debug: - ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . --config Debug -j${JOBS} ) all: library demos: library - ( cd build && cmake $(CMAKE_OPTIONS) -DDEMO=1 .. && cmake --build . -j${JOBS} ) - - ./build/colamd_example > ./build/colamd_example.out - - diff --strip-trailing-cr ./Demo/colamd_example.out ./build/colamd_example.out - - ./build/colamd_l_example > ./build/colamd_l_example.out - - diff --strip-trailing-cr ./Demo/colamd_l_example.out ./build/colamd_l_example.out + ( cd build && cmake $(CMAKE_OPTIONS) -DSUITESPARSE_DEMOS=1 .. && cmake --build . --config Release -j${JOBS} ) + - ./build/colamd_example > ./build/colamd_example.out && ( command -v d2u && d2u ./build/colamd_example.out || true ) + - diff ./Demo/colamd_example.out ./build/colamd_example.out + - ./build/colamd_l_example > ./build/colamd_l_example.out && ( command -v d2u && d2u ./build/colamd_l_example.out || true ) + - diff ./Demo/colamd_l_example.out ./build/colamd_l_example.out # just compile after running cmake; do not run cmake again remake: @@ -64,7 +64,7 @@ remake: # just run cmake to set things up setup: - ( cd build ; cmake $(CMAKE_OPTIONS) .. ) + ( cd build && cmake $(CMAKE_OPTIONS) .. ) install: ( cd build && cmake --install . ) diff --git a/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c b/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c index af5b27f7a0..968d90fc6a 100644 --- a/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c +++ b/ThirdParty/SuiteSparse/COLAMD/Source/colamd.c @@ -1046,7 +1046,6 @@ size_t COLAMD_recommended /* returns recommended value of Alen. */ return (ok ? s : 0) ; } - /* ========================================================================== */ /* === colamd_set_defaults ================================================== */ /* ========================================================================== */ diff --git a/ThirdParty/SuiteSparse/COLAMD/Source/colamd_version.c b/ThirdParty/SuiteSparse/COLAMD/Source/colamd_version.c new file mode 100644 index 0000000000..9184817efa --- /dev/null +++ b/ThirdParty/SuiteSparse/COLAMD/Source/colamd_version.c @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// COLAMD/Source/colamd_version.c: return COLAMD version +//------------------------------------------------------------------------------ + +// COLAMD, Copyright (c) 1998-2022, Timothy A. Davis and Stefan Larimore, +// All Rights Reserved. +// SPDX-License-Identifier: BSD-3-clause + +//------------------------------------------------------------------------------ + +#include "colamd.h" + +void colamd_version (int version [3]) +{ + version [0] = COLAMD_MAIN_VERSION ; + version [1] = COLAMD_SUB_VERSION ; + version [2] = COLAMD_SUBSUB_VERSION ; +} + diff --git a/ThirdParty/SuiteSparse/COLAMD/cmake_modules/FindCOLAMD.cmake b/ThirdParty/SuiteSparse/COLAMD/cmake_modules/FindCOLAMD.cmake deleted file mode 100644 index 00e8a9ac0f..0000000000 --- a/ThirdParty/SuiteSparse/COLAMD/cmake_modules/FindCOLAMD.cmake +++ /dev/null @@ -1,129 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/COLAMD/cmake_modules/FindCOLAMD.cmake -#------------------------------------------------------------------------------- - -# The following copyright and license applies to just this file only, not to -# the library itself: -# FindCOLAMD.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# Finds the COLAMD include file and compiled library and sets: - -# COLAMD_INCLUDE_DIR - where to find colamd.h -# COLAMD_LIBRARY - dynamic COLAMD library -# COLAMD_STATIC - static COLAMD library -# COLAMD_LIBRARIES - libraries when using COLAMD -# COLAMD_FOUND - true if COLAMD found - -# set ``COLAMD_ROOT`` to a COLAMD installation root to -# tell this module where to look. - -# All the Find*.cmake files in SuiteSparse are installed by 'make install' into -# /usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the -# ${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands -# in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: -# -# set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} -# ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) - -#------------------------------------------------------------------------------- - -# include files for COLAMD -find_path ( COLAMD_INCLUDE_DIR - NAMES colamd.h - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/COLAMD - HINTS ${CMAKE_SOURCE_DIR}/../COLAMD - PATH_SUFFIXES include Include -) - -# dynamic COLAMD library (or static if no dynamic library was built) -find_library ( COLAMD_LIBRARY - NAMES colamd colamd_static - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/COLAMD - HINTS ${CMAKE_SOURCE_DIR}/../COLAMD - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( MSVC ) - set ( STATIC_NAME colamd_static ) -else ( ) - set ( STATIC_NAME colamd ) - set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) -endif ( ) - -# static COLAMD library -find_library ( COLAMD_STATIC - NAMES ${STATIC_NAME} - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/COLAMD - HINTS ${CMAKE_SOURCE_DIR}/../COLAMD - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) -endif ( ) - -# get version of the library from the dynamic library name -get_filename_component ( COLAMD_LIBRARY ${COLAMD_LIBRARY} REALPATH ) -get_filename_component ( COLAMD_FILENAME ${COLAMD_LIBRARY} NAME ) -string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - COLAMD_VERSION - ${COLAMD_FILENAME} -) - -# set ( COLAMD_VERSION "" ) -if ( EXISTS "${COLAMD_INCLUDE_DIR}" AND NOT COLAMD_VERSION ) - # if the version does not appear in the filename, read the include file - file ( STRINGS ${COLAMD_INCLUDE_DIR}/colamd.h COLAMD_MAJOR_STR - REGEX "define COLAMD_MAIN_VERSION" ) - file ( STRINGS ${COLAMD_INCLUDE_DIR}/colamd.h COLAMD_MINOR_STR - REGEX "define COLAMD_SUB_VERSION" ) - file ( STRINGS ${COLAMD_INCLUDE_DIR}/colamd.h COLAMD_PATCH_STR - REGEX "define COLAMD_SUBSUB_VERSION" ) - message ( STATUS "major: ${COLAMD_MAJOR_STR}" ) - message ( STATUS "minor: ${COLAMD_MINOR_STR}" ) - message ( STATUS "patch: ${COLAMD_PATCH_STR}" ) - string ( REGEX MATCH "[0-9]+" COLAMD_MAJOR ${COLAMD_MAJOR_STR} ) - string ( REGEX MATCH "[0-9]+" COLAMD_MINOR ${COLAMD_MINOR_STR} ) - string ( REGEX MATCH "[0-9]+" COLAMD_PATCH ${COLAMD_PATCH_STR} ) - set (COLAMD_VERSION "${COLAMD_MAJOR}.${COLAMD_MINOR}.${COLAMD_PATCH}") -endif ( ) - -set (COLAMD_LIBRARIES ${COLAMD_LIBRARY}) - -include (FindPackageHandleStandardArgs) - -find_package_handle_standard_args ( COLAMD - REQUIRED_VARS COLAMD_LIBRARY COLAMD_INCLUDE_DIR - VERSION_VAR COLAMD_VERSION -) - -mark_as_advanced ( - COLAMD_INCLUDE_DIR - COLAMD_LIBRARY - COLAMD_STATIC - COLAMD_LIBRARIES -) - -if ( COLAMD_FOUND ) - message ( STATUS "COLAMD version: ${COLAMD_VERSION}" ) - message ( STATUS "COLAMD include: ${COLAMD_INCLUDE_DIR}" ) - message ( STATUS "COLAMD library: ${COLAMD_LIBRARY}" ) - message ( STATUS "COLAMD static: ${COLAMD_STATIC}" ) -else ( ) - message ( STATUS "COLAMD not found" ) - set ( COLAMD_INCLUDE_DIR "" ) - set ( COLAMD_LIBRARIES "" ) - set ( COLAMD_LIBRARY "" ) - set ( COLAMD_STATIC "" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/ChangeLog b/ThirdParty/SuiteSparse/ChangeLog index 06fe8950bc..0f1eb87902 100644 --- a/ThirdParty/SuiteSparse/ChangeLog +++ b/ThirdParty/SuiteSparse/ChangeLog @@ -1,3 +1,175 @@ +Jan 20, 2024: version 7.6.0 + + * CHOLMOD 5.2.0: bug fix (restore ABI compatibility with 5.0.x, i.e., 5.2.0 + is ABI incompatible to 5.1.x) + * SuiteSparse_config 7.6.0, Mongoose 3.3.2, COLAMD 3.3.2, CCOLAMD 3.3.2: + port Makefile to Windows + * SPQR 4.3.2: remove unused parameters + * LAGraph 1.1.2, CSparse 4.3.1, ParU 0.1.2, GraphBLAS 9.0.1: + minor updates to build system + * Example 1.6.2, UMFPACK 6.3.2, KLU 2.3.2, SuiteSparse_Mongoose 3.3.2, + SPEX 2.3.2: revise version numbers of dependent packages + * AMD, BTF, CAMD, CXSparse, LDL, RBio: unchanged + * Package versions in this release: + SuiteSparse_config 7.6.0 + AMD 3.3.1 + BTF 2.3.1 + CAMD 3.3.1 + CCOLAMD 3.3.2 + CHOLMOD 5.2.0 + COLAMD 3.3.2 + CSparse 4.3.1 + CXSparse 4.3.1 + Example 1.6.2 + GraphBLAS 9.0.1 + KLU 2.3.2 + LDL 3.3.1 + LAGraph 1.1.2 + SuiteSparse_Mongoose 3.3.2 + ParU 0.1.2 + RBio 4.3.1 + SPEX 2.3.2 + SPQR 4.3.2 + UMFPACK 6.3.2 + +Jan 12, 2024: version 7.5.1 + + * SuiteSparse_config: bug fix to SUITESPARSE__VERCODE macro. + * Example 1.6.1: add tests for *__VERSION macros. + + * Package versions in this release: + SuiteSparse_config 7.5.1 + AMD 3.3.1 + BTF 2.3.1 + CAMD 3.3.1 + CCOLAMD 3.3.1 + CHOLMOD 5.1.1 + COLAMD 3.3.1 + CSparse 4.3.0 + CXSparse 4.3.1 + Example 1.6.1 + GraphBLAS 9.0.0 + KLU 2.3.1 + LDL 3.3.1 + LAGraph 1.1.1 + SuiteSparse_Mongoose 3.3.1 + ParU 0.1.1 + RBio 4.3.1 + SPEX 2.3.1 + SPQR 4.3.1 + UMFPACK 6.3.1 + +Jan 10, 2024: version 7.5.0 + + * SuiteSparse_config: 7.5.0, to reflect the addition of GraphBLAS 9.0.0. + Minor updates to build system, including bug fixes when specifying a + specific BLAS/LAPACK library, and configuration of *.pc files. + * GraphBLAS 9.0.0: supporting the v2.1 C API; + see https://github.com/GraphBLAS/graphblas-api-c + * Example 1.6.0: using GraphBLAS 9.0.0 and SuiteSparse_config 7.5.0, + remove explicit dependencies on OpenMP, libm, GMP, and MPFR. + Add programs to test the *Config.cmake of each package. + * All other packages (except CSparse): minor updates to build system + and MATLAB interfaces + + * Package versions in this release: + SuiteSparse_config 7.5.0 + AMD 3.3.1 + BTF 2.3.1 + CAMD 3.3.1 + CCOLAMD 3.3.1 + CHOLMOD 5.1.1 + COLAMD 3.3.1 + CSparse 4.3.0 (unchanged from SuiteSparse 7.4.0) + CXSparse 4.3.1 + Example 1.6.0 + GraphBLAS 9.0.0 + KLU 2.3.1 + LDL 3.3.1 + LAGraph 1.1.1 + SuiteSparse_Mongoose 3.3.1 + ParU 0.1.1 + RBio 4.3.1 + SPEX 2.3.1 + SPQR 4.3.1 + UMFPACK 6.3.1 + +Dec 30, 2023: version 7.4.0 + + * major change to build system: by Markus Mützel. Includes a + top-level CMakeLists.txt that builds all packages, and support for + pkg-config. Default location of files is now listed below, where + PACKAGE is one of the packages in SuiteSparse: + * CMAKE_INSTALL_PREFIX/include/suitesparse: include files + * CMAKE_INSTALL_PREFIX/lib: compiled libraries + * CMAKE_INSTALL_PREFIX/lib/cmake/SuiteSparse: helper *.cmake scripts + for all of SuiteSparse + * CMAKE_INSTALL_PREFIX/lib/cmake/PACKAGE: *Config.cmake scripts for a + specific package + * CMAKE_INSTALL_PREFIX/lib/pkgconfig/PACKAGE.pc: *.pc pkg-config + files with information for a specific package + Additional changes are listed below. + * LAGraph 1.1.0: new package: graph algorithms based on GraphBLAS + * ParU 0.1.0: new package: parallel unsymmetric multifrontal method, + with Mohsen Aznaveh. This is a stable package but is tagged as 0.1.0 + since the API is still subject to change. + * CHOLMOD 5.1.0: full support for sparse single precision matrices, + bug fixes in the GPU Module. + * AMD 3.3.0: minor change for CHOLMOD 5.1.0 tests + * CAMD 3.3.0: minor change for CHOLMOD 5.1.0 tests + * SuiteSparse_config 7.4.0: added wrappers for single-precision BLAS/LAPACK, + added SUITESPARSE_TIME macro. + * *_version: added methods to all package that didn't have them: + AMD, CAMD, COLAMD, CCOLAMD, BTF, CSparse, CXSparse, KLU, BTF, RBio, + SPEX, SPQR, and UMFPACK. + +Oct 31, 2023: version 7.3.1 + + * CHOLMOD 5.0.1: remove "I" from cholmod.h. + +Oct 23, 2023: version 7.3.0 + + * CHOLMOD 5.0.0: initial support for sparse single precision matries. + CHOLMOD:Core replaced with CHOLMOD:Utility + * updated to require CHOLMOD 5.0.0: + Example 1.4.3, GPUQREngine 3.3.3, KLU 2.2.2, SPQR 4.2.2, UMFPACK 6.2.2 + * SuiteSparseLAPACK.cmake: allow the use of BLIS/FLAME for LAPACK; + update from Theirry Thomas. + * build system: further updates to cmake, by Markus Muetzel. + +Oct 18, 2023: version 7.2.2 + + * CHOLMOD 4.2.2: bug fix to CHOLMOD/Supernodal (heuristic to determine + # threads to use for last supernode was incorrect) + +Oct 7, 2023: version 7.2.1 + + * GraphBLAS 8.2.1: bug fix to GrB_mxm; incorrect handling of typecasting + * cross-compiler support: replace check_c_source_runs with _compiles, + for GraphBLAS and SuiteSparse_config, and remove check for + getenv("HOME"). + * cmake update: add "None" build type, from Antonio Rojas, for Arch Linux, + to all *Config.cmake files for all packages except CSparse (CXSparse + is built instead, and CSparse does not have CSparseConfig.cmake file) + * UMFPACK v6.2.1 and GPUQREngine v3.2.1: copies internal include files + from other SuiteSparse packages (AMD and SuiteSparse_GPURuntime), + so these two packages can be built independently. + +Sept 8, 2023: version 7.2.0 + + * build system: modern cmake structure, by Markus Muetzel. + Most packages updated to vX.2.0 where X is unchanged (except SPQR + and Example package). + * SPQR v4.2.0: Major SO update. Support for int32 indices by Raye Kimmerer + +June 29, 2023: version 7.1.0 + + * GraphBLAS v8.0.2: major update with a new JIT feature. + * build system: many changes to build systems of all packages, contributed + by Markus Muetzel. + * RBio 4.0.0: revised API: declaring many input parameters as const + * CXSparse 4.0.4: changed complex types for C++ callers + Jan 20, 2023: version 7.0.1 * GraphBLAS v7.4.3: debug was left on in GrB_Matrix_removeElement @@ -128,7 +300,7 @@ Mar 14, 2022, SuiteSparse 5.11.0 v1.9.3, Copyright (c) 2011-2016, Yann Collet, All Rights Reserved. * iso-valued matrices and vectors: to exploit the common case of an unweighted graph - * bug fixes: 4 bugs fixed since SuiteSparse 5.10.1 with + * bug fixes: 4 bugs fixed since SuiteSparse 5.10.1 with GraphBLAS v5.0.5. 12 other bugs appeared in the interim but appeared in versions after v5.0.5 but fixed before ever affecting SuiteSparse itself. @@ -496,7 +668,7 @@ June 20, 2012: SuiteSparse version 4.0.1 * UMFPACK 5.6.1: minor fix to MATLAB install; no change to C except version nubmer * MATLAB_Tools: - update to UFcollection (filesep) + update to UFcollection (filesep) June 1, 2012: SuiteSparse version 4.0.0 diff --git a/ThirdParty/SuiteSparse/KLU/CMakeLists.txt b/ThirdParty/SuiteSparse/KLU/CMakeLists.txt index f2e88576e3..05025e37f1 100644 --- a/ThirdParty/SuiteSparse/KLU/CMakeLists.txt +++ b/ThirdParty/SuiteSparse/KLU/CMakeLists.txt @@ -2,7 +2,7 @@ # SuiteSparse/KLU/CMakeLists.txt: cmake for KLU #------------------------------------------------------------------------------- -# KLU, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +# KLU, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. # Authors: Timothy A. Davis and Ekanathan Palamadai. # SPDX-License-Identifier: LGPL-2.1+ @@ -10,12 +10,12 @@ # get the version #------------------------------------------------------------------------------- -cmake_minimum_required ( VERSION 3.19 ) +cmake_minimum_required ( VERSION 3.22 ) -set ( KLU_DATE "Jan 17, 2023" ) -set ( KLU_VERSION_MAJOR 2 ) -set ( KLU_VERSION_MINOR 0 ) -set ( KLU_VERSION_SUB 3 ) +set ( KLU_DATE "Jan 20, 2024" ) +set ( KLU_VERSION_MAJOR 2 CACHE STRING "" FORCE ) +set ( KLU_VERSION_MINOR 3 CACHE STRING "" FORCE ) +set ( KLU_VERSION_SUB 2 CACHE STRING "" FORCE ) message ( STATUS "Building KLU version: v" ${KLU_VERSION_MAJOR}. @@ -23,60 +23,86 @@ message ( STATUS "Building KLU version: v" ${KLU_VERSION_SUB} " (" ${KLU_DATE} ")" ) #------------------------------------------------------------------------------- +# define the project +#------------------------------------------------------------------------------- + +project ( KLU + VERSION "${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB}" + LANGUAGES C ) +#------------------------------------------------------------------------------- # SuiteSparse policies #------------------------------------------------------------------------------- set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules - ${CMAKE_SOURCE_DIR}/../BTF/cmake_modules - ${CMAKE_SOURCE_DIR}/../AMD/cmake_modules - ${CMAKE_SOURCE_DIR}/../COLAMD/cmake_modules - ${CMAKE_SOURCE_DIR}/../CAMD/cmake_modules - ${CMAKE_SOURCE_DIR}/../CCOLAMD/cmake_modules - ${CMAKE_SOURCE_DIR}/../CHOLMOD/cmake_modules - ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) + ${PROJECT_SOURCE_DIR}/../SuiteSparse_config/cmake_modules ) include ( SuiteSparsePolicy ) #------------------------------------------------------------------------------- -# define the project +# find library dependencies #------------------------------------------------------------------------------- -project ( klu - VERSION "${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB}" - LANGUAGES C ) +if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) + find_package ( SuiteSparse_config 7.6.0 + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_package ( SuiteSparse_config 7.6.0 REQUIRED ) + endif ( ) -#------------------------------------------------------------------------------- -# find library dependencies -#------------------------------------------------------------------------------- + find_package ( AMD 3.3.1 + PATHS ${CMAKE_SOURCE_DIR}/../AMD/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::AMD ) + find_package ( AMD 3.3.1 REQUIRED ) + endif ( ) + + find_package ( COLAMD 3.3.2 + PATHS ${CMAKE_SOURCE_DIR}/../COLAMD/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::COLAMD ) + find_package ( COLAMD 3.3.2 REQUIRED ) + endif ( ) -find_package ( SuiteSparse_config 7.0.0 REQUIRED ) -find_package ( BTF 2.0.3 REQUIRED ) -find_package ( COLAMD 3.0.3 REQUIRED ) -find_package ( AMD 3.0.3 REQUIRED ) - -option ( NCHOLMOD "ON: do not use CHOLMOD. OFF (default): use CHOLMOD" off ) - -if ( NOT NCHOLMOD ) - # look for CHOLMOD (optional fill-reducing orderings) - find_package ( CHOLMOD 4.0.3 ) - find_package ( CHOLMOD_CUDA 4.0.3 ) - # look for CHOLMOD's dependencies: AMD and COLAMD are required. CAMD and - # CCOLAMD are optional, but must be found if CHOLMOD was built with them. - find_package ( CAMD 3.0.3 ) - find_package ( CCOLAMD 3.0.3 ) - if ( NOT CHOLMOD_FOUND OR NOT AMD_FOUND OR NOT COLAMD_FOUND ) - # CHOLMOD not found so disable it - set ( NCHOLMOD true ) + find_package ( BTF 2.3.1 + PATHS ${CMAKE_SOURCE_DIR}/../BTF/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::BTF ) + find_package ( BTF 2.3.1 REQUIRED ) endif ( ) endif ( ) -if ( NCHOLMOD ) - # tell KLU that CHOLMOD is not available - message ( STATUS "CHOLMOD not found or not requested" ) - add_compile_definitions ( NCHOLMOD ) +option ( KLU_USE_CHOLMOD "ON (default): use CHOLMOD in KLU. OFF: do not use CHOLMOD in KLU" ON ) + +if ( SUITESPARSE_ROOT_CMAKELISTS ) + # if KLU_USE_CHOLMOD is true, then CHOLMOD has been added to the + # list of packages to compile in the root CMakeLists.txt. + set ( KLU_HAS_CHOLMOD ${KLU_USE_CHOLMOD} ) else ( ) + if ( KLU_USE_CHOLMOD ) + # look for CHOLMOD (optional fill-reducing orderings) + find_package ( CHOLMOD 5.2.0 + PATHS ${CMAKE_SOURCE_DIR}/../CHOLMOD/build NO_DEFAULT_PATH ) + if ( NOT TARGET SuiteSparse::CHOLMOD ) + find_package ( CHOLMOD 5.2.0 ) + endif ( ) + if ( NOT CHOLMOD_FOUND ) + # CHOLMOD not found so disable it + set ( KLU_HAS_CHOLMOD OFF ) + else ( ) + set ( KLU_HAS_CHOLMOD ON ) + endif ( ) + else ( ) + set ( KLU_HAS_CHOLMOD OFF ) + endif ( ) +endif ( ) + +if ( KLU_HAS_CHOLMOD ) message ( STATUS "Using CHOLMOD for addtional pre-ordering options" ) +else ( ) + add_compile_definitions ( NCHOLMOD ) + message ( STATUS "CHOLMOD not found or not requested" ) +endif ( ) + +# check for strict usage +if ( SUITESPARSE_USE_STRICT AND KLU_USE_CHOLMOD AND NOT KLU_HAS_CHOLMOD ) + message ( FATAL_ERROR "CHOLMOD required for KLU but not found" ) endif ( ) #------------------------------------------------------------------------------- @@ -94,8 +120,7 @@ configure_file ( "Config/klu_version.tex.in" # include directories #------------------------------------------------------------------------------- -include_directories ( Source Include User ${SUITESPARSE_CONFIG_INCLUDE_DIR} - ${AMD_INCLUDE_DIR} ${COLAMD_INCLUDE_DIR} ${BTF_INCLUDE_DIR} ) +include_directories ( Source Include User ) #------------------------------------------------------------------------------- # dynamic klu library properties @@ -103,64 +128,103 @@ include_directories ( Source Include User ${SUITESPARSE_CONFIG_INCLUDE_DIR} file ( GLOB KLU_SOURCES "Source/*.c" ) -add_library ( klu SHARED ${KLU_SOURCES} ) +if ( BUILD_SHARED_LIBS ) + add_library ( KLU SHARED ${KLU_SOURCES} ) + + set_target_properties ( KLU PROPERTIES + VERSION ${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + OUTPUT_NAME klu + SOVERSION ${KLU_VERSION_MAJOR} + PUBLIC_HEADER "Include/klu.h" + WINDOWS_EXPORT_ALL_SYMBOLS ON ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( KLU PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) -set_target_properties ( klu PROPERTIES - VERSION ${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB} - C_STANDARD_REQUIRED 11 - SOVERSION ${KLU_VERSION_MAJOR} - PUBLIC_HEADER "Include/klu.h" - WINDOWS_EXPORT_ALL_SYMBOLS ON ) + target_include_directories ( KLU + INTERFACE $ + $ ) +endif ( ) #------------------------------------------------------------------------------- # static klu library properties #------------------------------------------------------------------------------- -if ( NOT NSTATIC ) - add_library ( klu_static STATIC ${KLU_SOURCES} ) +if ( BUILD_STATIC_LIBS ) + add_library ( KLU_static STATIC ${KLU_SOURCES} ) - set_target_properties ( klu_static PROPERTIES - VERSION ${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB} - C_STANDARD_REQUIRED 11 + set_target_properties ( KLU_static PROPERTIES + C_STANDARD 11 + C_STANDARD_REQUIRED ON OUTPUT_NAME klu - SOVERSION ${KLU_VERSION_MAJOR} ) + PUBLIC_HEADER "Include/klu.h" ) if ( MSVC ) - set_target_properties ( klu_static PROPERTIES + set_target_properties ( KLU_static PROPERTIES OUTPUT_NAME klu_static ) endif ( ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( KLU_static PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( KLU_static + INTERFACE $ + $ ) endif ( ) #------------------------------------------------------------------------------- # klu_cholmod library properties #------------------------------------------------------------------------------- -if ( NOT NCHOLMOD ) +if ( KLU_HAS_CHOLMOD ) file ( GLOB KLU_CHOLMOD_SOURCES "User/*.c" ) - add_library ( klu_cholmod SHARED ${KLU_CHOLMOD_SOURCES} ) - include_directories ( ${CHOLMOD_INCLUDE_DIR} ) + if ( BUILD_SHARED_LIBS ) + add_library ( KLU_CHOLMOD SHARED ${KLU_CHOLMOD_SOURCES} ) - set_target_properties ( klu_cholmod PROPERTIES - VERSION ${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB} - C_STANDARD_REQUIRED 11 - SOVERSION ${KLU_VERSION_MAJOR} - PUBLIC_HEADER "User/klu_cholmod.h" ) + set_target_properties ( KLU_CHOLMOD PROPERTIES + VERSION ${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + OUTPUT_NAME klu_cholmod + SOVERSION ${KLU_VERSION_MAJOR} + PUBLIC_HEADER "User/klu_cholmod.h" ) - if ( NOT NSTATIC ) - add_library ( klu_cholmod_static STATIC ${KLU_CHOLMOD_SOURCES} ) + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( KLU_CHOLMOD PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) - set_target_properties ( klu_cholmod_static PROPERTIES - VERSION ${KLU_VERSION_MAJOR}.${KLU_VERSION_MINOR}.${KLU_VERSION_SUB} - C_STANDARD_REQUIRED 11 + target_include_directories ( KLU_CHOLMOD + INTERFACE $ + $ ) + endif ( ) + + if ( BUILD_STATIC_LIBS ) + add_library ( KLU_CHOLMOD_static STATIC ${KLU_CHOLMOD_SOURCES} ) + + set_target_properties ( KLU_CHOLMOD_static PROPERTIES + C_STANDARD 11 + C_STANDARD_REQUIRED ON OUTPUT_NAME klu_cholmod - SOVERSION ${KLU_VERSION_MAJOR} ) + PUBLIC_HEADER "User/klu_cholmod.h" ) if ( MSVC ) - set_target_properties ( klu_cholmod_static PROPERTIES + set_target_properties ( KLU_CHOLMOD_static PROPERTIES OUTPUT_NAME klu_cholmod_static ) endif ( ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( KLU_CHOLMOD_static PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( KLU_CHOLMOD_static + INTERFACE $ + $ ) endif ( ) endif ( ) @@ -169,99 +233,285 @@ endif ( ) # add the library dependencies #------------------------------------------------------------------------------- -# suitesparseconfig: -target_link_libraries ( klu PUBLIC ${SUITESPARSE_CONFIG_LIBRARIES} ) -if ( NOT NSTATIC ) - target_link_libraries ( klu_static PUBLIC ${SUITESPARSE_CONFIG_STATIC} ) +# SuiteSparseConfig: +if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU PRIVATE SuiteSparse::SuiteSparseConfig ) endif ( ) - -# libm: -if ( NOT WIN32 ) - target_link_libraries ( klu PUBLIC m ) - if ( NOT NSTATIC ) - target_link_libraries ( klu_static PUBLIC m ) +if ( BUILD_STATIC_LIBS ) + if ( TARGET SuiteSparse::SuiteSparseConfig_static ) + target_link_libraries ( KLU_static PRIVATE SuiteSparse::SuiteSparseConfig_static ) + else ( ) + target_link_libraries ( KLU_static PRIVATE SuiteSparse::SuiteSparseConfig ) endif ( ) endif ( ) -# amd: -target_link_libraries ( klu PUBLIC ${AMD_LIBRARIES} ) -if ( NOT NSTATIC ) - target_link_libraries ( klu_static PUBLIC ${AMD_STATIC} ) +# AMD: +if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU PRIVATE SuiteSparse::AMD ) + target_include_directories ( KLU PUBLIC + "$" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + if ( TARGET SuiteSparse::AMD_static ) + target_link_libraries ( KLU_static PUBLIC SuiteSparse::AMD_static ) + else ( ) + target_link_libraries ( KLU_static PUBLIC SuiteSparse::AMD ) + endif ( ) endif ( ) -# colamd: -target_link_libraries ( klu PUBLIC ${COLAMD_LIBRARIES} ) -if ( NOT NSTATIC ) - target_link_libraries ( klu_static PUBLIC ${COLAMD_STATIC} ) +# COLAMD: +if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU PRIVATE SuiteSparse::COLAMD ) + target_include_directories ( KLU PUBLIC + "$" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + if ( TARGET SuiteSparse::COLAMD_static ) + target_link_libraries ( KLU_static PUBLIC SuiteSparse::COLAMD_static ) + else ( ) + target_link_libraries ( KLU_static PUBLIC SuiteSparse::COLAMD ) + endif ( ) endif ( ) -# btf: -target_link_libraries ( klu PUBLIC ${BTF_LIBRARIES} ) -if ( NOT NSTATIC ) - target_link_libraries ( klu_static PUBLIC ${BTF_STATIC} ) +# BTF: +if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU PRIVATE SuiteSparse::BTF ) + target_include_directories ( KLU PUBLIC + "$" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + if ( TARGET SuiteSparse::BTF_static ) + target_link_libraries ( KLU_static PUBLIC SuiteSparse::BTF_static ) + else ( ) + target_link_libraries ( KLU_static PUBLIC SuiteSparse::BTF ) + endif ( ) endif ( ) -if ( NOT NCHOLMOD ) +if ( KLU_HAS_CHOLMOD ) - # cholmod: + # CHOLMOD: # link with CHOLMOD and its dependencies, both required and optional - target_link_libraries ( klu PUBLIC - ${CHOLMOD_LIBRARIES} ${CHOLMOD_CUDA_LIBRARIES} - ${AMD_LIBRARIES} ${COLAMD_LIBRARIES} - ${CAMD_LIBRARIES} ${CCOLAMD_LIBRARIES} ) - target_link_libraries ( klu_cholmod PUBLIC - ${CHOLMOD_LIBRARIES} ${CHOLMOD_CUDA_LIBRARIES} - ${AMD_LIBRARIES} ${COLAMD_LIBRARIES} - ${CAMD_LIBRARIES} ${CCOLAMD_LIBRARIES} ) - if ( NOT NSTATIC ) - target_link_libraries ( klu_static PUBLIC - ${CHOLMOD_STATIC} ${CHOLMOD_CUDA_STATIC} - ${AMD_STATIC} ${COLAMD_STATIC} - ${CAMD_STATIC} ${CCOLAMD_STATIC} ) - target_link_libraries ( klu_cholmod_static PUBLIC - ${CHOLMOD_STATIC} ${CHOLMOD_CUDA_STATIC} - ${AMD_STATIC} ${COLAMD_STATIC} - ${CAMD_STATIC} ${CCOLAMD_STATIC} ) + # CHOLMOD without CUDA + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU_CHOLMOD PRIVATE SuiteSparse::CHOLMOD ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + set ( KLU_STATIC_MODULES "${KLU_STATIC_MODULES} CHOLMOD" ) + if ( TARGET SuiteSparse::CHOLMOD_static ) + target_link_libraries ( KLU_CHOLMOD_static PRIVATE SuiteSparse::CHOLMOD_static ) + else ( ) + target_link_libraries ( KLU_CHOLMOD_static PRIVATE SuiteSparse::CHOLMOD ) + endif ( ) endif ( ) # klu: - target_link_libraries ( klu_cholmod PUBLIC klu ${BTF_LIBRARIES} ) - if ( NOT NSTATIC ) - target_link_libraries ( klu_cholmod_static PUBLIC - klu_static ${BTF_STATIC} ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU_CHOLMOD PRIVATE KLU ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + target_link_libraries ( KLU_CHOLMOD_static PRIVATE KLU_static ) + if ( TARGET SuiteSparse::BTF_static ) + target_link_libraries ( KLU_CHOLMOD_static PRIVATE SuiteSparse::BTF_static ) + else ( ) + target_link_libraries ( KLU_CHOLMOD_static PRIVATE SuiteSparse::BTF ) + endif ( ) endif ( ) endif ( ) +# libm: +if ( NOT WIN32 ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( KLU PRIVATE m ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + set ( KLU_STATIC_LIBS "${KLU_STATIC_LIBS} -lm" ) + target_link_libraries ( KLU_static PUBLIC m ) + endif ( ) +endif ( ) + #------------------------------------------------------------------------------- # KLU installation location #------------------------------------------------------------------------------- -install ( TARGETS klu - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} - RUNTIME DESTINATION ${SUITESPARSE_BINDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) -install ( FILES - ${CMAKE_SOURCE_DIR}/cmake_modules/FindKLU.cmake - ${CMAKE_SOURCE_DIR}/cmake_modules/FindKLU_CHOLMOD.cmake - DESTINATION ${SUITESPARSE_LIBDIR}/cmake/SuiteSparse - COMPONENT Development ) - -if ( NOT NSTATIC ) - install ( TARGETS klu_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) -endif ( ) +include ( CMakePackageConfigHelpers ) -if ( NOT NCHOLMOD ) - install ( TARGETS klu_cholmod +if ( BUILD_SHARED_LIBS ) + install ( TARGETS KLU + EXPORT KLUTargets LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} RUNTIME DESTINATION ${SUITESPARSE_BINDIR} PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) - if ( NOT NSTATIC ) - install ( TARGETS klu_cholmod_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) +endif ( ) + +if ( BUILD_STATIC_LIBS ) + install ( TARGETS KLU_static + EXPORT KLUTargets + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) + +# create (temporary) export target file during build +export ( EXPORT KLUTargets + NAMESPACE SuiteSparse:: + FILE ${CMAKE_CURRENT_BINARY_DIR}/KLUTargets.cmake ) + +# install export target, config and version files for find_package +install ( EXPORT KLUTargets + NAMESPACE SuiteSparse:: + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/KLU ) + +# generate config file to be used in common build tree +set ( SUITESPARSE_IN_BUILD_TREE ON ) +configure_package_config_file ( + Config/KLUConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/KLUConfig.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/KLUConfig.cmake ) + +# generate config file to be installed +set ( SUITESPARSE_IN_BUILD_TREE OFF ) +configure_package_config_file ( + Config/KLUConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/target/KLUConfig.cmake + INSTALL_DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/KLU ) + +write_basic_package_version_file ( + ${CMAKE_CURRENT_BINARY_DIR}/KLUConfigVersion.cmake + COMPATIBILITY SameMajorVersion ) + +install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/target/KLUConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/KLUConfigVersion.cmake + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/KLU ) + +#------------------------------------------------------------------------------- +# create pkg-config file for KLU +#------------------------------------------------------------------------------- + +if ( NOT MSVC ) + set ( prefix "${CMAKE_INSTALL_PREFIX}" ) + set ( exec_prefix "\${prefix}" ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_LIBDIR SUITESPARSE_LIBDIR_IS_ABSOLUTE ) + if (SUITESPARSE_LIBDIR_IS_ABSOLUTE) + set ( libdir "${SUITESPARSE_LIBDIR}") + else ( ) + set ( libdir "\${exec_prefix}/${SUITESPARSE_LIBDIR}") + endif ( ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_INCLUDEDIR SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE ) + if (SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE) + set ( includedir "${SUITESPARSE_INCLUDEDIR}") + else ( ) + set ( includedir "\${prefix}/${SUITESPARSE_INCLUDEDIR}") + endif ( ) + if ( BUILD_SHARED_LIBS ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + endif ( ) + configure_file ( + Config/KLU.pc.in + KLU.pc.out + @ONLY + NEWLINE_STYLE LF ) + file ( GENERATE + OUTPUT KLU.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/KLU.pc.out + NEWLINE_STYLE LF ) + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/KLU.pc + DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) +endif ( ) + +#------------------------------------------------------------------------------- +# KLU_CHOLMOD installation +#------------------------------------------------------------------------------- + +if ( KLU_HAS_CHOLMOD ) + if ( BUILD_SHARED_LIBS ) + install ( TARGETS KLU_CHOLMOD + EXPORT KLU_CHOLMODTargets + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + install ( TARGETS KLU_CHOLMOD_static + EXPORT KLU_CHOLMODTargets + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) + endif ( ) + + # create (temporary) export target file during build + export ( EXPORT KLU_CHOLMODTargets + NAMESPACE SuiteSparse:: + FILE ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMODTargets.cmake ) + + # install export target, config and version files for find_package + install ( EXPORT KLU_CHOLMODTargets + NAMESPACE SuiteSparse:: + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/KLU_CHOLMOD ) + + # generate config file to be used in common build tree + set ( SUITESPARSE_IN_BUILD_TREE ON ) + configure_package_config_file ( + Config/KLU_CHOLMODConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMODConfig.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMODConfig.cmake ) + + # generate config file to be installed + set ( SUITESPARSE_IN_BUILD_TREE OFF ) + configure_package_config_file ( + Config/KLU_CHOLMODConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/target/KLU_CHOLMODConfig.cmake + INSTALL_DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/KLU_CHOLMOD ) + + write_basic_package_version_file ( + ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMODConfigVersion.cmake + COMPATIBILITY SameMajorVersion ) + + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMODConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMODConfigVersion.cmake + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/KLU_CHOLMOD ) + + #--------------------------------------------------------------------------- + # create pkg-config file for KLU_CHOLMOD + #--------------------------------------------------------------------------- + + if ( NOT MSVC ) + set ( prefix "${CMAKE_INSTALL_PREFIX}" ) + set ( exec_prefix "\${prefix}" ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_LIBDIR SUITESPARSE_LIBDIR_IS_ABSOLUTE ) + if (SUITESPARSE_LIBDIR_IS_ABSOLUTE) + set ( libdir "${SUITESPARSE_LIBDIR}") + else ( ) + set ( libdir "\${exec_prefix}/${SUITESPARSE_LIBDIR}") + endif ( ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_INCLUDEDIR SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE ) + if (SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE) + set ( includedir "${SUITESPARSE_INCLUDEDIR}") + else ( ) + set ( includedir "\${prefix}/${SUITESPARSE_INCLUDEDIR}") + endif ( ) + if ( BUILD_SHARED_LIBS ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + endif ( ) + configure_file ( + Config/KLU_CHOLMOD.pc.in + KLU_CHOLMOD.pc.out + @ONLY + NEWLINE_STYLE LF ) + file ( GENERATE + OUTPUT KLU_CHOLMOD.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMOD.pc.out + NEWLINE_STYLE LF ) + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/KLU_CHOLMOD.pc + DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) endif ( ) endif ( ) @@ -269,8 +519,7 @@ endif ( ) # Demo library and programs #------------------------------------------------------------------------------- -option ( DEMO "ON: Build the demo programs. OFF (default): do not build the demo programs." off ) -if ( DEMO ) +if ( SUITESPARSE_DEMOS ) #--------------------------------------------------------------------------- # demo library @@ -283,16 +532,29 @@ if ( DEMO ) #--------------------------------------------------------------------------- add_executable ( klu_simple "Demo/klu_simple.c" ) - if ( NOT NCHOLMOD ) + if ( KLU_HAS_CHOLMOD ) add_executable ( kludemo "Demo/kludemo.c" ) add_executable ( kluldemo "Demo/kluldemo.c" ) endif ( ) # Libraries required for Demo programs - target_link_libraries ( klu_simple PUBLIC klu ) - if ( NOT NCHOLMOD ) - target_link_libraries ( kludemo PUBLIC klu_cholmod ) - target_link_libraries ( kluldemo PUBLIC klu_cholmod ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( klu_simple PUBLIC KLU ) + else ( ) + target_link_libraries ( klu_simple PUBLIC KLU_static ) + endif ( ) + if ( KLU_HAS_CHOLMOD ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( kludemo PUBLIC KLU_CHOLMOD KLU SuiteSparse::CHOLMOD ) + target_link_libraries ( kluldemo PUBLIC KLU_CHOLMOD KLU SuiteSparse::CHOLMOD ) + else ( ) + target_link_libraries ( kludemo PUBLIC KLU_CHOLMOD_static KLU_static SuiteSparse::CHOLMOD ) + target_link_libraries ( kluldemo PUBLIC KLU_CHOLMOD_static KLU_static SuiteSparse::CHOLMOD ) + endif ( ) + if ( NOT WIN32 ) + target_link_libraries ( kludemo PUBLIC m ) + target_link_libraries ( kluldemo PUBLIC m ) + endif ( ) endif ( ) else ( ) @@ -306,4 +568,3 @@ endif ( ) #------------------------------------------------------------------------------- include ( SuiteSparseReport ) - diff --git a/ThirdParty/SuiteSparse/KLU/Config/KLU.pc.in b/ThirdParty/SuiteSparse/KLU/Config/KLU.pc.in new file mode 100644 index 0000000000..df7191b118 --- /dev/null +++ b/ThirdParty/SuiteSparse/KLU/Config/KLU.pc.in @@ -0,0 +1,17 @@ +# KLU, Copyright (c) 2004-2024, Timothy A. Davis. +# All Rights Reserved. +# SPDX-License-Identifier: LGPL-2.1-or-later + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: KLU +URL: https://github.com/DrTimothyAldenDavis/SuiteSparse +Description: Routines for solving sparse linear systems of equations in SuiteSparse +Version: @KLU_VERSION_MAJOR@.@KLU_VERSION_MINOR@.@KLU_VERSION_SUB@ +Requires.private: SuiteSparse_config AMD COLAMD BTF @KLU_STATIC_MODULES@ +Libs: -L${libdir} -l@SUITESPARSE_LIB_BASE_NAME@ +Libs.private: @KLU_STATIC_LIBS@ +Cflags: -I${includedir} diff --git a/ThirdParty/SuiteSparse/KLU/Config/KLUConfig.cmake.in b/ThirdParty/SuiteSparse/KLU/Config/KLUConfig.cmake.in new file mode 100644 index 0000000000..f28e22ba73 --- /dev/null +++ b/ThirdParty/SuiteSparse/KLU/Config/KLUConfig.cmake.in @@ -0,0 +1,193 @@ +#------------------------------------------------------------------------------- +# SuiteSparse/KLU/cmake_modules/KLUConfig.cmake +#------------------------------------------------------------------------------- + +# The following copyright and license applies to just this file only, not to +# the library itself: +# KLUConfig.cmake, Copyright (c) 2023-2024, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: BSD-3-clause + +#------------------------------------------------------------------------------- + +# Finds the KLU include file and compiled library. +# The following targets are defined: +# SuiteSparse::KLU - for the shared library (if available) +# SuiteSparse::KLU_static - for the static library (if available) + +# For backward compatibility the following variables are set: + +# KLU_INCLUDE_DIR - where to find klu.h +# KLU_LIBRARY - dynamic KLU library +# KLU_STATIC - static KLU library +# KLU_LIBRARIES - libraries when using KLU +# KLU_FOUND - true if KLU found + +# Set ``CMAKE_MODULE_PATH`` to the parent folder where this module file is +# installed. + +#------------------------------------------------------------------------------- + +@PACKAGE_INIT@ + +set ( KLU_DATE "@KLU_DATE@" ) +set ( KLU_VERSION_MAJOR @KLU_VERSION_MAJOR@ ) +set ( KLU_VERSION_MINOR @KLU_VERSION_MINOR@ ) +set ( KLU_VERSION_PATCH @KLU_VERSION_SUB@ ) +set ( KLU_VERSION "@KLU_VERSION_MAJOR@.@KLU_VERSION_MINOR@.@KLU_VERSION_SUB@" ) + +# Check for dependent targets +include ( CMakeFindDependencyMacro ) + +# Look for SuiteSparse_config, BTF, AMD and COLAMD targets +if ( @SUITESPARSE_IN_BUILD_TREE@ ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + # First check in a common build tree + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT SuiteSparse_config_FOUND ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) + endif ( ) + + if ( NOT TARGET SuiteSparse::BTF ) + # First check in a common build tree + find_dependency ( BTF @BTF_VERSION_MAJOR@.@BTF_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../BTF/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT BTF_FOUND ) + find_dependency ( BTF @BTF_VERSION_MAJOR@.@BTF_VERSION_MINOR@ ) + endif ( ) + endif ( ) + + if ( NOT TARGET SuiteSparse::AMD ) + # First check in a common build tree + find_dependency ( AMD @AMD_VERSION_MAJOR@.@AMD_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../AMD/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT AMD_FOUND ) + find_dependency ( AMD @AMD_VERSION_MAJOR@.@AMD_VERSION_MINOR@ ) + endif ( ) + endif ( ) + + if ( NOT TARGET SuiteSparse::COLAMD ) + # First check in a common build tree + find_dependency ( COLAMD @COLAMD_VERSION_MAJOR@.@COLAMD_VERSION_MINOR@ + PATHS ${CMAKE_SOURCE_DIR}/../COLAMD/build NO_DEFAULT_PATH ) + # Then, check in the currently active CMAKE_MODULE_PATH + if ( NOT COLAMD_FOUND ) + find_dependency ( COLAMD @COLAMD_VERSION_MAJOR@.@COLAMD_VERSION_MINOR@ ) + endif ( ) + endif ( ) + +else ( ) + if ( NOT TARGET SuiteSparse::SuiteSparseConfig ) + find_dependency ( SuiteSparse_config @SUITESPARSE_CONFIG_VERSION_MAJOR@.@SUITESPARSE_CONFIG_VERSION_MINOR@ ) + endif ( ) + if ( NOT TARGET SuiteSparse::BTF ) + find_dependency ( BTF @BTF_VERSION_MAJOR@.@BTF_VERSION_MINOR@ ) + endif ( ) + if ( NOT TARGET SuiteSparse::AMD ) + find_dependency ( AMD @AMD_VERSION_MAJOR@.@AMD_VERSION_MINOR@ ) + endif ( ) + if ( NOT TARGET SuiteSparse::COLAMD ) + find_dependency ( COLAMD @COLAMD_VERSION_MAJOR@.@COLAMD_VERSION_MINOR@ ) + endif ( ) +endif ( ) + +if ( NOT SuiteSparse_config_FOUND OR NOT BTF_FOUND OR NOT AMD_FOUND OR NOT COLAMD_FOUND ) + set ( KLU_FOUND OFF ) + return ( ) +endif ( ) + + +# Import target +include ( ${CMAKE_CURRENT_LIST_DIR}/KLUTargets.cmake ) + +# The following is only for backward compatibility with FindKLU. + +set ( _target_shared SuiteSparse::KLU ) +set ( _target_static SuiteSparse::KLU_static ) +set ( _var_prefix "KLU" ) + +if ( NOT @BUILD_SHARED_LIBS@ AND NOT TARGET ${_target_shared} ) + # make sure there is always an import target without suffix ) + add_library ( ${_target_shared} ALIAS ${_target_static} ) +endif ( ) + +get_target_property ( ${_var_prefix}_INCLUDE_DIR ${_target_shared} INTERFACE_INCLUDE_DIRECTORIES ) +if ( ${_var_prefix}_INCLUDE_DIR ) + # First item in SuiteSparse targets contains the "main" header directory. + list ( GET ${_var_prefix}_INCLUDE_DIR 0 ${_var_prefix}_INCLUDE_DIR ) +endif ( ) +get_target_property ( ${_var_prefix}_LIBRARY ${_target_shared} IMPORTED_IMPLIB ) +if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} IMPORTED_LOCATION ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) +endif ( ) +if ( TARGET ${_target_static} ) + get_target_property ( ${_var_prefix}_STATIC ${_target_static} IMPORTED_LOCATION ) +endif ( ) + +# Check for most common build types +set ( _config_types "Debug" "Release" "RelWithDebInfo" "MinSizeRel" "None" ) + +get_property ( _isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) +if ( _isMultiConfig ) + # For multi-configuration generators (e.g., Visual Studio), prefer those + # configurations. + list ( PREPEND _config_types ${CMAKE_CONFIGURATION_TYPES} ) +else ( ) + # For single-configuration generators, prefer the current configuration. + list ( PREPEND _config_types ${CMAKE_BUILD_TYPE} ) +endif ( ) + +list ( REMOVE_DUPLICATES _config_types ) + +foreach ( _config ${_config_types} ) + string ( TOUPPER ${_config} _uc_config ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_IMPLIB_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( TARGET ${_target_static} AND NOT ${_var_prefix}_STATIC ) + get_target_property ( _library_chk ${_target_static} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_STATIC ${_library_chk} ) + endif ( ) + endif ( ) +endforeach ( ) + +set ( KLU_LIBRARIES ${KLU_LIBRARY} ) + +macro ( suitesparse_check_exist _var _files ) + # ignore generator expressions + string ( GENEX_STRIP "${_files}" _files2 ) + + foreach ( _file ${_files2} ) + if ( NOT EXISTS "${_file}" ) + message ( FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist!" ) + endif ( ) + endforeach () +endmacro ( ) + +suitesparse_check_exist ( KLU_INCLUDE_DIR ${KLU_INCLUDE_DIR} ) +suitesparse_check_exist ( KLU_LIBRARY ${KLU_LIBRARY} ) + +message ( STATUS "KLU version: ${KLU_VERSION}" ) +message ( STATUS "KLU include: ${KLU_INCLUDE_DIR}" ) +message ( STATUS "KLU library: ${KLU_LIBRARY}" ) +message ( STATUS "KLU static: ${KLU_STATIC}" ) diff --git a/ThirdParty/SuiteSparse/KLU/Config/klu.h.in b/ThirdParty/SuiteSparse/KLU/Config/klu.h.in index 769a82aa6f..1f02c4be5f 100644 --- a/ThirdParty/SuiteSparse/KLU/Config/klu.h.in +++ b/ThirdParty/SuiteSparse/KLU/Config/klu.h.in @@ -2,7 +2,7 @@ // KLU/Source/klu.h: include file for KLU //------------------------------------------------------------------------------ -// KLU, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// KLU, Copyright (c) 2004-2024, University of Florida. All Rights Reserved. // Authors: Timothy A. Davis and Ekanathan Palamadai. // SPDX-License-Identifier: LGPL-2.1+ @@ -13,15 +13,15 @@ #ifndef _KLU_H #define _KLU_H +#include "amd.h" +#include "colamd.h" +#include "btf.h" + /* make it easy for C++ programs to include KLU */ #ifdef __cplusplus extern "C" { #endif -#include "amd.h" -#include "colamd.h" -#include "btf.h" - /* -------------------------------------------------------------------------- */ /* Symbolic object - contains the pre-ordering computed by klu_analyze */ /* -------------------------------------------------------------------------- */ @@ -795,6 +795,15 @@ void *klu_l_free (void *, size_t, size_t, klu_l_common *) ; void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; +//------------------------------------------------------------------------------ +// klu_version: return KLU version +//------------------------------------------------------------------------------ + +void klu_version (int version [3]) ; + +#ifdef __cplusplus +} +#endif /* ========================================================================== */ /* === KLU version ========================================================== */ @@ -819,10 +828,29 @@ void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; #define KLU_SUB_VERSION @KLU_VERSION_MINOR@ #define KLU_SUBSUB_VERSION @KLU_VERSION_SUB@ -#define KLU_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define KLU_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION) +#define KLU_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define KLU_VERSION KLU_VERSION_CODE(@KLU_VERSION_MAJOR@,@KLU_VERSION_MINOR@) -#ifdef __cplusplus -} +#define KLU__VERSION SUITESPARSE__VERCODE(@KLU_VERSION_MAJOR@,@KLU_VERSION_MINOR@,@KLU_VERSION_SUB@) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,6,0)) +#error "KLU @KLU_VERSION_MAJOR@.@KLU_VERSION_MINOR@.@KLU_VERSION_SUB@ requires SuiteSparse_config 7.6.0 or later" +#endif + +#if !defined (AMD__VERSION) || \ + (AMD__VERSION < SUITESPARSE__VERCODE(3,3,1)) +#error "KLU @KLU_VERSION_MAJOR@.@KLU_VERSION_MINOR@.@KLU_VERSION_SUB@ requires AMD 3.3.1 or later" #endif + +#if !defined (COLAMD__VERSION) || \ + (COLAMD__VERSION < SUITESPARSE__VERCODE(3,3,2)) +#error "KLU @KLU_VERSION_MAJOR@.@KLU_VERSION_MINOR@.@KLU_VERSION_SUB@ requires COLAMD 3.3.2 or later" +#endif + +#if !defined (BTF__VERSION) || \ + (BTF__VERSION < SUITESPARSE__VERCODE(2,3,1)) +#error "KLU @KLU_VERSION_MAJOR@.@KLU_VERSION_MINOR@.@KLU_VERSION_SUB@ requires BTF 2.3.1 or later" #endif + +#endif + diff --git a/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog b/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog index b4a4edabeb..d4313dbc55 100644 --- a/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog +++ b/ThirdParty/SuiteSparse/KLU/Doc/ChangeLog @@ -1,3 +1,33 @@ +Jan 20, 2024: version 2.3.2 + + * revise version numbers for dependencies + +Jan 10, 2024: version 2.3.1 + + * MATLAB interface: add -DNO_SSIZE_T for Windows + * minor updates to build system + +Dec 30, 2023: version 2.3.0 + + * major change to build system: by Markus Mützel + * klu_version: added to return version of KLU + +Oct 23, 2023: version 2.2.2 + + * for SuiteSparse 7.3.0: update for CHOLMOD 5.0.0 + +Sept 18, 2023: version 2.2.1 + + * cmake update: add "None" build type, from Antonio Rojas, for Arch Linux + +Sept 8, 2023: version 2.2.0 + + * cmake updates: SuiteSparse:: namespace by Markus Muetzel + +June 16, 2023: version 2.0.4 + + * cmake build system updates: update by Markus Muetzel + Jan 17, 2023: version 2.0.3 * SuiteSparse_config: now v7.0.0 diff --git a/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex b/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex index 8ed9466291..e710ff3887 100644 --- a/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex +++ b/ThirdParty/SuiteSparse/KLU/Doc/KLU_UserGuide.tex @@ -51,7 +51,7 @@ \section{License and Copyright} %------------------------------------------------------------------------------ -KLU, Copyright\copyright 2004-2022 University of Florida. +KLU, Copyright\copyright 2004-2023 University of Florida. All Rights Reserved. KLU is available under alternate licenses; contact T. Davis for details. diff --git a/ThirdParty/SuiteSparse/KLU/Doc/klu_version.tex b/ThirdParty/SuiteSparse/KLU/Doc/klu_version.tex index f15e030533..5e71c34bcb 100644 --- a/ThirdParty/SuiteSparse/KLU/Doc/klu_version.tex +++ b/ThirdParty/SuiteSparse/KLU/Doc/klu_version.tex @@ -1,2 +1,2 @@ % version of SuiteSparse/KLU -\date{VERSION 2.0.3, Jan 17, 2023} +\date{VERSION 2.3.2, Jan 20, 2024} diff --git a/ThirdParty/SuiteSparse/KLU/Include/klu.h b/ThirdParty/SuiteSparse/KLU/Include/klu.h index 80204ecf75..22155ff8b5 100644 --- a/ThirdParty/SuiteSparse/KLU/Include/klu.h +++ b/ThirdParty/SuiteSparse/KLU/Include/klu.h @@ -2,7 +2,7 @@ // KLU/Source/klu.h: include file for KLU //------------------------------------------------------------------------------ -// KLU, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// KLU, Copyright (c) 2004-2024, University of Florida. All Rights Reserved. // Authors: Timothy A. Davis and Ekanathan Palamadai. // SPDX-License-Identifier: LGPL-2.1+ @@ -13,15 +13,15 @@ #ifndef _KLU_H #define _KLU_H +#include "amd.h" +#include "colamd.h" +#include "btf.h" + /* make it easy for C++ programs to include KLU */ #ifdef __cplusplus extern "C" { #endif -#include "amd.h" -#include "colamd.h" -#include "btf.h" - /* -------------------------------------------------------------------------- */ /* Symbolic object - contains the pre-ordering computed by klu_analyze */ /* -------------------------------------------------------------------------- */ @@ -795,6 +795,15 @@ void *klu_l_free (void *, size_t, size_t, klu_l_common *) ; void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; +//------------------------------------------------------------------------------ +// klu_version: return KLU version +//------------------------------------------------------------------------------ + +void klu_version (int version [3]) ; + +#ifdef __cplusplus +} +#endif /* ========================================================================== */ /* === KLU version ========================================================== */ @@ -814,15 +823,34 @@ void *klu_l_realloc (size_t, size_t, size_t, void *, klu_l_common *) ; * #endif */ -#define KLU_DATE "Jan 17, 2023" +#define KLU_DATE "Jan 20, 2024" #define KLU_MAIN_VERSION 2 -#define KLU_SUB_VERSION 0 -#define KLU_SUBSUB_VERSION 3 +#define KLU_SUB_VERSION 3 +#define KLU_SUBSUB_VERSION 2 -#define KLU_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define KLU_VERSION KLU_VERSION_CODE(KLU_MAIN_VERSION,KLU_SUB_VERSION) +#define KLU_VERSION_CODE(main,sub) SUITESPARSE_VER_CODE(main,sub) +#define KLU_VERSION KLU_VERSION_CODE(2,3) -#ifdef __cplusplus -} +#define KLU__VERSION SUITESPARSE__VERCODE(2,3,2) +#if !defined (SUITESPARSE__VERSION) || \ + (SUITESPARSE__VERSION < SUITESPARSE__VERCODE(7,6,0)) +#error "KLU 2.3.2 requires SuiteSparse_config 7.6.0 or later" +#endif + +#if !defined (AMD__VERSION) || \ + (AMD__VERSION < SUITESPARSE__VERCODE(3,3,1)) +#error "KLU 2.3.2 requires AMD 3.3.1 or later" #endif + +#if !defined (COLAMD__VERSION) || \ + (COLAMD__VERSION < SUITESPARSE__VERCODE(3,3,2)) +#error "KLU 2.3.2 requires COLAMD 3.3.2 or later" +#endif + +#if !defined (BTF__VERSION) || \ + (BTF__VERSION < SUITESPARSE__VERCODE(2,3,1)) +#error "KLU 2.3.2 requires BTF 2.3.1 or later" #endif + +#endif + diff --git a/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h b/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h index 60fa514a3a..b30f937759 100644 --- a/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h +++ b/ThirdParty/SuiteSparse/KLU/Include/klu_internal.h @@ -2,7 +2,7 @@ // KLU/Include/klu_internal.h: internal include file for KLU //------------------------------------------------------------------------------ -// KLU, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// KLU, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. // Authors: Timothy A. Davis and Ekanathan Palamadai. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/ThirdParty/SuiteSparse/KLU/Include/klu_version.h b/ThirdParty/SuiteSparse/KLU/Include/klu_version.h index f2d4915c97..0e0951d112 100644 --- a/ThirdParty/SuiteSparse/KLU/Include/klu_version.h +++ b/ThirdParty/SuiteSparse/KLU/Include/klu_version.h @@ -2,7 +2,7 @@ // KLU/Include/klu_version.h: internal include file for KLU //------------------------------------------------------------------------------ -// KLU, Copyright (c) 2004-2022, University of Florida. All Rights Reserved. +// KLU, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. // Authors: Timothy A. Davis and Ekanathan Palamadai. // SPDX-License-Identifier: LGPL-2.1+ diff --git a/ThirdParty/SuiteSparse/KLU/Makefile b/ThirdParty/SuiteSparse/KLU/Makefile index 896ea4a1b6..97bb49f4e8 100644 --- a/ThirdParty/SuiteSparse/KLU/Makefile +++ b/ThirdParty/SuiteSparse/KLU/Makefile @@ -36,23 +36,23 @@ default: library # default is to install only in /usr/local library: - ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . --config Release -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=1 .. && cmake --build . --config Release -j${JOBS} ) # install only in /usr/local (default) global: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=0 .. && cmake --build . --config Release -j${JOBS} ) debug: - ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . --config Debug -j${JOBS} ) all: library demos: library - ( cd build && cmake $(CMAKE_OPTIONS) -DDEMO=1 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -DSUITESPARSE_DEMOS=1 .. && cmake --build . --config Release -j${JOBS} ) - ./build/klu_simple - ./build/kludemo < ./Matrix/1c.mtx - ./build/kludemo < ./Matrix/arrowc.mtx diff --git a/ThirdParty/SuiteSparse/KLU/Source/klu_version.c b/ThirdParty/SuiteSparse/KLU/Source/klu_version.c new file mode 100644 index 0000000000..e96215f580 --- /dev/null +++ b/ThirdParty/SuiteSparse/KLU/Source/klu_version.c @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// KLU/Source/klu_version: return KLU version +//------------------------------------------------------------------------------ + +// KLU, Copyright (c) 2004-2023, University of Florida. All Rights Reserved. +// Authors: Timothy A. Davis and Ekanathan Palamadai. +// SPDX-License-Identifier: LGPL-2.1+ + +//------------------------------------------------------------------------------ + +#include "klu_internal.h" + +void klu_version (int version [3]) +{ + version [0] = KLU_MAIN_VERSION ; + version [1] = KLU_SUB_VERSION ; + version [2] = KLU_SUBSUB_VERSION ; +} + diff --git a/ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU.cmake b/ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU.cmake deleted file mode 100644 index cd3f4040e4..0000000000 --- a/ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU.cmake +++ /dev/null @@ -1,129 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/KLU/cmake_modules/FindKLU.cmake -#------------------------------------------------------------------------------- - -# The following copyright and license applies to just this file only, not to -# the library itself: -# FindKLU.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# Finds the KLU include file and compiled library and sets: - -# KLU_INCLUDE_DIR - where to find klu.h -# KLU_LIBRARY - dynamic KLU library -# KLU_STATIC - static KLU library -# KLU_LIBRARIES - libraries when using KLU -# KLU_FOUND - true if KLU found - -# set ``KLU_ROOT`` to a KLU installation root to -# tell this module where to look. - -# All the Find*.cmake files in SuiteSparse are installed by 'make install' into -# /usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the -# ${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands -# in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: -# -# set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} -# ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) - -#------------------------------------------------------------------------------- - -# include files for KLU -find_path ( KLU_INCLUDE_DIR - NAMES klu.h - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU - HINTS ${CMAKE_SOURCE_DIR}/../KLU - PATH_SUFFIXES include Include -) - -# dynamic KLU library (or static if no dynamic library was built) -find_library ( KLU_LIBRARY - NAMES klu klu_static - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU - HINTS ${CMAKE_SOURCE_DIR}/../KLU - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( MSVC ) - set ( STATIC_NAME klu_static ) -else ( ) - set ( STATIC_NAME klu ) - set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) -endif ( ) - -# static KLU library -find_library ( KLU_STATIC - NAMES ${STATIC_NAME} - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU - HINTS ${CMAKE_SOURCE_DIR}/../KLU - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) -endif ( ) - -# get version of the library from the dynamic library name -get_filename_component ( KLU_LIBRARY ${KLU_LIBRARY} REALPATH ) -get_filename_component ( KLU_FILENAME ${KLU_LIBRARY} NAME ) -string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - KLU_VERSION - ${KLU_FILENAME} -) - -# set ( KLU_VERSION "" ) -if ( EXISTS "${KLU_INCLUDE_DIR}" AND NOT KLU_VERSION ) - # if the version does not appear in the filename, read the include file - file ( STRINGS ${KLU_INCLUDE_DIR}/klu.h KLU_MAJOR_STR - REGEX "define KLU_MAIN_VERSION" ) - file ( STRINGS ${KLU_INCLUDE_DIR}/klu.h KLU_MINOR_STR - REGEX "define KLU_SUB_VERSION" ) - file ( STRINGS ${KLU_INCLUDE_DIR}/klu.h KLU_PATCH_STR - REGEX "define KLU_SUBSUB_VERSION" ) - message ( STATUS "major: ${KLU_MAJOR_STR}" ) - message ( STATUS "minor: ${KLU_MINOR_STR}" ) - message ( STATUS "patch: ${KLU_PATCH_STR}" ) - string ( REGEX MATCH "[0-9]+" KLU_MAJOR ${KLU_MAJOR_STR} ) - string ( REGEX MATCH "[0-9]+" KLU_MINOR ${KLU_MINOR_STR} ) - string ( REGEX MATCH "[0-9]+" KLU_PATCH ${KLU_PATCH_STR} ) - set (KLU_VERSION "${KLU_MAJOR}.${KLU_MINOR}.${KLU_PATCH}") -endif ( ) - -set ( KLU_LIBRARIES ${KLU_LIBRARY} ) - -include (FindPackageHandleStandardArgs) - -find_package_handle_standard_args ( KLU - REQUIRED_VARS KLU_LIBRARY KLU_INCLUDE_DIR - VERSION_VAR KLU_VERSION - ) - -mark_as_advanced ( - KLU_INCLUDE_DIR - KLU_LIBRARY - KLU_STATIC - KLU_LIBRARIES - ) - -if ( KLU_FOUND ) - message ( STATUS "KLU version: ${KLU_VERSION}" ) - message ( STATUS "KLU include: ${KLU_INCLUDE_DIR}" ) - message ( STATUS "KLU library: ${KLU_LIBRARY}" ) - message ( STATUS "KLU static: ${KLU_STATIC}" ) -else ( ) - message ( STATUS "KLU not found" ) - set ( KLU_INCLUDE_DIR "" ) - set ( KLU_LIBRARIES "" ) - set ( KLU_LIBRARY "" ) - set ( KLU_STATIC "" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU_CHOLMOD.cmake b/ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU_CHOLMOD.cmake deleted file mode 100644 index d3b3663228..0000000000 --- a/ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU_CHOLMOD.cmake +++ /dev/null @@ -1,137 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/KLU/cmake_modules/FindKLU_CHOLMOD.cmake -#------------------------------------------------------------------------------- - -# The following copyright and license applies to just this file only, not to -# the library itself: -# FindKLU_CHOLMOD.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# Finds the KLU_CHOLMOD include file and compiled library and sets: - -# KLU_CHOLMOD_INCLUDE_DIR - where to find klu_cholmod.h -# KLU_CHOLMOD_LIBRARY - compiled KLU_CHOLMOD library -# KLU_CHOLMOD_LIBRARIES - libraries when using KLU_CHOLMOD -# KLU_CHOLMOD_FOUND - true if KLU_CHOLMOD found - -# set ``KLU_CHOLMOD_ROOT`` to a KLU_CHOLMOD installation root to -# tell this module where to look. - -# All the Find*.cmake files in SuiteSparse are installed by 'make install' into -# /usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the -# ${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands -# in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: -# -# set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} -# ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) - -#------------------------------------------------------------------------------- - -# include files for KLU_CHOLMOD -find_path ( KLU_CHOLMOD_INCLUDE_DIR - NAMES klu_cholmod.h - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU/User - HINTS ${CMAKE_SOURCE_DIR}/../KLU/User - PATH_SUFFIXES include Include -) - -# include files for KLU -find_path ( KLU_INCLUDE_DIR - NAMES klu.h - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU - HINTS ${CMAKE_SOURCE_DIR}/../KLU - PATH_SUFFIXES include Include -) - -# dynamic KLU_CHOLMOD library (or static if no dynamic library was built) -find_library ( KLU_CHOLMOD_LIBRARY - NAMES klu_cholmod klu_cholmod_static - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU/User - HINTS ${CMAKE_SOURCE_DIR}/../KLU/User - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( MSVC ) - set ( STATIC_NAME klu_cholmod_static ) -else ( ) - set ( STATIC_NAME klu_cholmod ) - set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) -endif ( ) - -# static KLU_CHOLMOD library -find_library ( KLU_CHOLMOD_STATIC - NAMES ${STATIC_NAME} - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/KLU/User - HINTS ${CMAKE_SOURCE_DIR}/../KLU/User - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) -endif ( ) - -# get version of the library from the dynamic library name -get_filename_component ( KLU_CHOLMOD_LIBRARY ${KLU_CHOLMOD_LIBRARY} REALPATH ) -get_filename_component ( KLU_CHOLMOD_FILENAME ${KLU_CHOLMOD_LIBRARY} NAME ) -string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - KLU_CHOLMOD_VERSION - ${KLU_CHOLMOD_FILENAME} -) - -# set ( KLU_CHOLMOD_VERSION "" ) -if ( EXISTS "${KLU_INCLUDE_DIR}" AND NOT KLU_CHOLMOD_VERSION ) - # if the version does not appear in the filename, read the include file - file ( STRINGS ${KLU_INCLUDE_DIR}/klu.h KLU_CHOLMOD_MAJOR_STR - REGEX "define KLU_MAIN_VERSION" ) - file ( STRINGS ${KLU_INCLUDE_DIR}/klu.h KLU_CHOLMOD_MINOR_STR - REGEX "define KLU_SUB_VERSION" ) - file ( STRINGS ${KLU_INCLUDE_DIR}/klu.h KLU_CHOLMOD_PATCH_STR - REGEX "define KLU_SUBSUB_VERSION" ) - message ( STATUS "major: ${KLU_CHOLMOD_MAJOR_STR}" ) - message ( STATUS "minor: ${KLU_CHOLMOD_MINOR_STR}" ) - message ( STATUS "patch: ${KLU_CHOLMOD_PATCH_STR}" ) - string ( REGEX MATCH "[0-9]+" KLU_CHOLMOD_MAJOR ${KLU_CHOLMOD_MAJOR_STR} ) - string ( REGEX MATCH "[0-9]+" KLU_CHOLMOD_MINOR ${KLU_CHOLMOD_MINOR_STR} ) - string ( REGEX MATCH "[0-9]+" KLU_CHOLMOD_PATCH ${KLU_CHOLMOD_PATCH_STR} ) - set (KLU_CHOLMOD_VERSION "${KLU_CHOLMOD_MAJOR}.${KLU_CHOLMOD_MINOR}.${KLU_CHOLMOD_PATCH}") -endif ( ) - -set ( KLU_CHOLMOD_LIBRARIES ${KLU_CHOLMOD_LIBRARY} ) - -include (FindPackageHandleStandardArgs) - -find_package_handle_standard_args ( KLU_CHOLMOD - REQUIRED_VARS KLU_CHOLMOD_LIBRARY KLU_CHOLMOD_INCLUDE_DIR - VERSION_VAR KLU_CHOLMOD_VERSION -) - -mark_as_advanced ( - KLU_CHOLMOD_INCLUDE_DIR - KLU_CHOLMOD_LIBRARY - KLU_CHOLMOD_STATIC - KLU_CHOLMOD_LIBRARIES -) - -if ( KLU_CHOLMOD_FOUND ) - message ( STATUS "KLU_CHOLMOD version: ${KLU_CHOLMOD_VERSION}" ) - message ( STATUS "KLU_CHOLMOD include: ${KLU_CHOLMOD_INCLUDE_DIR}" ) - message ( STATUS "KLU_CHOLMOD library: ${KLU_CHOLMOD_LIBRARY}" ) - message ( STATUS "KLU_CHOLMOD static: ${KLU_CHOLMOD_STATIC}" ) -else ( ) - message ( STATUS "KLU_CHOLMOD not found" ) - set ( KLU_CHOLMOD_INCLUDE_DIR "" ) - set ( KLU_CHOLMOD_LIBRARIES "" ) - set ( KLU_CHOLMOD_LIBRARY "" ) - set ( KLU_CHOLMOD_STATIC "" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/LICENSE.txt b/ThirdParty/SuiteSparse/LICENSE.txt index 0e51e9e0c8..8c6d47346c 100644 --- a/ThirdParty/SuiteSparse/LICENSE.txt +++ b/ThirdParty/SuiteSparse/LICENSE.txt @@ -6,7 +6,7 @@ found in the lists below. SPEX: a Sparse Left-looking Integer-Preserving LU Factorization - Copyright (c) 2019-2022, Christopher Lourenco, JinHao Chen, Erick Moreno- + Copyright (c) 2019-2023, Christopher Lourenco, JinHao Chen, Erick Moreno- Centeno, and Timothy A. Davis. Available at: @@ -46,7 +46,7 @@ found in the lists below. ==> AMD/Doc/License.txt <== - AMD, Copyright (c), 1996-2022, Timothy A. Davis, + AMD, Copyright (c), 1996-2023, Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. Availability: @@ -82,7 +82,7 @@ found in the lists below. DAMAGE. ==> BTF/Doc/License.txt <== - BTF, Copyright (C) 2004-2022, University of Florida + BTF, Copyright (C) 2004-2023, University of Florida by Timothy A. Davis and Ekanathan Palamadai. BTF is also available under other licenses; contact authors for details. http://suitesparse.com @@ -143,7 +143,7 @@ found in the lists below. ==> CCOLAMD/Doc/License.txt <== CCOLAMD: constrained column approximate minimum degree ordering - Copyright (C) 2005-2022, Univ. of Florida. Authors: Timothy A. Davis, + Copyright (C) 2005-2023, Univ. of Florida. Authors: Timothy A. Davis, Sivasankaran Rajamanickam, and Stefan Larimore. Closely based on COLAMD by Davis, Stefan Larimore, in collaboration with Esmond Ng, and John Gilbert. http://suitesparse.com @@ -183,7 +183,7 @@ found in the lists below. ==> Check/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Check Module. Copyright (C) 2005-2022, Timothy A. Davis CHOLMOD is + CHOLMOD/Check Module. Copyright (C) 2005-2023, Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -210,7 +210,7 @@ found in the lists below. ==> Cholesky/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Cholesky module, Copyright (C) 2005-2022, Timothy A. Davis. + CHOLMOD/Cholesky module, Copyright (C) 2005-2023, Timothy A. Davis. CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -235,14 +235,14 @@ found in the lists below. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -------------------------------------------------------------------------------- - ==> Core/License.txt <== + ==> Utility/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Core Module. Copyright (C) 2005-2022, Univ. of Florida. Author: - Timothy A. Davis. CHOLMOD is also available under other licenses; contact - authors for details. http://suitesparse.com + CHOLMOD/Utility Module, Copyright (C) 2023, Timothy A. Davis. + CHOLMOD is also available under other licenses; contact authors for + details. http://suitesparse.com - Note that this license is for the CHOLMOD/Core module only. + Note that this license is for the CHOLMOD/Utility module only. All CHOLMOD modules are licensed separately. @@ -267,7 +267,7 @@ found in the lists below. ==> Demo/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Demo Module. Copyright (C) 2005-2022, Timothy A. Davis. CHOLMOD + CHOLMOD/Demo Module. Copyright (C) 2005-2023, Timothy A. Davis. CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -296,35 +296,18 @@ found in the lists below. ==> Include/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Include/* files. Copyright (C) 2005-2022, either Univ. of Florida - or T. Davis, depending on the file. - - Each file is licensed separately, according to the Module for which it - contains definitions and prototypes: - - Include/cholmod.h LGPL - Include/cholmod_camd.h part of Partition module - Include/cholmod_check.h part of Check module - Include/cholmod_cholesky.h part of Cholesky module - Include/cholmod_complexity.h LGPL - Include/cholmod_config.h LGPL - Include/cholmod_core.h part of Core module - Include/cholmod_function.h no license; freely usable, no restrictions - Include/cholmod_gpu.h part of GPU module - Include/cholmod_gpu_kernels.h part of GPU module - Include/cholmod_internal.h LGPL - Include/cholmod_io64.h LGPL - Include/cholmod_matrixops.h part of MatrixOps module - Include/cholmod_modify.h part of Modify module - Include/cholmod_partition.h part of Partition module - Include/cholmod_supernodal.h part of Supernodal module - Include/cholmod_template.h LGPL + CHOLMOD/Include/* files. Copyright (C) 2005-2023 + + CHOLMOD/Include/cholmod.h SPDX-License-Identifier: Apache-2.0 + CHOLMOD/Include/cholmod_internal.h SPDX-License-Identifier: Apache-2.0 + CHOLMOD/Include/cholmod_template.h SPDX-License-Identifier: Apache-2.0 + CHOLMOD/Include/cholmod_types.h SPDX-License-Identifier: Apache-2.0 -------------------------------------------------------------------------------- ==> MATLAB/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/MATLAB Module. Copyright (C) 2005-2022, Timothy A. Davis. CHOLMOD + CHOLMOD/MATLAB Module. Copyright (C) 2005-2023, Timothy A. Davis. CHOLMOD is also available under other licenses; contact authors for details. MATLAB(tm) is a Registered Trademark of The MathWorks, Inc. http://suitesparse.com @@ -353,7 +336,7 @@ found in the lists below. ==> MatrixOps/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/MatrixOps Module. Copyright (C) 2005-2022, Timothy A. Davis. + CHOLMOD/MatrixOps Module. Copyright (C) 2005-2023, Timothy A. Davis. CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -382,7 +365,7 @@ found in the lists below. ==> Modify/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Modify Module. Copyright (C) 2005-2022, Timothy A. Davis and + CHOLMOD/Modify Module. Copyright (C) 2005-2023, Timothy A. Davis and William W. Hager. CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -412,7 +395,7 @@ found in the lists below. -------------------------------------------------------------------------------- CHOLMOD/Partition Module. - Copyright (C) 2005-2022, Univ. of Florida. Author: Timothy A. Davis + Copyright (C) 2005-2023, Univ. of Florida. Author: Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -442,7 +425,7 @@ found in the lists below. -------------------------------------------------------------------------------- CHOLMOD/Supernodal Module. - Copyright (C) 2005-2022, Timothy A. Davis + Copyright (C) 2005-2023, Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -471,7 +454,7 @@ found in the lists below. ==> Tcov/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Tcov Module. Copyright (C) 2005-2022, Timothy A. Davis + CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -500,7 +483,7 @@ found in the lists below. ==> Valgrind/License.txt <== -------------------------------------------------------------------------------- - CHOLMOD/Valgrind Module. Copyright (C) 2005-2022, Timothy A. Davis. + CHOLMOD/Valgrind Module. Copyright (C) 2005-2023, Timothy A. Davis. CHOLMOD is also available under other licenses; contact authors for details. http://suitesparse.com @@ -526,7 +509,7 @@ found in the lists below. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. ==> COLAMD/Doc/License.txt <== - COLAMD, Copyright 1998-2022, Timothy A. Davis. http://suitesparse.com + COLAMD, Copyright 1998-2023, Timothy A. Davis. http://suitesparse.com http://suitesparse.com COLAMD License: BSD 3-clause @@ -557,7 +540,7 @@ found in the lists below. ==> CSparse/Doc/License.txt <== CSparse: a Concise Sparse matrix package. - Copyright (c) 2006-2022, Timothy A. Davis. + Copyright (c) 2006-2023, Timothy A. Davis. http://suitesparse.com -------------------------------------------------------------------------------- @@ -578,7 +561,7 @@ found in the lists below. ==> CXSparse/Doc/License.txt <== CXSparse: a Concise Sparse matrix package - Extended. - Copyright (c) 2006-2022, Timothy A. Davis. + Copyright (c) 2006-2023, Timothy A. Davis. http://suitesparse.com -------------------------------------------------------------------------------- @@ -599,7 +582,7 @@ found in the lists below. ==> CXSparse_newfiles/Doc/License.txt <== CXSparse: a Concise Sparse matrix package - Extended. - Copyright (c) 2006-2022, Timothy A. Davis. + Copyright (c) 2006-2023, Timothy A. Davis. http://suitesparse.com -------------------------------------------------------------------------------- @@ -618,17 +601,17 @@ found in the lists below. License along with this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -==> GPUQREngine/Doc/License.txt <== - GPUQREngine Copyright (c) 2013-2022, Timothy A. Davis, Sencer Nuri Yeralan, +==> SPQR/GPUQREngine/Doc/License.txt <== + SPQR/GPUQREngine Copyright (c) 2013-2023, Timothy A. Davis, Sencer Nuri Yeralan, and Sanjay Ranka. http://suitesparse.com - GPUQREngine is free software; you can redistribute it and/or modify it under + SPQR/GPUQREngine is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - GPUQREngine is distributed in the hope that it will be useful, but WITHOUT + SPQR/GPUQREngine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -638,7 +621,7 @@ found in the lists below. ==> KLU/Doc/License.txt <== - KLU, Copyright (C) 2004-2022, University of Florida + KLU, Copyright (C) 2004-2023, University of Florida by Timothy A. Davis and Ekanathan Palamadai. KLU is also available under other licenses; contact authors for details. http://suitesparse.com @@ -660,7 +643,7 @@ found in the lists below. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ==> LDL/Doc/License.txt <== - LDL Copyright (c) 2005-2022 by Timothy A. Davis. + LDL Copyright (c) 2005-2023 by Timothy A. Davis. LDL is also available under other licenses; contact the author for details. http://suitesparse.com @@ -739,7 +722,7 @@ found in the lists below. SSMULT License: -------------------------------------------------------------------------------- - SSMULT, Copyright (c) 2007-2022, Timothy A. Davis, + SSMULT, Copyright (c) 2007-2023, Timothy A. Davis, http://suitesparse.com. SSMULT is free software; you can redistribute it and/or modify it under the @@ -758,7 +741,7 @@ found in the lists below. ==> RBio/Doc/License.txt <== - RBio toolbox. Copyright (C) 2006-2022, Timothy A. Davis + RBio toolbox. Copyright (C) 2006-2023, Timothy A. Davis RBio is also available under other licenses; contact authors for details. http://suitesparse.com @@ -780,7 +763,7 @@ found in the lists below. ==> SPQR/Doc/License.txt <== - SPQR, Copyright 2008-2022 by Timothy A. Davis. + SPQR, Copyright 2008-2023 by Timothy A. Davis. All Rights Reserved. SPQR is available under alternate licenses, contact T. Davis for details. @@ -819,18 +802,18 @@ found in the lists below. http://suitesparse.com -==> SuiteSparse_GPURuntime/Doc/License.txt <== - SuiteSparse_GPURuntime Copyright (c) 2013-2022, Timothy A. Davis, +==> SPQR/GPURuntime/Doc/License.txt <== + SPQR/GPURuntime Copyright (c) 2013-2023, Timothy A. Davis, Sencer Nuri Yeralan, and Sanjay Ranka. http://suitesparse.com -------------------------------------------------------------------------------- - SuiteSparse_GPURuntime is free software; you can redistribute it and/or modify + SPQR/GPURuntime is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - SuiteSparse_GPURuntime is distributed in the hope that it will be useful, but + SPQR/GPURuntime is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -840,7 +823,7 @@ found in the lists below. Street, Fifth Floor, Boston, MA 02110-1301, USA. ==> ssget/Doc/License.txt <== - Copyright (c), 2009-2022, Timothy A. Davis, All Rights Reserved. + Copyright (c), 2009-2023, Timothy A. Davis, All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -868,7 +851,7 @@ found in the lists below. ==> UMFPACK/Doc/License.txt <== - UMFPACK, Copyright 1995-2022 by Timothy A. Davis. + UMFPACK, Copyright 1995-2023, by Timothy A. Davis. All Rights Reserved. UMFPACK is available under alternate licenses, contact T. Davis for details. @@ -908,7 +891,7 @@ found in the lists below. ==> CSparse/MATLAB/ssget/Doc/License.txt <== - Copyright (c), 2009-2022, Timothy A. Davis, All Rights Reserved. + Copyright (c), 2009-2023, Timothy A. Davis, All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -936,7 +919,7 @@ found in the lists below. ==> CXSparse/MATLAB/ssget/Doc/License.txt <== - Copyright (c), 2009-2022, Timothy A. Davis, All Rights Reserved. + Copyright (c), 2009-2023, Timothy A. Davis, All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -1003,13 +986,13 @@ found in the lists below. SPDX-License-Identifier: GPL-3.0-or-later ==> Mongoose License <== - Mongoose, Copyright 2018-2022, Timothy A. Davis, Scott P. Kolodziej, + Mongoose, Copyright 2018-2023, Timothy A. Davis, Scott P. Kolodziej, William W. Hager, S. Nuri Yeralan Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3, 29 June 2007 ==> Example License <== -Example package, Copyright (c), 2022, Timothy A. Davis, All Rights Reserved. +Example package, Copyright (c), 2023, Timothy A. Davis, All Rights Reserved. SPDX-License-Identifier: BSD-3-clause Redistribution and use in source and binary forms, with or without @@ -1036,3 +1019,60 @@ SPDX-License-Identifier: BSD-3-clause OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +==> ParU License <== + + ParU package, Copyright (c), 2023, Mohsen Aznaveh and Timothy A. Davis, All + Rights Reserved. + SPDX-License-Identifier: GPL-3.0-or-later + +==> LAGraph License <== + + SPDX-License-Identifier: BSD-2-clause + + File: LICENSE + + LAGraph + + Copyright 2019-2023 LAGraph Contributors. All Rights Reserved. + (see Contributors.txt for a full list of Contributors; + see ContributionInstructions.txt for information on how you can + Contribute to this project). + + BSD + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + ACKNOWLEDGMENTS AND DISCLAIMERS: + + This program includes and/or can make use of certain third party source code, + object code, documentation and other files ("Third Party Software"). The Third + Party Software that is used by this program is dependent upon your system + configuration. By using this program, You agree to comply with any and all + relevant Third Party Software terms and conditions contained in any such Third + Party Software or separate license file distributed with such Third Party + Software. The parties who own the Third Party Software ("Third Party + Licensors") are intended third party beneficiaries to this License with + respect to the terms applicable to their Third Party Software. Third Party + Software licenses only apply to the Third Party Software and not any other + portion of this program or this program as a whole. + + Created, in part, with funding and support from the United States Government. + (see Acknowledgments.txt file). + + NO WARRANTY. THIS MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. THE LAGRAPH + CONTRIBUTORS MAKE NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS + TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE + OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE + MATERIAL. THE CONTRIBUTORS DO NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT + TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. + + DM22-0790 + diff --git a/ThirdParty/SuiteSparse/README.md b/ThirdParty/SuiteSparse/README.md index 6771fa1d86..29c74df122 100644 --- a/ThirdParty/SuiteSparse/README.md +++ b/ThirdParty/SuiteSparse/README.md @@ -2,18 +2,48 @@ SuiteSparse: A Suite of Sparse matrix packages at http://suitesparse.com ----------------------------------------------------------------------------- -Jan 20, 2023, SuiteSparse VERSION 7.0.1 +Jan 20, 2024, SuiteSparse VERSION 7.6.0 SuiteSparse is a set of sparse-matrix-related packages written or co-authored by Tim Davis, available at https://github.com/DrTimothyAldenDavis/SuiteSparse . Primary author of SuiteSparse (codes and algorithms, excl. METIS): Tim Davis -Code co-authors, in alphabetical order (not including METIS): - Patrick Amestoy, David Bateman, Jinhao Chen, Yanqing Chen, Iain Duff, - Les Foster, William Hager, Scott Kolodziej, Chris Lourenco, Stefan - Larimore, Erick Moreno-Centeno, Ekanathan Palamadai, Sivasankaran - Rajamanickam, Sanjay Ranka, Wissam Sid-Lakhdar, Nuri Yeralan. +Code co-authors, in alphabetical order (not including METIS or LAGraph): + Patrick Amestoy, Mohsen Aznaveh, David Bateman, Jinhao Chen, Yanqing Chen, + Iain Duff, Joe Eaton, Les Foster, William Hager, Raye Kimmerer, Scott + Kolodziej, Chris Lourenco, Stefan Larimore, Lorena Mejia Domenzain, Erick + Moreno-Centeno, Markus Mützel, Corey Nolel, Ekanathan Palamadai, + Sivasankaran Rajamanickam, Sanjay Ranka, Wissam Sid-Lakhdar, and + Nuri Yeralan. + +LAGraph has been developed by the highest number of developers of any of +the packages in SuiteSparse and deserves its own list. The list also +appears in LAGraph/Contibutors.txt: + + Janos B. Antal, Budapest University of Technology and Economics, Hungary + Mohsen Aznaveh, Texas A&M University + David A. Bader New Jersey Institute of Technology + Aydin Buluc, Lawrence Berkeley National Lab + Jinhao Chen, Texas A&M University + Tim Davis, Texas A&M University + Florentin Dorre, Technische Univeritat Dresden, Neo4j + Marton Elekes, Budapest University of Technology and Economics, Hungary + Balint Hegyi, Budapest University of Technology and Economics, Hungary + Tanner Hoke, Texas A&M University + James Kitchen, Anaconda + Scott Kolodziej, Texas A&M University + Pranav Konduri, Texas A&M University + Roi Lipman, Redis Labs (now FalkorDB) + Tze Meng Low, Carnegie Mellon University + Tim Mattson, Intel + Scott McMillan, Carnegie Mellon University + Markus Muetzel + Michel Pelletier, Graphegon + Gabor Szarnyas, CWI Amsterdam, The Netherlands + Erik Welch, Anaconda, NVIDIA + Carl Yang, University of California at Davis, Waymo + Yongzhe Zhang, SOKENDAI, Japan METIS is authored by George Karypis. @@ -21,17 +51,460 @@ Additional algorithm designers: Esmond Ng and John Gilbert. Refer to each package for license, copyright, and author information. +----------------------------------------------------------------------------- +Documentation +----------------------------------------------------------------------------- + +Refer to each package for the documentation on each package, typically in the +Doc subfolder. + ----------------------------------------------------------------------------- SuiteSparse branches ----------------------------------------------------------------------------- - * dev: the default branch, with recent updates of features to appear in - the next stable release. The intent is to keep this branch in - fully working order at all times, but the features will not be - finalized at any given time. - * stable: the most recent stable release. - * dev2: working branch. All submitted PRs should made to this branch. - This branch might not always be in working order. +* dev: the default branch, with recent updates of features to appear in + the next stable release. The intent is to keep this branch in + fully working order at all times, but the features will not be + finalized at any given time. +* stable: the most recent stable release. +* dev2: working branch. All submitted PRs should made to this branch. + This branch might not always be in working order. + +----------------------------------------------------------------------------- +SuiteSparse Packages +----------------------------------------------------------------------------- + +Packages in SuiteSparse, and files in this directory: + +* `AMD` + + approximate minimum degree ordering. This is the built-in AMD function in + MATLAB. + + authors: Tim Davis, Patrick Amestoy, Iain Duff + +* `bin` + + where programs are placed when compiled, for `make local` + +* `BTF` + + permutation to block triangular form + + authors: Tim Davis, Ekanathan Palamadai + +* `build` + + folder for default build tree + +* `CAMD` + + constrained approximate minimum degree ordering + + authors: Tim Davis, Patrick Amestoy, Iain Duff, Yanqing Chen + +* `CCOLAMD` + + constrained column approximate minimum degree ordering + + authors: Tim Davis, Sivasankaran Rajamanickam, Stefan Larimore. + + Algorithm design collaborators: Esmond Ng, John Gilbert (for COLAMD) + +* `ChangeLog` + + a summary of changes to SuiteSparse. See `*/Doc/ChangeLog` for details for + each package. + +* `CHOLMOD` + + sparse Cholesky factorization. Requires AMD, COLAMD, CCOLAMD, the BLAS, and + LAPACK. Optionally uses METIS. This is `chol` and `x=A\b` in MATLAB. + + author for all modules: Tim Davis + + CHOLMOD/Modify module authors: Tim Davis and William W. Hager + + CHOLMOD/SuiteSparse_metis: a modified version of METIS, embedded into the + CHOLMOD library. See the README.txt files for details. author: George + Karypis. This is a slightly modified copy included with SuiteSparse via the + open-source license provided by George Karypis. SuiteSparse cannot use an + unmodified copy of METIS. + +* `CITATION.bib` + + citations for SuiteSparse packages, in bibtex format. + +* `CMakeLists.txt` + + optional, to compile all of SuiteSparse. See below. + +* `CODE_OF_CONDUCT.md` + + community guidelines + +* `COLAMD` + + column approximate minimum degree ordering. This is the built-in COLAMD + function in MATLAB. + + authors (of the code): Tim Davis and Stefan Larimore + + Algorithm design collaborators: Esmond Ng, John Gilbert + +* `Contents.m` + + a list of contents for 'help SuiteSparse' in MATLAB. + +* `CONTRIBUTING.md` + + how to contribute to SuiteSparse + +* `CONTRIBUTOR-LICENSE.txt` + + required contributor agreement + +* `CSparse` + + a concise sparse matrix package, developed for my book, "Direct Methods for + Sparse Linear Systems", published by SIAM. Intended primarily for teaching. + Note that the code is (c) Tim Davis, as stated in the book. + + For production, use CXSparse instead. In particular, both CSparse and + CXSparse have the same include filename: `cs.h`. This package is used for + the built-in DMPERM in MATLAB. + + author: Tim Davis + +* `CXSparse` + + CSparse Extended. Includes support for complex matrices and both int or long + integers. Use this instead of CSparse for production use; it creates a + libcsparse.so (or dylib on the Mac) with the same name as CSparse. It is a + superset of CSparse. Any code that links against CSparse should also be able + to link against CXSparse instead. + + author: Tim Davis, David Bateman + +* `Example` + + a simple package that relies on almost all of SuiteSparse + +* `.github` + + workflows for CI testing on GitHub. + +* `GraphBLAS` + + graph algorithms in the language of linear algebra. + + https://graphblas.org + + authors: Tim Davis, Joe Eaton, Corey Nolet + +* `include` + + `make install` places user-visible include files for each package here, after + `make local`. + +* `KLU` + + sparse LU factorization, primarily for circuit simulation. Requires AMD, + COLAMD, and BTF. Optionally uses CHOLMOD, CAMD, CCOLAMD, and METIS. + + authors: Tim Davis, Ekanathan Palamadai + +* `LAGraph` + + a graph algorithms library based on GraphBLAS. See also + https://github.com/GraphBLAS/LAGraph + + Authors: many. + +* `LDL` + + a very concise LDL' factorization package + + author: Tim Davis + +* `lib` + + `make install` places shared libraries for each package here, after + `make local`. + +* `LICENSE.txt` + + collected licenses for each package. + +* `Makefile` + + optional, to compile all of SuiteSparse using `make`, which is used as a + simple wrapper for `cmake` in each subproject. + + * `make` + + compiles SuiteSparse libraries. Subsequent `make install` will install + in `CMAKE_INSTALL_PATH` (might default to `/usr/local/lib` on Linux or Mac). + + * `make local` + + compiles SuiteSparse. Subsequent `make install` will install in `./lib`, + `./include`. Does not install in `CMAKE_INSTALL_PATH`. + + * `make global` + + compiles SuiteSparse libraries. Subsequent `make install` will install in + `/usr/local/lib` (or whatever the configured `CMAKE_INSTALL_PREFIX` is). + Does not install in `./lib` and `./include`. + + * `make install` + + installs in the current directory (`./lib`, `./include`), or in + `/usr/local/lib` and `/usr/local/include`, (the latter defined by + `CMAKE_INSTALL_PREFIX`) depending on whether `make`, `make local`, or + `make global` has been done. + + * `make uninstall` + + undoes `make install`. + + * `make distclean` + + removes all files not in distribution, including `./bin`, `./share`, + `./lib`, and `./include`. + + * `make purge` + + same as `make distclean`. + + * `make clean` + + removes all files not in distribution, but keeps compiled libraries and + demos, `./lib`, `./share`, and `./include`. + + Each individual subproject also has each of the above `make` targets. + + Things you don't need to do: + + * `make docs` + + creates user guides from LaTeX files + + * `make cov` + + runs statement coverage tests (Linux only) + +* `MATLAB_Tools` + + various m-files for use in MATLAB + + author: Tim Davis (all parts) + + for `spqr_rank`: author Les Foster and Tim Davis + + * `Contents.m` + + list of contents + + * `dimacs10` + + loads matrices for DIMACS10 collection + + * `Factorize` + + object-oriented `x=A\b` for MATLAB + + * `find_components` + + finds connected components in an image + + * `GEE` + + simple Gaussian elimination + + * `getversion.m` + + determine MATLAB version + + * `gipper.m` + + create MATLAB archive + + * `hprintf.m` + + print hyperlinks in command window + + * `LINFACTOR` + + predecessor to `Factorize` package + + * `MESHND` + + nested dissection ordering of regular meshes + + * `pagerankdemo.m` + + illustrates how PageRank works + + * `SFMULT` + + `C=S*F` where `S` is sparse and `F` is full + + * `shellgui` + + display a seashell + + * `sparseinv` + + sparse inverse subset + + * `spok` + + check if a sparse matrix is valid + + * `spqr_rank` + + SPQR_RANK package. MATLAB toolbox for rank deficient sparse matrices: null + spaces, reliable factorizations, etc. With Leslie Foster, San Jose State + Univ. + + * `SSMULT` + + `C=A*B` where `A` and `B` are both sparse. + This was the basis for the built-in `C=A*B` in MATLAB, until it was + superseded by GraphBLAS in MATLAB R2021a. + + * `SuiteSparseCollection` + + for the SuiteSparse Matrix Collection + + * `waitmex` + + waitbar for use inside a mexFunction + +* `Mongoose` + + graph partitioning. + + authors: Nuri Yeralan, Scott Kolodziej, William Hager, Tim Davis + +* `ParU` + + a parallel unsymmetric pattern multifrontal method. + + Currently a pre-release. + + authors: Mohsen Aznaveh and Tim Davis + +* `RBio` + + read/write sparse matrices in Rutherford/Boeing format + + author: Tim Davis + +* `README.md` + + this file + +* `SPEX` + + solves sparse linear systems in exact arithmetic. + + Requires the GNU GMP and MPRF libraries. + + This will be soon replaced by a more general package, SPEX v3 that includes + this method (exact sparse LU) and others (sparse exact Cholesky, and sparse + exact update/downdate). The API of v3 will be changing significantly. + + authors: Chris Lourenco, Jinhao Chen, Erick Moreno-Centeno, + Lorena Lorena Mejia Domenzain, and Tim Davis. + + See https://github.com/clouren/SPEX for the latest version. + +* `SPQR` + + sparse QR factorization. This the built-in `qr` and `x=A\b` in MATLAB. Also + called SuiteSparseQR. + + Includes two GPU libraries: `SPQR/GPUQREngine` and + `SPQR/SuiteSparse_GPURuntime`. + + author of the CPU code: Tim Davis + + author of GPU modules: Tim Davis, Nuri Yeralan, Wissam Sid-Lakhdar, + Sanjay Ranka + +* `ssget` + + MATLAB interface to the SuiteSparse Matrix Collection + + author: Tim Davis + +* `SuiteSparse_config` + + library with common functions and configuration for all the above packages. + `CSparse`, `GraphBLAS`, `LAGraph`, and `MATLAB_Tools` do not use + `SuiteSparse_config`. + + author: Tim Davis + +* `SuiteSparse_demo.m` + + a demo of SuiteSparse for MATLAB + +* `SuiteSparse_install.m` + + install SuiteSparse for MATLAB + +* `SuiteSparse_paths.m` + + set paths for SuiteSparse MATLAB mexFunctions + +* `SuiteSparse_test.m` + + exhaustive test for SuiteSparse in MATLAB + +* `UMFPACK` + + sparse LU factorization. Requires `AMD` and the `BLAS`. + + This is the built-in `lu` and `x=A\b` in MATLAB. + + author: Tim Davis + + algorithm design collaboration: Iain Duff + +Refer to each package for license, copyright, and author information. All +codes are authored or co-authored by Timothy A. Davis (email: davis@tamu.edu), +except for METIS (by George Karypis), `GraphBLAS/cpu_features` (by Google), +GraphBLAS/lz4, zstd, and xxHash (by Yann Collet, now at Facebook), and +GraphBLAS/CUDA/jitify.hpp (by NVIDIA). Parts of GraphBLAS/CUDA are +Copyright (c) by NVIDIA. Please refer to each of these licenses. + +----------------------------------------------------------------------------- +For distro maintainers (Linux, homebrew, spack, R, Octave, Trilinos, ...): +----------------------------------------------------------------------------- + +Thanks for packaging SuiteSparse! Here are some suggestions: + +* GraphBLAS takes a long time to compile because it creates many fast + "FactoryKernels" at compile-time. If you want to reduce the compile time and + library size, enable the `GRAPHBLAS_COMPACT` mode, but keep the JIT compiler + enabled. Then GraphBLAS will compile the kernels it needs at run-time, via + its JIT compiler. Performance will be the same as the FactoryKernels once + the JIT kernels are compiled. User compiled kernels are placed in + `~/.SuiteSparse`, by default. You do not need to distribute the source for + GraphBLAS to enable the JIT compiler: just `libgraphblas.so` and + `GraphBLAS.h` is enough. + +* GraphBLAS needs OpenMP! It's fundamentally a parallel code so please + distribute it with OpenMP enabled. Performance will suffer otherwise. + +* CUDA acceleration: CHOLMOD and SPQR can benefit from their CUDA kernels. If + you do not have CUDA or do not want to include it in your distro, this + version of SuiteSparse skips the building of the `CHOLMOD_CUDA` and `SPQR_CUDA` + libraries, and does not link against the `GPUQREngine` and + `SuiteSparse_GPURuntime` libraries. ----------------------------------------------------------------------------- How to cite the SuiteSparse meta-package and its component packages: @@ -40,193 +513,180 @@ How to cite the SuiteSparse meta-package and its component packages: SuiteSparse is a meta-package of many packages, each with their own published papers. To cite the whole collection, use the URLs: - * https://github.com/DrTimothyAldenDavis/SuiteSparse - * http://suitesparse.com (which is a forwarding URL +* https://github.com/DrTimothyAldenDavis/SuiteSparse +* http://suitesparse.com (which is a forwarding URL to https://people.engr.tamu.edu/davis/suitesparse.html) Please also cite the specific papers for the packages you use. This is a long list; if you want a shorter list, just cite the most recent "Algorithm XXX:" papers in ACM TOMS, for each package. - * For the MATLAB x=A\b, see below for AMD, COLAMD, CHOLMOD, UMFPACK, - and SuiteSparseQR (SPQR). +* For the MATLAB x=A\b, see below for AMD, COLAMD, CHOLMOD, UMFPACK, + and SuiteSparseQR (SPQR). - * for GraphBLAS, and `C=A*B` in MATLAB (sparse-times-sparse): +* for GraphBLAS, and C=AB in MATLAB (sparse-times-sparse): - T. Davis, Algorithm 10xx: SuiteSparse:GraphBLAS: parallel graph - algorithms in the language of sparse linear algebra, ACM Trans on - Mathematical Software, to appear, 2023. See the pdf in - https://github.com/DrTimothyAldenDavis/GraphBLAS/tree/stable/Doc + T. A. Davis. Algorithm 1037: SuiteSparse:GraphBLAS: Parallel Graph Algorithms + in the Language of Sparse Linear Algebra. ACM Trans. Math. Softw. 49, 3, + Article 28 (September 2023), 30 pages. https://doi.org/10.1145/3577195 - T. Davis, Algorithm 1000: SuiteSparse:GraphBLAS: graph algorithms in - the language of sparse linear algebra, ACM Trans on Mathematical - Software, vol 45, no 4, Dec. 2019, Article No 44. - https://doi.org/10.1145/3322125. + T. Davis, Algorithm 1000: SuiteSparse:GraphBLAS: graph algorithms in the + language of sparse linear algebra, ACM Trans on Mathematical Software, vol + 45, no 4, Dec. 2019, Article No 44. https://doi.org/10.1145/3322125. - * for CSparse/CXSParse: +* for LAGraph: - T. A. Davis, Direct Methods for Sparse Linear Systems, SIAM Series on - the Fundamentals of Algorithms, SIAM, Philadelphia, PA, 2006. - https://doi.org/10.1137/1.9780898718881 + G. Szárnyas et al., "LAGraph: Linear Algebra, Network Analysis Libraries, and + the Study of Graph Algorithms," 2021 IEEE International Parallel and + Distributed Processing Symposium Workshops (IPDPSW), Portland, OR, USA, 2021, + pp. 243-252. https://doi.org/10.1109/IPDPSW52791.2021.00046. - * for SuiteSparseQR (SPQR): (also cite AMD, COLAMD): +* for CSparse/CXSParse: - T. A. Davis, Algorithm 915: SuiteSparseQR: Multifrontal multithreaded - rank-revealing sparse QR factorization, ACM Trans. on Mathematical - Software, 38(1), 2011, pp. 8:1--8:22. - https://doi.org/10.1145/2049662.2049670 + T. A. Davis, Direct Methods for Sparse Linear Systems, SIAM Series on the + Fundamentals of Algorithms, SIAM, Philadelphia, PA, 2006. + https://doi.org/10.1137/1.9780898718881 - * for SuiteSparseQR/GPU: +* for SuiteSparseQR (SPQR): (also cite AMD, COLAMD): - Sencer Nuri Yeralan, T. A. Davis, Wissam M. Sid-Lakhdar, and Sanjay - Ranka. 2017. Algorithm 980: Sparse QR Factorization on the GPU. ACM - Trans. Math. Softw. 44, 2, Article 17 (June 2018), 29 pages. - https://doi.org/10.1145/3065870 + T. A. Davis, Algorithm 915: SuiteSparseQR: Multifrontal multithreaded + rank-revealing sparse QR factorization, ACM Trans. on Mathematical Software, + 38(1), 2011, pp. 8:1--8:22. https://doi.org/10.1145/2049662.2049670 - * for CHOLMOD: (also cite AMD, COLAMD): +* for SuiteSparseQR/GPU: - Y. Chen, T. A. Davis, W. W. Hager, and S. Rajamanickam, Algorithm 887: - CHOLMOD, supernodal sparse Cholesky factorization and update/downdate, - ACM Trans. on Mathematical Software, 35(3), 2008, pp. 22:1--22:14. - https://dl.acm.org/doi/abs/10.1145/1391989.1391995 + Sencer Nuri Yeralan, T. A. Davis, Wissam M. Sid-Lakhdar, and Sanjay Ranka. + 2017. Algorithm 980: Sparse QR Factorization on the GPU. ACM Trans. Math. + Softw. 44, 2, Article 17 (June 2018), 29 pages. + https://doi.org/10.1145/3065870 - T. A. Davis and W. W. Hager, Dynamic supernodes in sparse Cholesky - update/downdate and triangular solves, ACM Trans. on Mathematical - Software, 35(4), 2009, pp. 27:1--27:23. - https://doi.org/10.1145/1462173.1462176 +* for CHOLMOD: (also cite AMD, COLAMD): - * for CHOLMOD/Modify Module: (also cite AMD, COLAMD): + Y. Chen, T. A. Davis, W. W. Hager, and S. Rajamanickam, Algorithm 887: + CHOLMOD, supernodal sparse Cholesky factorization and update/downdate, ACM + Trans. on Mathematical Software, 35(3), 2008, pp. 22:1--22:14. + https://dl.acm.org/doi/abs/10.1145/1391989.1391995 - T. A. Davis and William W. Hager, Row Modifications of a Sparse - Cholesky Factorization SIAM Journal on Matrix Analysis and Applications - 2005 26:3, 621-639 - https://doi.org/10.1137/S089547980343641X + T. A. Davis and W. W. Hager, Dynamic supernodes in sparse Cholesky + update/downdate and triangular solves, ACM Trans. on Mathematical Software, + 35(4), 2009, pp. 27:1--27:23. https://doi.org/10.1145/1462173.1462176 - T. A. Davis and William W. Hager, Multiple-Rank Modifications of a - Sparse Cholesky Factorization SIAM Journal on Matrix Analysis and - Applications 2001 22:4, 997-1013 - https://doi.org/10.1137/S0895479899357346 +* for CHOLMOD/Modify Module: (also cite AMD, COLAMD): - T. A. Davis and William W. Hager, Modifying a Sparse Cholesky - Factorization, SIAM Journal on Matrix Analysis and Applications 1999 - 20:3, 606-627 - https://doi.org/10.1137/S0895479897321076 + T. A. Davis and William W. Hager, Row Modifications of a Sparse Cholesky + Factorization SIAM Journal on Matrix Analysis and Applications 2005 26:3, + 621-639. https://doi.org/10.1137/S089547980343641X - * for CHOLMOD/GPU Modules: + T. A. Davis and William W. Hager, Multiple-Rank Modifications of a Sparse + Cholesky Factorization SIAM Journal on Matrix Analysis and Applications 2001 + 22:4, 997-1013. https://doi.org/10.1137/S0895479899357346 - Steven C. Rennich, Darko Stosic, Timothy A. Davis, Accelerating sparse - Cholesky factorization on GPUs, Parallel Computing, Vol 59, 2016, pp - 140-150. - https://doi.org/10.1016/j.parco.2016.06.004 + T. A. Davis and William W. Hager, Modifying a Sparse Cholesky Factorization, + SIAM Journal on Matrix Analysis and Applications 1999 20:3, 606-627. + https://doi.org/10.1137/S0895479897321076 - * for AMD and CAMD: +* for CHOLMOD/GPU Modules: - P. Amestoy, T. A. Davis, and I. S. Duff, Algorithm 837: An approximate - minimum degree ordering algorithm, ACM Trans. on Mathematical Software, - 30(3), 2004, pp. 381--388. - https://dl.acm.org/doi/abs/10.1145/1024074.1024081 + Steven C. Rennich, Darko Stosic, Timothy A. Davis, Accelerating sparse + Cholesky factorization on GPUs, Parallel Computing, Vol 59, 2016, pp 140-150. + https://doi.org/10.1016/j.parco.2016.06.004 - P. Amestoy, T. A. Davis, and I. S. Duff, An approximate minimum degree - ordering algorithm, SIAM J. Matrix Analysis and Applications, 17(4), - 1996, pp. 886--905. - https://doi.org/10.1137/S0895479894278952 +* for AMD and CAMD: - * for COLAMD, SYMAMD, CCOLAMD, and CSYMAMD: + P. Amestoy, T. A. Davis, and I. S. Duff, Algorithm 837: An approximate + minimum degree ordering algorithm, ACM Trans. on Mathematical Software, + 30(3), 2004, pp. 381--388. + https://dl.acm.org/doi/abs/10.1145/1024074.1024081 - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, - an approximate column minimum degree ordering algorithm, ACM Trans. on - Mathematical Software, 30(3), 2004, pp. 377--380. - https://doi.org/10.1145/1024074.1024080 + P. Amestoy, T. A. Davis, and I. S. Duff, An approximate minimum degree + ordering algorithm, SIAM J. Matrix Analysis and Applications, 17(4), 1996, + pp. 886--905. https://doi.org/10.1137/S0895479894278952 - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, A column approximate - minimum degree ordering algorithm, ACM Trans. on Mathematical Software, - 30(3), 2004, pp. 353--376. - https://doi.org/10.1145/1024074.1024079 +* for COLAMD, SYMAMD, CCOLAMD, and CSYMAMD: - * for UMFPACK: (also cite AMD and COLAMD): + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, an + approximate column minimum degree ordering algorithm, ACM Trans. on + Mathematical Software, 30(3), 2004, pp. 377--380. + https://doi.org/10.1145/1024074.1024080 - T. A. Davis, Algorithm 832: UMFPACK - an unsymmetric-pattern - multifrontal method with a column pre-ordering strategy, ACM Trans. on - Mathematical Software, 30(2), 2004, pp. 196--199. - https://dl.acm.org/doi/abs/10.1145/992200.992206 + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, A column approximate minimum + degree ordering algorithm, ACM Trans. on Mathematical Software, 30(3), 2004, + pp. 353--376. https://doi.org/10.1145/1024074.1024079 - T. A. Davis, A column pre-ordering strategy for the unsymmetric-pattern - multifrontal method, ACM Trans. on Mathematical Software, 30(2), 2004, - pp. 165--195. - https://dl.acm.org/doi/abs/10.1145/992200.992205 +* for UMFPACK: (also cite AMD and COLAMD): - T. A. Davis and I. S. Duff, A combined unifrontal/multifrontal method - for unsymmetric sparse matrices, ACM Trans. on Mathematical Software, - 25(1), 1999, pp. 1--19. - https://doi.org/10.1145/305658.287640 + T. A. Davis, Algorithm 832: UMFPACK - an unsymmetric-pattern multifrontal + method with a column pre-ordering strategy, ACM Trans. on Mathematical + Software, 30(2), 2004, pp. 196--199. + https://dl.acm.org/doi/abs/10.1145/992200.992206 - T. A. Davis and I. S. Duff, An unsymmetric-pattern multifrontal method - for sparse LU factorization, SIAM J. Matrix Analysis and Computations, - 18(1), 1997, pp. 140--158. - https://doi.org/10.1137/S0895479894246905 + T. A. Davis, A column pre-ordering strategy for the unsymmetric-pattern + multifrontal method, ACM Trans. on Mathematical Software, 30(2), 2004, pp. + 165--195. https://dl.acm.org/doi/abs/10.1145/992200.992205 - * for the FACTORIZE m-file: + T. A. Davis and I. S. Duff, A combined unifrontal/multifrontal method for + unsymmetric sparse matrices, ACM Trans. on Mathematical Software, 25(1), + 1999, pp. 1--19. https://doi.org/10.1145/305658.287640 - T. A. Davis, Algorithm 930: FACTORIZE, an object-oriented linear system - solver for MATLAB, ACM Trans. on Mathematical Software, 39(4), 2013, - pp. 28:1-28:18. - https://doi.org/10.1145/2491491.2491498 + T. A. Davis and I. S. Duff, An unsymmetric-pattern multifrontal method for + sparse LU factorization, SIAM J. Matrix Analysis and Computations, 18(1), + 1997, pp. 140--158. https://doi.org/10.1137/S0895479894246905 - * for KLU and BTF (also cite AMD and COLAMD): +* for the FACTORIZE m-file: - T. A. Davis and Ekanathan Palamadai Natarajan. 2010. Algorithm 907: - KLU, A Direct Sparse Solver for Circuit Simulation Problems. ACM Trans. - Math. Softw. 37, 3, Article 36 (September 2010), 17 pages. - https://dl.acm.org/doi/abs/10.1145/1824801.1824814 + T. A. Davis, Algorithm 930: FACTORIZE, an object-oriented linear system + solver for MATLAB, ACM Trans. on Mathematical Software, 39(4), 2013, pp. + 28:1-28:18. https://doi.org/10.1145/2491491.2491498 - * for LDL: +* for KLU and BTF (also cite AMD and COLAMD): - T. A. Davis. Algorithm 849: A concise sparse Cholesky factorization - package. ACM Trans. Math. Softw. 31, 4 (December 2005), 587–591. - https://doi.org/10.1145/1114268.1114277 + T. A. Davis and Ekanathan Palamadai Natarajan. 2010. Algorithm 907: KLU, A + Direct Sparse Solver for Circuit Simulation Problems. ACM Trans. Math. + Softw. 37, 3, Article 36 (September 2010), 17 pages. + https://dl.acm.org/doi/abs/10.1145/1824801.1824814 - * for ssget and the SuiteSparse Matrix Collection: +* for LDL: - T. A. Davis and Yifan Hu. 2011. The University of Florida sparse - matrix collection. ACM Trans. Math. Softw. 38, 1, Article 1 (November - 2011), 25 pages. - https://doi.org/10.1145/2049662.2049663 + T. A. Davis. Algorithm 849: A concise sparse Cholesky factorization package. + ACM Trans. Math. Softw. 31, 4 (December 2005), 587–591. + https://doi.org/10.1145/1114268.1114277 - Kolodziej et al., (2019). The SuiteSparse Matrix Collection Website - Interface. Journal of Open Source Software, 4(35), 1244, - https://doi.org/10.21105/joss.01244 +* for ssget and the SuiteSparse Matrix Collection: - * for `spqr_rank`: + T. A. Davis and Yifan Hu. 2011. The University of Florida sparse matrix + collection. ACM Trans. Math. Softw. 38, 1, Article 1 (November 2011), 25 + pages. https://doi.org/10.1145/2049662.2049663 - Leslie V. Foster and T. A. Davis. 2013. Algorithm 933: Reliable - calculation of numerical rank, null space bases, pseudoinverse - solutions, and basic solutions using suitesparseQR. ACM Trans. Math. - Softw. 40, 1, Article 7 (September 2013), 23 pages. - https://doi.org/10.1145/2513109.2513116 + Kolodziej et al., (2019). The SuiteSparse Matrix Collection Website + Interface. Journal of Open Source Software, 4(35), 1244. + https://doi.org/10.21105/joss.01244 - * for Mongoose: +* for `spqr_rank`: - T. A. Davis, William W. Hager, Scott P. Kolodziej, and S. Nuri Yeralan. - 2020. Algorithm 1003: Mongoose, a Graph Coarsening and Partitioning - Library. ACM Trans. Math. Softw. 46, 1, Article 7 (March 2020), 18 - pages. - https://doi.org/10.1145/3337792 + Leslie V. Foster and T. A. Davis. 2013. Algorithm 933: Reliable calculation + of numerical rank, null space bases, pseudoinverse solutions, and basic + solutions using suitesparseQR. ACM Trans. Math. Softw. 40, 1, Article 7 + (September 2013), 23 pages. https://doi.org/10.1145/2513109.2513116 - * for SPEX: +* for Mongoose: - Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and T. A. - Davis. 2022. Algorithm 1021: SPEX Left LU, Exactly Solving Sparse - Linear Systems via a Sparse Left-Looking Integer-Preserving LU - Factorization. ACM Trans. Math. Softw. June 2022. - https://doi.org/10.1145/3519024 + T. A. Davis, William W. Hager, Scott P. Kolodziej, and S. Nuri Yeralan. + 2020. Algorithm 1003: Mongoose, a Graph Coarsening and Partitioning Library. + ACM Trans. Math. Softw. 46, 1, Article 7 (March 2020), 18 pages. + https://doi.org/10.1145/3337792 + +* for SPEX: + + Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and T. A. Davis. + 2022. Algorithm 1021: SPEX Left LU, Exactly Solving Sparse Linear Systems via + a Sparse Left-Looking Integer-Preserving LU Factorization. ACM Trans. Math. + Softw. June 2022. https://doi.org/10.1145/3519024 ----------------------------------------------------------------------------- About the BLAS and LAPACK libraries ----------------------------------------------------------------------------- -NOTE: Use of the Intel MKL BLAS is strongly recommended. In a 2019 test, -OpenBLAS caused result in severe performance degradation. The reason for this -is being investigated, and this may be resolved in the near future. +NOTE: if you use OpenBLAS, be sure to use version 0.3.27 or later. To select your BLAS/LAPACK, see the instructions in SuiteSparseBLAS.cmake in `SuiteSparse_config/cmake_modules`. If `SuiteSparse_config` finds a BLAS with @@ -234,15 +694,17 @@ To select your BLAS/LAPACK, see the instructions in SuiteSparseBLAS.cmake in `SuiteSparse_config.h` with the `SUITESPARSE_BLAS_INT` defined as `int64_t`. Otherwise, if a 32-bit BLAS is found, this type is defined as `int32_t`. If later on, UMFPACK, CHOLMOD, or SPQR are compiled and linked with a BLAS that -has a different integer size, you must override the definition with -DBLAS64 -(to assert the use of 64-bit integers in the BLAS) or -DBLAS32, (to assert the -use of 32-bit integers in the BLAS). +has a different integer size, you must override the definition with `-DBLAS64` +(to assert the use of 64-bit integers in the BLAS) or `-DBLAS32`, (to assert +the use of 32-bit integers in the BLAS). + +The size of the BLAS integer has nothing to do with `sizeof(void *)`. When distributed in a binary form (such as a Debian, Ubuntu, Spack, or Brew package), SuiteSparse should probably be compiled to expect a 32-bit BLAS, since this is the most common case. The default is to use a 32-bit BLAS, but -this can be changed in SuiteSparseBLAS.cmake or by compiling with -`-DALLOW_64BIT_BLAS=1`. +this can be changed by setting the cmake variable +`SUITESPARSE_USE_64BIT_BLAS` to `ON`. By default, SuiteSparse hunts for a suitable BLAS library. To enforce a particular BLAS library use either: @@ -251,263 +713,140 @@ particular BLAS library use either: cd Package ; cmake -DBLA_VENDOR=OpenBLAS .. make To use the default (hunt for a BLAS), do not set `BLA_VENDOR`, or set it to -ANY. In this case, if `ALLOW_64BIT_BLAS` is set, preference is given to a -64-bit BLAS, but a 32-bit BLAS library will be used if no 64-bit library is -found. +`ANY`. In this case, if `SUITESPARSE_USE_64BIT_BLAS` is ON, preference is +given to a 64-bit BLAS, but a 32-bit BLAS library will be used if no 64-bit +library is found. However, if both `SUITESPARSE_USE_64BIT_BLAS` and +`SUITESPARSE_USE_STRICT` are ON, then only a 64-bit BLAS is considered. -When selecting a particular BLAS library, the `ALLOW_64BIT_BLAS` setting is -strictly followed. If set to true, only a 64-bit BLAS library will be used. -If false (the default), only a 32-bit BLAS library will be used. If no such -BLAS is found, the build will fail. +When selecting a particular BLAS library, the `SUITESPARSE_USE_64BIT_BLAS` +setting is strictly followed. If set to true, only a 64-bit BLAS library will +be used. If false (the default), only a 32-bit BLAS library will be used. If +no such BLAS is found, the build will fail. ------------------- -SuiteSparse/README ------------------- +----------------------------------------------------------------------------- +QUICK START FOR THE C/C++ LIBRARIES: +----------------------------------------------------------------------------- -Packages in SuiteSparse, and files in this directory: +Type the following in this directory (requires system priviledge to do the +`sudo make install`): +``` + mkdir -p build && cd build + cmake .. + cmake --build . + sudo cmake --install . +``` + +All libraries will be created and installed into the default system-wide folder +(/usr/local/lib on Linux). All include files needed by the applications that +use SuiteSparse are installed into /usr/local/include/suitesparse (on Linux). + +To build only a subset of libraries, set `SUITESPARSE_ENABLE_PROJECTS` when +configuring with CMake. E.g., to build and install CHOLMOD and CXSparse +(including their dependencies), use the following commands: +``` + mkdir -p build && cd build + cmake -DSUITESPARSE_ENABLE_PROJECTS="cholmod;cxsparse" .. + cmake --build . + sudo cmake --install . +``` + +For Windows (MSVC), import the `CMakeLists.txt` file into MS Visual Studio. +Be sure to specify the build type as Release; for example, to build SuiteSparse +on Windows in the command window, run: +``` + mkdir -p build && cd build + cmake .. + cmake --build . --config Release + cmake --install . +``` - GraphBLAS graph algorithms in the language of linear algebra. - https://graphblas.org - author: Tim Davis - - SPEX solves sparse linear systems in exact arithmetic. - Requires the GNU GMP and MPRF libraries. - This will be soon replaced by a more general package, SPEX v3 - that includes this method (exact sparse LU) and others (sparse - exact Cholesky, and sparse exact update/downdate). The API - of v3 will be changing significantly. - - AMD approximate minimum degree ordering. This is the built-in AMD - function in MATLAB. - authors: Tim Davis, Patrick Amestoy, Iain Duff - - bin where programs are placed when compiled - - BTF permutation to block triangular form - authors: Tim Davis, Ekanathan Palamadai - - CAMD constrained approximate minimum degree ordering - authors: Tim Davis, Patrick Amestoy, Iain Duff, Yanqing Chen - - CCOLAMD constrained column approximate minimum degree ordering - authors: Tim Davis, Sivasankaran Rajamanickam, Stefan Larimore. - Algorithm design collaborators: Esmond Ng, John Gilbert - (for COLAMD) - - ChangeLog a summary of changes to SuiteSparse. See */Doc/ChangeLog - for details for each package. - - CHOLMOD sparse Cholesky factorization. Requires AMD, COLAMD, CCOLAMD, - the BLAS, and LAPACK. Optionally uses METIS. This is chol and - x=A\b in MATLAB. - author for all modules: Tim Davis - CHOLMOD/Modify module authors: Tim Davis and William W. Hager - - COLAMD column approximate minimum degree ordering. This is the - built-in COLAMD function in MATLAB. - authors (of the code): Tim Davis and Stefan Larimore - Algorithm design collaborators: Esmond Ng, John Gilbert - - Contents.m a list of contents for 'help SuiteSparse' in MATLAB. - - CSparse a concise sparse matrix package, developed for my - book, "Direct Methods for Sparse Linear Systems", - published by SIAM. Intended primarily for teaching. - Note that the code is (c) Tim Davis, as stated in the book. - For production, use CXSparse instead. In particular, both - CSparse and CXSparse have the same include filename: cs.h. - This package is used for the built-in DMPERM in MATLAB. - author: Tim Davis - - CXSparse CSparse Extended. Includes support for complex matrices - and both int or long integers. Use this instead of CSparse - for production use; it creates a libcsparse.so (or *dylib on - the Mac) with the same name as CSparse. It is a superset - of CSparse. Any code that links against CSparse should - also be able to link against CXSparse instead. - author: Tim Davis, David Bateman - - include 'make install' places user-visible include files for each - package here, after 'make local' - - KLU sparse LU factorization, primarily for circuit simulation. - Requires AMD, COLAMD, and BTF. Optionally uses CHOLMOD, - CAMD, CCOLAMD, and METIS. - authors: Tim Davis, Ekanathan Palamadai - - LDL a very concise LDL' factorization package - author: Tim Davis - - lib 'make install' places shared libraries for each package - here, after 'make local' - - Makefile to compile all of SuiteSparse - - make compiles SuiteSparse libraries. - Subsequent "make install" will install - in just CMAKE_INSTALL_PATH (defaults to - /usr/local/lib on Linux or Mac). - - make both compiles SuiteSparse, and then "make install" - will instal in both ./lib and - CMAKE_INSTALL_PATH). - - make local compiles SuiteSparse. - Subsequent "make install will install only - in ./lib, ./include only. - Does not install in CMAKE_INSTALL_PATH. - - make global compiles SuiteSparse libraries. - Subsequent "make install" will install in - just /usr/local/lib (or whatever your - CMAKE_INSTALL_PREFIX is). - Does not install in ./lib and ./include. - - make install installs in the current directory - (./lib, ./include), and/or in - /usr/local/lib and /usr/local/include, - depending on whether "make", "make local", - "make global", or "make both", - etc has been done. - - make uninstall undoes 'make install' - - make distclean removes all files not in distribution, including - ./bin, ./share, ./lib, and ./include. - - make purge same as 'make distclean' - - make clean removes all files not in distribution, but - keeps compiled libraries and demoes, ./lib, - ./share, and ./include. - - Each individual package also has each of the above 'make' - targets. - - Things you don't need to do: - make docs creates user guides from LaTeX files - make cov runs statement coverage tests (Linux only) - - MATLAB_Tools various m-files for use in MATLAB - author: Tim Davis (all parts) - for spqr_rank: author Les Foster and Tim Davis - - Contents.m list of contents - dimacs10 loads matrices for DIMACS10 collection - Factorize object-oriented x=A\b for MATLAB - find_components finds connected components in an image - GEE simple Gaussian elimination - getversion.m determine MATLAB version - gipper.m create MATLAB archive - hprintf.m print hyperlinks in command window - LINFACTOR predecessor to Factorize package - MESHND nested dissection ordering of regular meshes - pagerankdemo.m illustrates how PageRank works - SFMULT C=S*F where S is sparse and F is full - shellgui display a seashell - sparseinv sparse inverse subset - spok check if a sparse matrix is valid - spqr_rank SPQR_RANK package. MATLAB toolbox for rank - deficient sparse matrices: null spaces, - reliable factorizations, etc. With Leslie - Foster, San Jose State Univ. - SSMULT C=A*B where A and B are both sparse - SuiteSparseCollection for the SuiteSparse Matrix Collection - waitmex waitbar for use inside a mexFunction - - The SSMULT and SFMULT functions are the basis for the - built-in C=A*B functions in MATLAB. - - Mongoose graph partitioning. - authors: Nuri Yeralan, Scott Kolodziej, William Hager, Tim Davis - - CHOLMOD/SuiteSparse_metis: a modified version of METIS, embedded into - the CHOLMOD library. See the README.txt files - for details. author: George Karypis. This is a slightly - modified copy included with SuiteSparse via the open-source - license provided by George Karypis. SuiteSparse cannot use - an unmodified copy METIS. - - RBio read/write sparse matrices in Rutherford/Boeing format - author: Tim Davis - - README.txt this file - - SPQR sparse QR factorization. This the built-in qr and x=A\b in - MATLAB. Also called SuiteSparseQR. - author of the CPU code: Tim Davis - author of GPU modules: Tim Davis, Nuri Yeralan, - Wissam Sid-Lakhdar, Sanjay Ranka - - GPUQREngine: GPU support package for SPQR - (not built into MATLAB, however) - authors: Tim Davis, Nuri Yeralan, Sanjay Ranka, - Wissam Sid-Lakhdar - - SuiteSparse_config configuration file for all the above packages. - CSparse and MATLAB_Tools do not use SuiteSparse_config. - author: Tim Davis - - SuiteSparse_GPURuntime GPU support package for SPQR and CHOLMOD - (not builtin to MATLAB, however). - - SuiteSparse_install.m install SuiteSparse for MATLAB - SuiteSparse_paths.m set paths for SuiteSparse MATLAB mexFunctions - - SuiteSparse_test.m exhaustive test for SuiteSparse in MATLAB - - ssget MATLAB interface to the SuiteSparse Matrix Collection - author: Tim Davis - - UMFPACK sparse LU factorization. Requires AMD and the BLAS. - This is the built-in lu and x=A\b in MATLAB. - author: Tim Davis - algorithm design collaboration: Iain Duff - -Some codes optionally use METIS 5.1.0. This package is located in SuiteSparse -in the `CHOLMOD/SuiteSparse_metis` directory. Its use is optional. To compile -CHOLMOD without it, use the CMAKE_OPTIONS="-DNPARTITION=1" setting. The use of -METIS can improve ordering quality for some matrices, particularly large 3D -discretizations. METIS has been slightly modified for use in SuiteSparse; see -the `CHOLMOD/SuiteSparse_metis/README.txt` file for details. +Be sure to first install all required libraries: BLAS and LAPACK for UMFPACK, +CHOLMOD, and SPQR, and GMP and MPFR for SPEX. Be sure to use the latest +libraries; SPEX requires MPFR 4.0.2 and GMP 6.1.2 (these version numbers +do NOT correspond to the X.Y.Z suffix of libgmp.so.X.Y.Z and libmpfr.so.X.Y.Z; +see the SPEX user guide for details). -Refer to each package for license, copyright, and author information. All -codes are authored or co-authored by Timothy A. Davis (email: davis@tamu.edu), -except for METIS (by George Karypis), GraphBLAS/cpu_features (by Google), -GraphBLAS/lz4 and zstd (by Yann Collet, now at Facebook), and -GraphBLAS/CUDA/jitify.hpp (by NVIDIA). Parts of GraphBLAS/CUDA are -Copyright (c) by NVIDIA. Please refer to each of these licenses. +To compile the libraries and install them only in SuiteSparse/lib (not +/usr/local/lib), do this instead in the top-level of SuiteSparse: +``` + mkdir -p build && cd build + cmake -DCMAKE_INSTALL_PREFIX=.. .. + cmake --build . + cmake --install . +``` + +If you add /home/me/SuiteSparse/lib to your library search path +(`LD_LIBRARY_PATH` in Linux), you can do the following (for example): +``` + S = /home/me/SuiteSparse + cc myprogram.c -I$(S)/include/suitesparse -lumfpack -lamd -lcholmod -lsuitesparseconfig -lm +``` + +To change the C and C++ compilers, and to compile in parallel use: +``` + cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER==g++ .. +``` + +for example, which changes the compiler to gcc and g++. + +This will work on Linux/Unix and the Mac. It should automatically detect if +you have the Intel compilers or not, and whether or not you have CUDA. + +See `SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake` to select your BLAS. + +You may also need to add SuiteSparse/lib to your path. If your copy of +SuiteSparse is in /home/me/SuiteSparse, for example, then add this to your +`~/.bashrc` file: + +``` +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/SuiteSparse/lib +export LD_LIBRARY_PATH +``` -Licenses for each package are located in the following files, all in -PACKAGENAME/Doc/License.txt, and these files are also concatenated into -the top-level LICENSE.txt file. +For the Mac, use this instead: +``` +DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/home/me/SuiteSparse/lib +export DYLD_LIBRARY_PATH +``` + +Default install location of files is below, where PACKAGE is one of the +packages in SuiteSparse: + + * `CMAKE_INSTALL_PREFIX/include/suitesparse/`: include files + * `CMAKE_INSTALL_PREFIX/lib/`: compiled libraries + * `CMAKE_INSTALL_PREFIX/lib/cmake/SuiteSparse/`: `*.cmake` scripts + for all of SuiteSparse + * `CMAKE_INSTALL_PREFIX/lib/cmake/PACKAGE/`: `*Config.cmake` scripts for a + specific package + * `CMAKE_INSTALL_PREFIX/lib/pkgconfig/PACKAGE.pc`: `.pc` scripts for + a specific package pkgconfig ----------------------------------------------------------------------------- QUICK START FOR MATLAB USERS (Linux or Mac): ----------------------------------------------------------------------------- -Uncompress the SuiteSparse.zip or SuiteSparse.tar.gz archive file (they contain -the same thing). Suppose you place SuiteSparse in the /home/me/SuiteSparse -folder. - -Add the SuiteSparse/lib folder to your run-time library path. On Linux, add -this to your ~/.bashrc script, assuming /home/me/SuiteSparse is the location of -your copy of SuiteSparse: +Suppose you place SuiteSparse in the `/home/me/SuiteSparse` folder. +Add the `SuiteSparse/lib` folder to your run-time library path. On Linux, add +this to your `~/.bashrc` script, assuming `/home/me/SuiteSparse` is the +location of your copy of SuiteSparse: +``` LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/SuiteSparse/lib export LD_LIBRARY_PATH +``` -For the Mac, use this instead, in your ~/.zshrc script, assuming you place -SuiteSparse in /Users/me/SuiteSparse: - +For the Mac, use this instead, in your `~/.zshrc` script, assuming you place +SuiteSparse in `/Users/me/SuiteSparse`: +``` DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Users/me/SuiteSparse/lib export DYLD_LIBRARY_PATH +``` -Compile all of SuiteSparse with "make local". +Compile all of SuiteSparse with `make local`. Next, compile the GraphBLAS MATLAB library. In the system shell while in the -SuiteSparse folder, type "make gbmatlab" if you want to install it system-wide -with "make install", or "make gblocal" if you want to use the library in +SuiteSparse folder, type `make gbmatlab` if you want to install it system-wide +with `make install`, or `make gblocal` if you want to use the library in your own SuiteSparse/lib. Then in the MATLAB Command Window, cd to the SuiteSparse directory and type @@ -521,162 +860,360 @@ Documents/MATLAB/startup.m. You can also use the `SuiteSparse_paths` m-file to set all your paths at the start of each MATLAB session. ----------------------------------------------------------------------------- -QUICK START FOR THE C/C++ LIBRARIES: +Compilation options ----------------------------------------------------------------------------- -For Linux and Mac: type the following in this directory (requires system -priviledge to do the `sudo make install`): +You can set specific options for CMake with the command (for example): +``` + cmake -DCHOLMOD_PARTITION=OFF -DBUILD_STATIC_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug .. +``` - make - sudo make install +That command will compile all of SuiteSparse except for CHOLMOD/Partition +Module (because of `-DCHOLMOD_PARTITION=OFF`). Debug mode will be used (the +build type). The static libraries will not be built (since +`-DBUILD_STATIC_LIBS=OFF` is set). -All libraries will be created and copied into SuiteSparse/lib and into -/usr/local/lib. All include files need by the applications that use -SuiteSparse are copied into SuiteSparse/include and into /usr/local/include. +* `SUITESPARSE_ENABLE_PROJECTS`: -For Windows, import each `*/CMakeLists.txt` file into MS Visual Studio. + Semicolon separated list of projects to be built or `all`. + Default: `all` in which case the following projects are built: -Be sure to first install all required libraries: BLAS and LAPACK for UMFPACK, -CHOLMOD, and SPQR, and GMP and MPFR for SPEX. Be sure to use the latest -libraries; SPEX requires MPFR 4.0.2 and GMP 6.1.2 (these version numbers -do NOT correspond to the X.Y.Z suffix of libgmp.so.X.Y.Z and libmpfr.so.X.Y.Z; -see the SPEX user guide for details). + `suitesparse_config;mongoose;amd;btf;camd;ccolamd;colamd;cholmod;cxsparse;ldl;klu;umfpack;paru;rbio;spqr;spex;graphblas;lagraph` -To compile the libraries and install them only in SuiteSparse/lib (not -/usr/local/lib), do this instead in the top-level of SuiteSparse: + Additionally, `csparse` can be included in that list to build CSparse. - make local +* `CMAKE_BUILD_TYPE`: -If you add /home/me/SuiteSparse/lib to your library search path -(`LD_LIBRARY_PATH` in Linux), you can do the following (for example): + Default: `Release`, use `Debug` for debugging. - S = /home/me/SuiteSparse - cc myprogram.c -I$(S)/include -lumfpack -lamd -lcholmod -lsuitesparseconfig -lm +* `SUITESPARSE_USE_STRICT`: -To change the C and C++ compilers, and to compile in parallel use: + SuiteSparse has many user-definable settings of the form `SUITESPARSE_USE_*` + or `(package)_USE_*` for some particular package. In general, these settings + are not strict. For example, if `SUITESPARSE_USE_OPENMP` is `ON` then OpenMP + is preferred, but SuiteSparse can be used without OpenMP so no error is + generated if OpenMP is not found. However, if `SUITESPARSE_USE_STRICT` is + `ON` then all `*_USE_*` settings are treated strictly and an error occurs + if any are set to `ON` but the corresponding package or setting is not + available. The `*_USE_SYSTEM_*` settings are always treated as strict. + Default: `OFF`. - CC=gcc CX=g++ JOBS=32 make +* `SUITESPARSE_USE_CUDA`: -for example, which changes the compiler to gcc and g++, and runs make with -'make -j32', in parallel with 32 jobs. + If set to `ON`, CUDA is enabled for all of SuiteSparse. Default: `ON`, -This will work on Linux/Unix and the Mac. It should automatically detect if -you have the Intel compilers or not, and whether or not you have CUDA. + CUDA on Windows with MSVC appears to be working with this release, but it + should be considered as a prototype and may not be fully functional. I have + limited resources for testing CUDA on Windows. If you encounter issues, + disable CUDA and post this as an issue on GitHub. -NOTE: Use of the Intel MKL BLAS is strongly recommended. The OpenBLAS can -(rarely) result in severe performance degradation, in CHOLMOD in particular. -The reason for this is still under investigation and might already be resolved -in the current version of OpenBLAS. See -`SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake` to select your BLAS. +* `CHOLMOD_USE_CUDA`: -You may also need to add SuiteSparse/lib to your path. If your copy of -SuiteSparse is in /home/me/SuiteSparse, for example, then add this to your -~/.bashrc file: + Default: `ON`. Both `SUITESPARSE_USE_CUDA` and `CHOLMOD_USE_CUDA` must be + enabled to use CUDA in CHOLMOD. - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/SuiteSparse/lib - export LD_LIBRARY_PATH +* `SPQR_USE_CUDA`: -For the Mac, use this instead: + Default: `ON`. Both `SUITESPARSE_USE_CUDA` and `SPQR_USE_CUDA` must be + enabled to use CUDA in SPQR. - DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/home/me/SuiteSparse/lib - export DYLD_LIBRARY_PATH +* `CMAKE_INSTALL_PREFIX`: ------------------------------------------------------------------------------ -Python interface ------------------------------------------------------------------------------ + Defines the install location (default on Linux is `/usr/local`). For example, + this command while in a folder `build` in the top level SuiteSparse folder + will set the install directory to `/stuff`, used by the subsequent + `sudo cmake --install .`: +``` + cmake -DCMAKE_INSTALL_PREFIX=/stuff .. + sudo cmake --install . +``` -See scikit-sparse and scikit-umfpack for the Python interface via SciPy: +* `SUITESPARSE_PKGFILEDIR`: -https://github.com/scikit-sparse/scikit-sparse + Directory where CMake Config and pkg-config files will be installed. By + default, CMake Config files will be installed in the subfolder `cmake` of the + directory where the (static) libraries will be installed (e.g., `lib`). The + `.pc` files for pkg-config will be installed in the subfolder `pkgconfig` of + the directory where the (static) libraries will be installed. -https://github.com/scikit-umfpack/scikit-umfpack + This option allows to install them at a location different from the (static) + libraries. This allows to install multiple configurations of the SuiteSparse + libraries at the same time (e.g., by also setting a different + `CMAKE_RELEASE_POSTFIX` and `CMAKE_INSTALL_LIBDIR` for each of them). To pick + up the respective configuration in downstream projects, set, e.g., + `CMAKE_PREFIX_PATH` (for CMake) or `PKG_CONFIG_PATH` (for build systems using + pkg-config) to the path containing the respective CMake Config files or + pkg-config files. + +* `SUITESPARSE_INCLUDEDIR_POSTFIX`: + + Postfix for installation target of header from SuiteSparse. Default: + suitesparse, so the default include directory is: + `CMAKE_INSTALL_PREFIX/include/suitesparse` + +* `BUILD_SHARED_LIBS`: + + If `ON`, shared libraries are built. + Default: `ON`. + +* `BUILD_STATIC_LIBS`: + + If `ON`, static libraries are built. + Default: `ON`, except for GraphBLAS, which takes a long time to compile so + the default for GraphBLAS is `OFF` unless `BUILD_SHARED_LIBS` is `OFF`. + +* `SUITESPARSE_CUDA_ARCHITECTURES`: + + A string, such as `"all"` or `"35;50;75;80"` that lists the CUDA + architectures to use when compiling CUDA kernels with `nvcc`. The `"all"` + option requires CMake 3.23 or later. Default: `"52;75;80"`. + +* `BLA_VENDOR`: + + A string. Leave unset, or use `"ANY"` to select any BLAS library (the + default). Or set to the name of a `BLA_VENDOR` defined by FindBLAS.cmake. + See: + https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors + +* `SUITESPARSE_USE_64BIT_BLAS`: + + If `ON`, look for a 64-bit BLAS. If `OFF`: 32-bit only. Default: `OFF`. + +* `SUITESPARSE_USE_OPENMP`: + + If `ON`, OpenMP is used by default if it is available. Default: `ON`. + + GraphBLAS, LAGraph, and ParU will be vastly slower if OpenMP is not used. + CHOLMOD will be somewhat slower without OpenMP (as long as it still has a + parallel BLAS/LAPACK). Three packages (UMFPACK, CHOLMOD, and SPQR) rely + heavily on parallel BLAS/LAPACK libraries and those libraries may use OpenMP + internally. If you wish to disable OpenMP in an entire application, select a + single-threaded BLAS/LAPACK, or a parallel BLAS/LAPACK that does not use + OpenMP (such as the Apple Accelerate Framework). Using a single-threaded + BLAS/LAPACK library will cause UMFPACK, CHOLMOD, and SPQR to be vastly + slower. + + WARNING: GraphBLAS may not be thread-safe if built without OpenMP or pthreads + (see the GraphBLAS User Guide for details). + +* `SUITESPARSE_CONFIG_USE_OPENMP`: + + If `ON`, `SuiteSparse_config` uses OpenMP if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + It is not essential and only used to let `SuiteSparse_time` call + `omp_get_wtime`. + +* `CHOLMOD_USE_OPENMP`: + + If `ON`, OpenMP is used in CHOLMOD if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `GRAPHBLAS_USE_OPENMP`: + + If `ON`, OpenMP is used in GraphBLAS if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `LAGRAPH_USE_OPENMP`: + + If `ON`, OpenMP is used in LAGraph if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `PARU_USE_OPENMP`: + + If `ON`, OpenMP is used in ParU if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `SUITESPARSE_DEMOS`: + + If `ON`, build the demo programs for each package. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_BTF`: + + If `ON`, use BTF libraries installed on the build system. If `OFF`, + automatically build BTF as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_CHOLMOD`: + + If `ON`, use CHOLMOD libraries installed on the build system. If `OFF`, + automatically build CHOLMOD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_AMD`: + + If `ON`, use AMD libraries installed on the build system. If `OFF`, + automatically build AMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_COLAMD`: + + If `ON`, use COLAMD libraries installed on the build system. If `OFF`, + automatically build COLAMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_CAMD`: + + If `ON`, use CAMD libraries installed on the build system. If `OFF`, + automatically build CAMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_CCOLAMD`: + + If `ON`, use CCOLAMD libraries installed on the build system. If `OFF`, + automatically build CCOLAMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_GRAPHBLAS`: + + If `ON`, use GraphBLAS libraries installed on the build system. If `OFF`, + automatically build GraphBLAS as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_SUITESPARSE_CONFIG`: + + If `ON`, use `SuiteSparse_config` libraries installed on the build system. If + `OFF`, automatically build `SuiteSparse_config` as dependency if needed. + Default: `OFF`. + +* `SUITESPARSE_USE_FORTRAN` + + If `ON`, use the Fortran compiler to determine how C calls Fortan, and to + build several optional Fortran routines. If `OFF`, use + `SUITESPARSE_C_TO_FORTRAN` to define how C calls Fortran (see + `SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake` for details). + Default: `ON`. + +Additional options are available for specific packages: + +* `UMFPACK_USE_CHOLMOD`: + + If `ON`, UMFPACK uses CHOLMOD for additional (optional) + ordering options. Default: `ON`. + +* `KLU_USE_CHOLMOD`: + + If `ON`, KLU uses CHOLMOD for additional (optional) + ordering options. Default: `ON`. + +CHOLMOD is composed of a set of Modules that can be independently selected; +all options default to `ON`: + +* `CHOLMOD_GPL` + + If `OFF`, do not build any GPL-licensed module (MatrixOps, Modify, Supernodal, + and GPU modules) + +* `CHOLMOD_CHECK` + + If `OFF`, do not build the Check module. + +* `CHOLMOD_MATRIXOPS` + + If `OFF`, do not build the MatrixOps module. + +* `CHOLMOD_CHOLESKY` + If `OFF`, do not build the Cholesky module. This also disables the Supernodal + and Modify modules. + +* `CHOLMOD_MODIFY` + + If `OFF`, do not build the Modify module. + +* `CHOLMOD_CAMD` + + If `OFF`, do not link against CAMD and CCOLAMD. This also disables the + Partition module. + +* `CHOLMOD_PARTITION` + + If `OFF`, do not build the Partition module. + +* `CHOLMOD_SUPERNODAL` + + If `OFF`, do not build the Supernodal module. ----------------------------------------------------------------------------- -Compilation options +Possible build/install issues ----------------------------------------------------------------------------- -You can set specific options for CMake with the command (for example): +One common issue can affect all packages: getting the right #include files +that match the current libraries being built. It's possible that your Linux +distro has an older copy of SuiteSparse headers in /usr/include or +/usr/local/include, or that Homebrew has installed its suite-sparse bundle into +/opt/homebrew/include or other places. Old libraries can appear in in +/usr/local/lib, /usr/lib, etc. When building a new copy of SuiteSparse, the +cmake build system is normally (or always?) able to avoid these, and use the +right header for the right version of each library. + +As an additional guard against this possible error, each time one SuiteSparse +package #include's a header from another one, it checks the version number in +the header file, and reports an #error to the compiler if a stale version is +detected. In addition, the Example package checks both the header version and +the library version (by calling a function in each library). If the versions +mismatch in any way, the Example package reports an error at run time. + +For example, CHOLMOD 5.1.0 requires AMD 3.3.0 or later. If it detects an +older one in `amd.h`, it will report an `#error`: + +``` + #include "amd.h" + #if ( ... AMD version is stale ... ) + #error "CHOLMOD 5.1.0 requires AMD 3.3.0 or later" + #endif +``` + +and the compilation will fail. The Example package makes another check, +by calling `amd_version` and comparing it with the versions from the `amd.h` +header file. + +If this error or one like it occurs, check to see if you have an old copy of +SuiteSparse, and uninstall it before compiling your new copy of SuiteSparse. + +There are other many possible build/install issues that are covered by the +corresponding user guides for each package, such as finding the right BLAS, +OpenMP, and other libraries, and how to compile on the Mac when using GraphBLAS +inside MATLAB, and so on. Refer to the User Guides for more details. - CMAKE_OPTIONS="-DNPARTITION=1 -DNSTATIC=1 -DCMAKE_BUILD_TYPE=Debug" make +----------------------------------------------------------------------------- +Interfaces to SuiteSparse +----------------------------------------------------------------------------- -That command will compile all of SuiteSparse except for CHOLMOD/Partition -Module. Debug mode will be used. The static libraries will not be built -(NSTATIC is true). - - CMAKE_BUILD_TYPE: Default: "Release", use "Debug" for debugging. - - ENABLE_CUDA: if set to true, CUDA is enabled for the project. - Default: true for CHOLMOD and SPQR; false otherwise - - LOCAL_INSTALL: if true, "cmake --install" will install - into SuiteSparse/lib and SuiteSparse/include. - if false, "cmake --install" will install into the - default prefix (or the one configured with - CMAKE_INSTALL_PREFIX). - Default: false - - NSTATIC: if true, static libraries are not built. - Default: false, except for GraphBLAS, which - takes a long time to compile so the default for - GraphBLAS is true. For Mongoose, the NSTATIC setting - is treated as if it always false, since the mongoose - program is built with the static library. - - SUITESPARSE_CUDA_ARCHITECTURES: a string, such as "all" or - "35;50;75;80" that lists the CUDA architectures to use - when compiling CUDA kernels with nvcc. The "all" - option requires cmake 3.23 or later. - Default: "52;75;80". - - BLA_VENDOR a string. Leave unset, or use "ANY" to select any BLAS - library (the default). Or set to the name of a - BLA_VENDOR defined by FindBLAS.cmake. See: - https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors - - ALLOW_64BIT_BLAS if true: look for a 64-bit BLAS. If false: 32-bit only. - Default: false. - - NOPENMP if true: OpenMP is not used. Default: false. - UMFPACK, CHOLMOD, SPQR, and GraphBLAS will be slow. - Note that BLAS and LAPACK may still use OpenMP - internally; if you wish to disable OpenMP in an entire - application, select a single-threaded BLAS/LAPACK. - WARNING: GraphBLAS may not be thread-safe if built - without OpenMP (see the User Guide for details). - - DEMO if true: build the demo programs for each package. - Default: false. - -Additional options are available within specific packages: - - NCHOLMOD if true, UMFPACK and KLU do not use CHOLMOD for - additional (optional) ordering options +MATLAB/Octave/R/Mathematica interfaces: -CHOLMOD is composed of a set of Modules that can be independently selected; -all options default to false: - - NGL if true: do not build any GPL-licensed module - (MatrixOps, Modify, Supernodal, and GPU modules) - NCHECK if true: do not build the Check module. - NMATRIXOPS if true: do not build the MatrixOps module. - NCHOLESKY if true: do not build the Cholesky module. - This also disables the Supernodal and Modify modules. - NMODIFY if true: do not build the Modify module. - NCAMD if true: do not link against CAMD and CCOLAMD. - This also disables the Partition module. - NPARTITION if true: do not build the Partition module. - NSUPERNODAL if true: do not build the Supernodal module. + Many built-in methods in MATLAB and Octave rely on SuiteSparse, including + `C=A*B` `x=A\b`, `L=chol(A)`, `[L,U,P,Q]=lu(A)`, `R=qr(A)`, `dmperm(A)`, + `p=amd(A)`, `p=colamd(A)`, ... + See also Mathematica, R, and many many more. The list is too long. + +Julia interface: + + https://github.com/JuliaSparse/SparseArrays.jl + +python interface to GraphBLAS by Anaconda and NVIDIA: + + https://pypi.org/project/python-graphblas + +Intel's Go interface to GraphBLAS: + + https://pkg.go.dev/github.com/intel/forGraphBLASGo + +See scikit-sparse and scikit-umfpack for the Python interface via SciPy: + + https://github.com/scikit-sparse/scikit-sparse + https://github.com/scikit-umfpack/scikit-umfpack + +See russell for a Rust interface: + + https://github.com/cpmech/russell ----------------------------------------------------------------------------- Acknowledgements ----------------------------------------------------------------------------- -I would like to thank François Bissey, Sebastien Villemot, Erik Welch, Jim -Kitchen, Markus Mützel, and Fabian Wein for their valuable feedback on the +Markus Mützel contributed the most recent update of the SuiteSparse build +system for all SuiteSparse packages, extensively porting it and modernizing it. + +I would also like to thank François Bissey, Sebastien Villemot, Erik Welch, Jim +Kitchen, and Fabian Wein for their valuable feedback on the SuiteSparse build system and how it works with various Linux / Python distros and other package managers. If you are a maintainer of a SuiteSparse packaging for a Linux distro, conda-forge, R, spack, brew, vcpkg, etc, please feel free to contact me if there's anything I can do to make your life easier. +I would also like to thank Raye Kimmerer for adding support for 32-bit +row/column indices in SPQR v4.2.0. See also the various Acknowledgements within each package. diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/CMakeLists.txt b/ThirdParty/SuiteSparse/SuiteSparse_config/CMakeLists.txt index 3c25382368..8e5c119b54 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/CMakeLists.txt +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/CMakeLists.txt @@ -10,30 +10,42 @@ # get the version #------------------------------------------------------------------------------- -# cmake 3.22 is required to find the BLAS +# cmake 3.22 is required to find BLAS/LAPACK for UMFPACK, CHOLMOD, SPQR, +# and ParU: cmake_minimum_required ( VERSION 3.22 ) # version of both SuiteSparse and SuiteSparse_config -set ( SUITESPARSE_DATE "Jan 20, 2023" ) +set ( SUITESPARSE_DATE "Jan 20, 2024" ) set ( SUITESPARSE_VERSION_MAJOR 7 ) -set ( SUITESPARSE_VERSION_MINOR 0 ) -set ( SUITESPARSE_VERSION_SUB 1 ) +set ( SUITESPARSE_VERSION_MINOR 6 ) +set ( SUITESPARSE_VERSION_SUB 0 ) +set ( SUITESPARSE_CONFIG_VERSION_MAJOR ${SUITESPARSE_VERSION_MAJOR} CACHE STRING "" FORCE ) +set ( SUITESPARSE_CONFIG_VERSION_MINOR ${SUITESPARSE_VERSION_MINOR} CACHE STRING "" FORCE ) +set ( SUITESPARSE_CONFIG_VERSION_PATCH ${SUITESPARSE_VERSION_SUB} CACHE STRING "" FORCE ) message ( STATUS "Building SuiteSparse_config version: v" ${SUITESPARSE_VERSION_MAJOR}. ${SUITESPARSE_VERSION_MINOR}. ${SUITESPARSE_VERSION_SUB} " (" ${SUITESPARSE_DATE} ")" ) +#------------------------------------------------------------------------------- +# define the project +#------------------------------------------------------------------------------- + +project ( SuiteSparseConfig + VERSION "${SUITESPARSE_VERSION_MAJOR}.${SUITESPARSE_VERSION_MINOR}.${SUITESPARSE_VERSION_SUB}" + LANGUAGES C ) + #------------------------------------------------------------------------------- # SuiteSparse policies #------------------------------------------------------------------------------- set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} - ${CMAKE_SOURCE_DIR}/cmake_modules ) + ${PROJECT_SOURCE_DIR}/cmake_modules ) include ( SuiteSparsePolicy ) -if ( NOT NFORTRAN ) +if ( SUITESPARSE_HAS_FORTRAN ) include ( FortranCInterface ) else ( ) # No Fortran compiler available or enabled, configuration is not automatic. @@ -41,30 +53,74 @@ else ( ) set ( FortranCInterface_GLOBAL__MACRO ${SUITESPARSE_C_TO_FORTRAN} ) endif ( ) +message ( STATUS "C to Fortran calling protocol: ") +message ( STATUS " SUITESPARSE_HAS_FORTRAN : ${SUITESPARSE_HAS_FORTRAN}" ) +message ( STATUS " FortranCInterface_GLOBAL_MACRO : ${FortranCInterface_GLOBAL_MACRO}" ) +message ( STATUS " FortranCInterface_GLOBAL__MACRO : ${FortranCInterface_GLOBAL__MACRO}" ) + #------------------------------------------------------------------------------- -# define the project +# CUDA warning on Windows with MSVC #------------------------------------------------------------------------------- -project ( suitesparseconfig - VERSION "${SUITESPARSE_VERSION_MAJOR}.${SUITESPARSE_VERSION_MINOR}.${SUITESPARSE_VERSION_SUB}" - LANGUAGES C ) +if ( SUITESPARSE_HAS_CUDA AND MSVC ) + message ( WARNING "NOTE: CUDA on MSVC has only recently been revised. It appears to be functional but has not been as rigorously tested as I would like (I have limited resources for testing CUDA on Windows). If you encounter issues, set the cmake option SUITESPARSE_USE_CUDA to OFF and post an issue on GitHub." ) +endif ( ) #------------------------------------------------------------------------------- -# find library dependencies +# find OpenMP #------------------------------------------------------------------------------- -option ( NOPENMP "ON: do not use OpenMP. OFF (default): use OpenMP" off ) -if ( NOPENMP ) +option ( SUITESPARSE_CONFIG_USE_OPENMP "ON: Use OpenMP in SuiteSparse_config if available. OFF: Do not use OpenMP. (Default: SUITESPARSE_USE_OPENMP)" ${SUITESPARSE_USE_OPENMP} ) +if ( SUITESPARSE_CONFIG_USE_OPENMP ) + if ( CMAKE_VERSION VERSION_LESS 3.24 ) + find_package ( OpenMP COMPONENTS C ) + else ( ) + find_package ( OpenMP COMPONENTS C GLOBAL ) + endif ( ) +else ( ) # OpenMP has been disabled - message ( STATUS "OpenMP disabled" ) - set ( OPENMP_FOUND false ) + set ( OpenMP_C_FOUND OFF ) +endif ( ) + +if ( SUITESPARSE_CONFIG_USE_OPENMP AND OpenMP_C_FOUND ) + set ( SUITESPARSE_CONFIG_HAS_OPENMP ON ) else ( ) - find_package ( OpenMP ) + set ( SUITESPARSE_CONFIG_HAS_OPENMP OFF ) endif ( ) +message ( STATUS "SuiteSparse_config has OpenMP: ${SUITESPARSE_CONFIG_HAS_OPENMP}" ) -# AMICI -# include ( SuiteSparseBLAS ) -set(SuiteSparse_BLAS_integer int64_t) +# check for strict usage +if ( SUITESPARSE_USE_STRICT AND SUITESPARSE_CONFIG_USE_OPENMP AND NOT SUITESPARSE_CONFIG_HAS_OPENMP ) + message ( FATAL_ERROR "OpenMP required for SuiteSparse_config but not found" ) +endif ( ) + +# check for librt in case of fallback to "clock_gettime" +include ( CheckSymbolExists ) +check_symbol_exists ( clock_gettime "time.h" NO_RT ) +if ( NO_RT ) + message ( STATUS "Using clock_gettime without librt" ) + set ( SUITESPARSE_HAVE_CLOCK_GETTIME ON ) +else ( ) + # check if we need to link to librt for that function + set ( _orig_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ) + list ( APPEND CMAKE_REQUIRED_LIBRARIES "rt" ) + check_symbol_exists ( clock_gettime "time.h" WITH_RT ) + set ( CMAKE_REQUIRED_LIBRARIES ${_orig_CMAKE_REQUIRED_LIBRARIES} ) + if ( WITH_RT ) + message ( STATUS "Using clock_gettime with librt" ) + set ( SUITESPARSE_HAVE_CLOCK_GETTIME ON ) + endif ( ) +endif ( ) + +if ( NOT SUITESPARSE_CONFIG_USE_OPENMP AND NOT SUITESPARSE_HAVE_CLOCK_GETTIME ) + message ( STATUS "No OpenMP and no clock_gettime available. Timing functions won't work." ) +endif ( ) + +#------------------------------------------------------------------------------- +# find the BLAS +#------------------------------------------------------------------------------- + +include ( SuiteSparseBLAS ) #------------------------------------------------------------------------------- # configure files @@ -79,36 +135,57 @@ configure_file ( "Config/README.md.in" NEWLINE_STYLE LF ) #------------------------------------------------------------------------------- -# dynamic suitesparseconfig library properties +# dynamic SuiteSparseConfig library properties #------------------------------------------------------------------------------- file ( GLOB SUITESPARSECONFIG_SOURCES "*.c" ) -add_library ( suitesparseconfig SHARED ${SUITESPARSECONFIG_SOURCES} ) -set_target_properties ( suitesparseconfig PROPERTIES - VERSION ${SUITESPARSE_VERSION_MAJOR}.${SUITESPARSE_VERSION_MINOR}.${SUITESPARSE_VERSION_SUB} - C_STANDARD_REQUIRED 11 - SOVERSION ${SUITESPARSE_VERSION_MAJOR} - PUBLIC_HEADER "SuiteSparse_config.h" - WINDOWS_EXPORT_ALL_SYMBOLS ON ) +if ( BUILD_SHARED_LIBS ) + add_library ( SuiteSparseConfig SHARED ${SUITESPARSECONFIG_SOURCES} ) + + set_target_properties ( SuiteSparseConfig PROPERTIES + VERSION ${SUITESPARSE_VERSION_MAJOR}.${SUITESPARSE_VERSION_MINOR}.${SUITESPARSE_VERSION_SUB} + C_STANDARD 11 + C_STANDARD_REQUIRED ON + OUTPUT_NAME suitesparseconfig + SOVERSION ${SUITESPARSE_VERSION_MAJOR} + PUBLIC_HEADER "SuiteSparse_config.h" + WINDOWS_EXPORT_ALL_SYMBOLS ON ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( SuiteSparseConfig PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( SuiteSparseConfig + INTERFACE $ + $ ) +endif ( ) #------------------------------------------------------------------------------- -# static suitesparseconfig library properties +# static SuiteSparseConfig library properties #------------------------------------------------------------------------------- -if ( NOT NSTATIC ) - add_library ( suitesparseconfig_static STATIC ${SUITESPARSECONFIG_SOURCES} ) +if ( BUILD_STATIC_LIBS ) + add_library ( SuiteSparseConfig_static STATIC ${SUITESPARSECONFIG_SOURCES} ) - set_target_properties ( suitesparseconfig_static PROPERTIES - VERSION ${SUITESPARSE_VERSION_MAJOR}.${SUITESPARSE_VERSION_MINOR}.${SUITESPARSE_VERSION_SUB} - C_STANDARD_REQUIRED 11 + set_target_properties ( SuiteSparseConfig_static PROPERTIES + C_STANDARD 11 + C_STANDARD_REQUIRED ON OUTPUT_NAME suitesparseconfig - SOVERSION ${SUITESPARSE_VERSION_MAJOR} ) + PUBLIC_HEADER "SuiteSparse_config.h" ) if ( MSVC ) - set_target_properties ( suitesparseconfig_static PROPERTIES + set_target_properties ( SuiteSparseConfig_static PROPERTIES OUTPUT_NAME suitesparseconfig_static ) endif ( ) + + if ( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25" ) + set_target_properties ( SuiteSparseConfig_static PROPERTIES EXPORT_NO_SYSTEM ON ) + endif ( ) + + target_include_directories ( SuiteSparseConfig_static + INTERFACE $ + $ ) endif ( ) #------------------------------------------------------------------------------- @@ -116,24 +193,45 @@ endif ( ) #------------------------------------------------------------------------------- # libm: -if ( NOT WIN32 ) - target_link_libraries ( suitesparseconfig PUBLIC m ) - if ( NOT NSTATIC ) - target_link_libraries ( suitesparseconfig_static PUBLIC m ) +include ( CheckSymbolExists ) +check_symbol_exists ( fmax "math.h" NO_LIBM ) +if ( NOT NO_LIBM ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( SuiteSparseConfig PRIVATE m ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + target_link_libraries ( SuiteSparseConfig_static PUBLIC m ) + list ( APPEND SUITESPARSE_CONFIG_STATIC_LIBS "m" ) endif ( ) endif ( ) # OpenMP: -if ( OPENMP_FOUND ) +if ( SUITESPARSE_CONFIG_HAS_OPENMP ) message ( STATUS "OpenMP C libraries: ${OpenMP_C_LIBRARIES} ") message ( STATUS "OpenMP C include: ${OpenMP_C_INCLUDE_DIRS} ") message ( STATUS "OpenMP C flags: ${OpenMP_C_FLAGS} ") - target_link_libraries ( suitesparseconfig PUBLIC ${OpenMP_C_LIBRARIES} ) - if ( NOT NSTATIC ) - target_link_libraries ( suitesparseconfig_static PUBLIC ${OpenMP_C_LIBRARIES} ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( SuiteSparseConfig PRIVATE OpenMP::OpenMP_C ) + target_include_directories ( SuiteSparseConfig SYSTEM AFTER INTERFACE + "$" ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + target_link_libraries ( SuiteSparseConfig_static PRIVATE OpenMP::OpenMP_C ) + target_include_directories ( SuiteSparseConfig_static SYSTEM AFTER INTERFACE + "$" ) + list ( APPEND SUITESPARSE_CONFIG_STATIC_LIBS ${OpenMP_C_LIBRARIES} ) + endif ( ) +else ( ) + # librt + if ( WITH_RT ) + if ( BUILD_SHARED_LIBS ) + target_link_libraries ( SuiteSparseConfig PRIVATE "rt" ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + target_link_libraries ( SuiteSparseConfig_static PRIVATE "rt" ) + list ( APPEND SUITESPARSE_CONFIG_STATIC_LIBS "rt" ) + endif ( ) endif ( ) - set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS} " ) - include_directories ( ${OpenMP_C_INCLUDE_DIRS} ) endif ( ) # BLAS: @@ -147,23 +245,123 @@ if ( BLAS_FOUND ) endif ( ) #------------------------------------------------------------------------------- -# suitesparseconfig installation location +# SuiteSparseConfig installation location #------------------------------------------------------------------------------- +include ( CMakePackageConfigHelpers ) + file ( GLOB SUITESPARSE_CMAKE_MODULES "cmake_modules/*" ) -install ( TARGETS suitesparseconfig - LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} - RUNTIME DESTINATION ${SUITESPARSE_BINDIR} - PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +if ( BUILD_SHARED_LIBS ) + install ( TARGETS SuiteSparseConfig + EXPORT SuiteSparse_configTargets + LIBRARY DESTINATION ${SUITESPARSE_LIBDIR} + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + RUNTIME DESTINATION ${SUITESPARSE_BINDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + install ( TARGETS SuiteSparseConfig_static + EXPORT SuiteSparse_configTargets + ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} + PUBLIC_HEADER DESTINATION ${SUITESPARSE_INCLUDEDIR} ) +endif ( ) install ( FILES ${SUITESPARSE_CMAKE_MODULES} - DESTINATION ${SUITESPARSE_LIBDIR}/cmake/SuiteSparse + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/SuiteSparse COMPONENT Development ) -if ( NOT NSTATIC ) - install ( TARGETS suitesparseconfig_static - ARCHIVE DESTINATION ${SUITESPARSE_LIBDIR} ) + +# create (temporary) export target file during build +export ( EXPORT SuiteSparse_configTargets + NAMESPACE SuiteSparse:: + FILE ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_configTargets.cmake ) + +# install export target and config for find_package +install ( EXPORT SuiteSparse_configTargets + NAMESPACE SuiteSparse:: + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/SuiteSparse_config ) + +configure_package_config_file ( + Config/SuiteSparse_configConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_configConfig.cmake + INSTALL_DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/SuiteSparse_config ) + +write_basic_package_version_file ( + ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_configConfigVersion.cmake + COMPATIBILITY SameMajorVersion ) + +install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_configConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_configConfigVersion.cmake + DESTINATION ${SUITESPARSE_PKGFILEDIR}/cmake/SuiteSparse_config ) + +#------------------------------------------------------------------------------- +# create pkg-config file +#------------------------------------------------------------------------------- + +if ( NOT MSVC ) + # This might be something like: + # /usr/lib/libgomp.so;/usr/lib/libpthread.a;m + # convert to -l flags for pkg-config, i.e.: "-lgomp -lpthread -lm" + set ( SUITESPARSE_CONFIG_STATIC_LIBS_LIST ${SUITESPARSE_CONFIG_STATIC_LIBS} ) + set ( SUITESPARSE_CONFIG_STATIC_LIBS "" ) + foreach ( _lib ${SUITESPARSE_CONFIG_STATIC_LIBS_LIST} ) + string ( FIND ${_lib} "." _pos REVERSE ) + if ( ${_pos} EQUAL "-1" ) + set ( SUITESPARSE_CONFIG_STATIC_LIBS "${SUITESPARSE_CONFIG_STATIC_LIBS} -l${_lib}" ) + continue () + endif ( ) + set ( _kinds "SHARED" "STATIC" ) + if ( WIN32 ) + list ( PREPEND _kinds "IMPORT" ) + endif ( ) + foreach ( _kind IN LISTS _kinds ) + set ( _regex ".*\\/(lib)?([^\\.]*)(${CMAKE_${_kind}_LIBRARY_SUFFIX})" ) + if ( ${_lib} MATCHES ${_regex} ) + string ( REGEX REPLACE ${_regex} "\\2" _libname ${_lib} ) + if ( NOT "${_libname}" STREQUAL "" ) + set ( SUITESPARSE_CONFIG_STATIC_LIBS "${SUITESPARSE_CONFIG_STATIC_LIBS} -l${_libname}" ) + break () + endif ( ) + endif ( ) + endforeach ( ) + endforeach ( ) + + set ( prefix "${CMAKE_INSTALL_PREFIX}" ) + set ( exec_prefix "\${prefix}" ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_LIBDIR SUITESPARSE_LIBDIR_IS_ABSOLUTE ) + if (SUITESPARSE_LIBDIR_IS_ABSOLUTE) + set ( libdir "${SUITESPARSE_LIBDIR}") + else ( ) + set ( libdir "\${exec_prefix}/${SUITESPARSE_LIBDIR}") + endif ( ) + cmake_path ( IS_ABSOLUTE SUITESPARSE_INCLUDEDIR SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE ) + if (SUITESPARSE_INCLUDEDIR_IS_ABSOLUTE) + set ( includedir "${SUITESPARSE_INCLUDEDIR}") + else ( ) + set ( includedir "\${prefix}/${SUITESPARSE_INCLUDEDIR}") + endif ( ) + if ( BUILD_SHARED_LIBS ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $ ) + endif ( ) + configure_file ( + Config/SuiteSparse_config.pc.in + SuiteSparse_config.pc.out + @ONLY + NEWLINE_STYLE LF ) + file ( GENERATE + OUTPUT SuiteSparse_config.pc + INPUT ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_config.pc.out + NEWLINE_STYLE LF ) + install ( FILES + ${CMAKE_CURRENT_BINARY_DIR}/SuiteSparse_config.pc + DESTINATION ${SUITESPARSE_PKGFILEDIR}/pkgconfig ) endif ( ) +#------------------------------------------------------------------------------- +# report status +#------------------------------------------------------------------------------- + include ( SuiteSparseReport ) diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/Config/README.md.in b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/README.md.in index e45ae9c08d..bc0c9142fa 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/Config/README.md.in +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/README.md.in @@ -9,11 +9,41 @@ by Tim Davis, available at https://github.com/DrTimothyAldenDavis/SuiteSparse . Primary author of SuiteSparse (codes and algorithms, excl. METIS): Tim Davis -Code co-authors, in alphabetical order (not including METIS): - Patrick Amestoy, David Bateman, Jinhao Chen, Yanqing Chen, Iain Duff, - Les Foster, William Hager, Scott Kolodziej, Chris Lourenco, Stefan - Larimore, Erick Moreno-Centeno, Ekanathan Palamadai, Sivasankaran - Rajamanickam, Sanjay Ranka, Wissam Sid-Lakhdar, Nuri Yeralan. +Code co-authors, in alphabetical order (not including METIS or LAGraph): + Patrick Amestoy, Mohsen Aznaveh, David Bateman, Jinhao Chen, Yanqing Chen, + Iain Duff, Joe Eaton, Les Foster, William Hager, Raye Kimmerer, Scott + Kolodziej, Chris Lourenco, Stefan Larimore, Lorena Mejia Domenzain, Erick + Moreno-Centeno, Markus Mützel, Corey Nolel, Ekanathan Palamadai, + Sivasankaran Rajamanickam, Sanjay Ranka, Wissam Sid-Lakhdar, and + Nuri Yeralan. + +LAGraph has been developed by the highest number of developers of any of +the packages in SuiteSparse and deserves its own list. The list also +appears in LAGraph/Contibutors.txt: + + Janos B. Antal, Budapest University of Technology and Economics, Hungary + Mohsen Aznaveh, Texas A&M University + David A. Bader New Jersey Institute of Technology + Aydin Buluc, Lawrence Berkeley National Lab + Jinhao Chen, Texas A&M University + Tim Davis, Texas A&M University + Florentin Dorre, Technische Univeritat Dresden, Neo4j + Marton Elekes, Budapest University of Technology and Economics, Hungary + Balint Hegyi, Budapest University of Technology and Economics, Hungary + Tanner Hoke, Texas A&M University + James Kitchen, Anaconda + Scott Kolodziej, Texas A&M University + Pranav Konduri, Texas A&M University + Roi Lipman, Redis Labs (now FalkorDB) + Tze Meng Low, Carnegie Mellon University + Tim Mattson, Intel + Scott McMillan, Carnegie Mellon University + Markus Muetzel + Michel Pelletier, Graphegon + Gabor Szarnyas, CWI Amsterdam, The Netherlands + Erik Welch, Anaconda, NVIDIA + Carl Yang, University of California at Davis, Waymo + Yongzhe Zhang, SOKENDAI, Japan METIS is authored by George Karypis. @@ -21,17 +51,460 @@ Additional algorithm designers: Esmond Ng and John Gilbert. Refer to each package for license, copyright, and author information. +----------------------------------------------------------------------------- +Documentation +----------------------------------------------------------------------------- + +Refer to each package for the documentation on each package, typically in the +Doc subfolder. + ----------------------------------------------------------------------------- SuiteSparse branches ----------------------------------------------------------------------------- - * dev: the default branch, with recent updates of features to appear in - the next stable release. The intent is to keep this branch in - fully working order at all times, but the features will not be - finalized at any given time. - * stable: the most recent stable release. - * dev2: working branch. All submitted PRs should made to this branch. - This branch might not always be in working order. +* dev: the default branch, with recent updates of features to appear in + the next stable release. The intent is to keep this branch in + fully working order at all times, but the features will not be + finalized at any given time. +* stable: the most recent stable release. +* dev2: working branch. All submitted PRs should made to this branch. + This branch might not always be in working order. + +----------------------------------------------------------------------------- +SuiteSparse Packages +----------------------------------------------------------------------------- + +Packages in SuiteSparse, and files in this directory: + +* `AMD` + + approximate minimum degree ordering. This is the built-in AMD function in + MATLAB. + + authors: Tim Davis, Patrick Amestoy, Iain Duff + +* `bin` + + where programs are placed when compiled, for `make local` + +* `BTF` + + permutation to block triangular form + + authors: Tim Davis, Ekanathan Palamadai + +* `build` + + folder for default build tree + +* `CAMD` + + constrained approximate minimum degree ordering + + authors: Tim Davis, Patrick Amestoy, Iain Duff, Yanqing Chen + +* `CCOLAMD` + + constrained column approximate minimum degree ordering + + authors: Tim Davis, Sivasankaran Rajamanickam, Stefan Larimore. + + Algorithm design collaborators: Esmond Ng, John Gilbert (for COLAMD) + +* `ChangeLog` + + a summary of changes to SuiteSparse. See `*/Doc/ChangeLog` for details for + each package. + +* `CHOLMOD` + + sparse Cholesky factorization. Requires AMD, COLAMD, CCOLAMD, the BLAS, and + LAPACK. Optionally uses METIS. This is `chol` and `x=A\b` in MATLAB. + + author for all modules: Tim Davis + + CHOLMOD/Modify module authors: Tim Davis and William W. Hager + + CHOLMOD/SuiteSparse_metis: a modified version of METIS, embedded into the + CHOLMOD library. See the README.txt files for details. author: George + Karypis. This is a slightly modified copy included with SuiteSparse via the + open-source license provided by George Karypis. SuiteSparse cannot use an + unmodified copy of METIS. + +* `CITATION.bib` + + citations for SuiteSparse packages, in bibtex format. + +* `CMakeLists.txt` + + optional, to compile all of SuiteSparse. See below. + +* `CODE_OF_CONDUCT.md` + + community guidelines + +* `COLAMD` + + column approximate minimum degree ordering. This is the built-in COLAMD + function in MATLAB. + + authors (of the code): Tim Davis and Stefan Larimore + + Algorithm design collaborators: Esmond Ng, John Gilbert + +* `Contents.m` + + a list of contents for 'help SuiteSparse' in MATLAB. + +* `CONTRIBUTING.md` + + how to contribute to SuiteSparse + +* `CONTRIBUTOR-LICENSE.txt` + + required contributor agreement + +* `CSparse` + + a concise sparse matrix package, developed for my book, "Direct Methods for + Sparse Linear Systems", published by SIAM. Intended primarily for teaching. + Note that the code is (c) Tim Davis, as stated in the book. + + For production, use CXSparse instead. In particular, both CSparse and + CXSparse have the same include filename: `cs.h`. This package is used for + the built-in DMPERM in MATLAB. + + author: Tim Davis + +* `CXSparse` + + CSparse Extended. Includes support for complex matrices and both int or long + integers. Use this instead of CSparse for production use; it creates a + libcsparse.so (or dylib on the Mac) with the same name as CSparse. It is a + superset of CSparse. Any code that links against CSparse should also be able + to link against CXSparse instead. + + author: Tim Davis, David Bateman + +* `Example` + + a simple package that relies on almost all of SuiteSparse + +* `.github` + + workflows for CI testing on GitHub. + +* `GraphBLAS` + + graph algorithms in the language of linear algebra. + + https://graphblas.org + + authors: Tim Davis, Joe Eaton, Corey Nolet + +* `include` + + `make install` places user-visible include files for each package here, after + `make local`. + +* `KLU` + + sparse LU factorization, primarily for circuit simulation. Requires AMD, + COLAMD, and BTF. Optionally uses CHOLMOD, CAMD, CCOLAMD, and METIS. + + authors: Tim Davis, Ekanathan Palamadai + +* `LAGraph` + + a graph algorithms library based on GraphBLAS. See also + https://github.com/GraphBLAS/LAGraph + + Authors: many. + +* `LDL` + + a very concise LDL' factorization package + + author: Tim Davis + +* `lib` + + `make install` places shared libraries for each package here, after + `make local`. + +* `LICENSE.txt` + + collected licenses for each package. + +* `Makefile` + + optional, to compile all of SuiteSparse using `make`, which is used as a + simple wrapper for `cmake` in each subproject. + + * `make` + + compiles SuiteSparse libraries. Subsequent `make install` will install + in `CMAKE_INSTALL_PATH` (might default to `/usr/local/lib` on Linux or Mac). + + * `make local` + + compiles SuiteSparse. Subsequent `make install` will install in `./lib`, + `./include`. Does not install in `CMAKE_INSTALL_PATH`. + + * `make global` + + compiles SuiteSparse libraries. Subsequent `make install` will install in + `/usr/local/lib` (or whatever the configured `CMAKE_INSTALL_PREFIX` is). + Does not install in `./lib` and `./include`. + + * `make install` + + installs in the current directory (`./lib`, `./include`), or in + `/usr/local/lib` and `/usr/local/include`, (the latter defined by + `CMAKE_INSTALL_PREFIX`) depending on whether `make`, `make local`, or + `make global` has been done. + + * `make uninstall` + + undoes `make install`. + + * `make distclean` + + removes all files not in distribution, including `./bin`, `./share`, + `./lib`, and `./include`. + + * `make purge` + + same as `make distclean`. + + * `make clean` + + removes all files not in distribution, but keeps compiled libraries and + demos, `./lib`, `./share`, and `./include`. + + Each individual subproject also has each of the above `make` targets. + + Things you don't need to do: + + * `make docs` + + creates user guides from LaTeX files + + * `make cov` + + runs statement coverage tests (Linux only) + +* `MATLAB_Tools` + + various m-files for use in MATLAB + + author: Tim Davis (all parts) + + for `spqr_rank`: author Les Foster and Tim Davis + + * `Contents.m` + + list of contents + + * `dimacs10` + + loads matrices for DIMACS10 collection + + * `Factorize` + + object-oriented `x=A\b` for MATLAB + + * `find_components` + + finds connected components in an image + + * `GEE` + + simple Gaussian elimination + + * `getversion.m` + + determine MATLAB version + + * `gipper.m` + + create MATLAB archive + + * `hprintf.m` + + print hyperlinks in command window + + * `LINFACTOR` + + predecessor to `Factorize` package + + * `MESHND` + + nested dissection ordering of regular meshes + + * `pagerankdemo.m` + + illustrates how PageRank works + + * `SFMULT` + + `C=S*F` where `S` is sparse and `F` is full + + * `shellgui` + + display a seashell + + * `sparseinv` + + sparse inverse subset + + * `spok` + + check if a sparse matrix is valid + + * `spqr_rank` + + SPQR_RANK package. MATLAB toolbox for rank deficient sparse matrices: null + spaces, reliable factorizations, etc. With Leslie Foster, San Jose State + Univ. + + * `SSMULT` + + `C=A*B` where `A` and `B` are both sparse. + This was the basis for the built-in `C=A*B` in MATLAB, until it was + superseded by GraphBLAS in MATLAB R2021a. + + * `SuiteSparseCollection` + + for the SuiteSparse Matrix Collection + + * `waitmex` + + waitbar for use inside a mexFunction + +* `Mongoose` + + graph partitioning. + + authors: Nuri Yeralan, Scott Kolodziej, William Hager, Tim Davis + +* `ParU` + + a parallel unsymmetric pattern multifrontal method. + + Currently a pre-release. + + authors: Mohsen Aznaveh and Tim Davis + +* `RBio` + + read/write sparse matrices in Rutherford/Boeing format + + author: Tim Davis + +* `README.md` + + this file + +* `SPEX` + + solves sparse linear systems in exact arithmetic. + + Requires the GNU GMP and MPRF libraries. + + This will be soon replaced by a more general package, SPEX v3 that includes + this method (exact sparse LU) and others (sparse exact Cholesky, and sparse + exact update/downdate). The API of v3 will be changing significantly. + + authors: Chris Lourenco, Jinhao Chen, Erick Moreno-Centeno, + Lorena Lorena Mejia Domenzain, and Tim Davis. + + See https://github.com/clouren/SPEX for the latest version. + +* `SPQR` + + sparse QR factorization. This the built-in `qr` and `x=A\b` in MATLAB. Also + called SuiteSparseQR. + + Includes two GPU libraries: `SPQR/GPUQREngine` and + `SPQR/SuiteSparse_GPURuntime`. + + author of the CPU code: Tim Davis + + author of GPU modules: Tim Davis, Nuri Yeralan, Wissam Sid-Lakhdar, + Sanjay Ranka + +* `ssget` + + MATLAB interface to the SuiteSparse Matrix Collection + + author: Tim Davis + +* `SuiteSparse_config` + + library with common functions and configuration for all the above packages. + `CSparse`, `GraphBLAS`, `LAGraph`, and `MATLAB_Tools` do not use + `SuiteSparse_config`. + + author: Tim Davis + +* `SuiteSparse_demo.m` + + a demo of SuiteSparse for MATLAB + +* `SuiteSparse_install.m` + + install SuiteSparse for MATLAB + +* `SuiteSparse_paths.m` + + set paths for SuiteSparse MATLAB mexFunctions + +* `SuiteSparse_test.m` + + exhaustive test for SuiteSparse in MATLAB + +* `UMFPACK` + + sparse LU factorization. Requires `AMD` and the `BLAS`. + + This is the built-in `lu` and `x=A\b` in MATLAB. + + author: Tim Davis + + algorithm design collaboration: Iain Duff + +Refer to each package for license, copyright, and author information. All +codes are authored or co-authored by Timothy A. Davis (email: davis@tamu.edu), +except for METIS (by George Karypis), `GraphBLAS/cpu_features` (by Google), +GraphBLAS/lz4, zstd, and xxHash (by Yann Collet, now at Facebook), and +GraphBLAS/CUDA/jitify.hpp (by NVIDIA). Parts of GraphBLAS/CUDA are +Copyright (c) by NVIDIA. Please refer to each of these licenses. + +----------------------------------------------------------------------------- +For distro maintainers (Linux, homebrew, spack, R, Octave, Trilinos, ...): +----------------------------------------------------------------------------- + +Thanks for packaging SuiteSparse! Here are some suggestions: + +* GraphBLAS takes a long time to compile because it creates many fast + "FactoryKernels" at compile-time. If you want to reduce the compile time and + library size, enable the `GRAPHBLAS_COMPACT` mode, but keep the JIT compiler + enabled. Then GraphBLAS will compile the kernels it needs at run-time, via + its JIT compiler. Performance will be the same as the FactoryKernels once + the JIT kernels are compiled. User compiled kernels are placed in + `~/.SuiteSparse`, by default. You do not need to distribute the source for + GraphBLAS to enable the JIT compiler: just `libgraphblas.so` and + `GraphBLAS.h` is enough. + +* GraphBLAS needs OpenMP! It's fundamentally a parallel code so please + distribute it with OpenMP enabled. Performance will suffer otherwise. + +* CUDA acceleration: CHOLMOD and SPQR can benefit from their CUDA kernels. If + you do not have CUDA or do not want to include it in your distro, this + version of SuiteSparse skips the building of the `CHOLMOD_CUDA` and `SPQR_CUDA` + libraries, and does not link against the `GPUQREngine` and + `SuiteSparse_GPURuntime` libraries. ----------------------------------------------------------------------------- How to cite the SuiteSparse meta-package and its component packages: @@ -40,193 +513,180 @@ How to cite the SuiteSparse meta-package and its component packages: SuiteSparse is a meta-package of many packages, each with their own published papers. To cite the whole collection, use the URLs: - * https://github.com/DrTimothyAldenDavis/SuiteSparse - * http://suitesparse.com (which is a forwarding URL +* https://github.com/DrTimothyAldenDavis/SuiteSparse +* http://suitesparse.com (which is a forwarding URL to https://people.engr.tamu.edu/davis/suitesparse.html) Please also cite the specific papers for the packages you use. This is a long list; if you want a shorter list, just cite the most recent "Algorithm XXX:" papers in ACM TOMS, for each package. - * For the MATLAB x=A\b, see below for AMD, COLAMD, CHOLMOD, UMFPACK, - and SuiteSparseQR (SPQR). +* For the MATLAB x=A\b, see below for AMD, COLAMD, CHOLMOD, UMFPACK, + and SuiteSparseQR (SPQR). - * for GraphBLAS, and `C=A*B` in MATLAB (sparse-times-sparse): +* for GraphBLAS, and C=AB in MATLAB (sparse-times-sparse): - T. Davis, Algorithm 10xx: SuiteSparse:GraphBLAS: parallel graph - algorithms in the language of sparse linear algebra, ACM Trans on - Mathematical Software, to appear, 2023. See the pdf in - https://github.com/DrTimothyAldenDavis/GraphBLAS/tree/stable/Doc + T. A. Davis. Algorithm 1037: SuiteSparse:GraphBLAS: Parallel Graph Algorithms + in the Language of Sparse Linear Algebra. ACM Trans. Math. Softw. 49, 3, + Article 28 (September 2023), 30 pages. https://doi.org/10.1145/3577195 - T. Davis, Algorithm 1000: SuiteSparse:GraphBLAS: graph algorithms in - the language of sparse linear algebra, ACM Trans on Mathematical - Software, vol 45, no 4, Dec. 2019, Article No 44. - https://doi.org/10.1145/3322125. + T. Davis, Algorithm 1000: SuiteSparse:GraphBLAS: graph algorithms in the + language of sparse linear algebra, ACM Trans on Mathematical Software, vol + 45, no 4, Dec. 2019, Article No 44. https://doi.org/10.1145/3322125. - * for CSparse/CXSParse: +* for LAGraph: - T. A. Davis, Direct Methods for Sparse Linear Systems, SIAM Series on - the Fundamentals of Algorithms, SIAM, Philadelphia, PA, 2006. - https://doi.org/10.1137/1.9780898718881 + G. Szárnyas et al., "LAGraph: Linear Algebra, Network Analysis Libraries, and + the Study of Graph Algorithms," 2021 IEEE International Parallel and + Distributed Processing Symposium Workshops (IPDPSW), Portland, OR, USA, 2021, + pp. 243-252. https://doi.org/10.1109/IPDPSW52791.2021.00046. - * for SuiteSparseQR (SPQR): (also cite AMD, COLAMD): +* for CSparse/CXSParse: - T. A. Davis, Algorithm 915: SuiteSparseQR: Multifrontal multithreaded - rank-revealing sparse QR factorization, ACM Trans. on Mathematical - Software, 38(1), 2011, pp. 8:1--8:22. - https://doi.org/10.1145/2049662.2049670 + T. A. Davis, Direct Methods for Sparse Linear Systems, SIAM Series on the + Fundamentals of Algorithms, SIAM, Philadelphia, PA, 2006. + https://doi.org/10.1137/1.9780898718881 - * for SuiteSparseQR/GPU: +* for SuiteSparseQR (SPQR): (also cite AMD, COLAMD): - Sencer Nuri Yeralan, T. A. Davis, Wissam M. Sid-Lakhdar, and Sanjay - Ranka. 2017. Algorithm 980: Sparse QR Factorization on the GPU. ACM - Trans. Math. Softw. 44, 2, Article 17 (June 2018), 29 pages. - https://doi.org/10.1145/3065870 + T. A. Davis, Algorithm 915: SuiteSparseQR: Multifrontal multithreaded + rank-revealing sparse QR factorization, ACM Trans. on Mathematical Software, + 38(1), 2011, pp. 8:1--8:22. https://doi.org/10.1145/2049662.2049670 - * for CHOLMOD: (also cite AMD, COLAMD): +* for SuiteSparseQR/GPU: - Y. Chen, T. A. Davis, W. W. Hager, and S. Rajamanickam, Algorithm 887: - CHOLMOD, supernodal sparse Cholesky factorization and update/downdate, - ACM Trans. on Mathematical Software, 35(3), 2008, pp. 22:1--22:14. - https://dl.acm.org/doi/abs/10.1145/1391989.1391995 + Sencer Nuri Yeralan, T. A. Davis, Wissam M. Sid-Lakhdar, and Sanjay Ranka. + 2017. Algorithm 980: Sparse QR Factorization on the GPU. ACM Trans. Math. + Softw. 44, 2, Article 17 (June 2018), 29 pages. + https://doi.org/10.1145/3065870 - T. A. Davis and W. W. Hager, Dynamic supernodes in sparse Cholesky - update/downdate and triangular solves, ACM Trans. on Mathematical - Software, 35(4), 2009, pp. 27:1--27:23. - https://doi.org/10.1145/1462173.1462176 +* for CHOLMOD: (also cite AMD, COLAMD): - * for CHOLMOD/Modify Module: (also cite AMD, COLAMD): + Y. Chen, T. A. Davis, W. W. Hager, and S. Rajamanickam, Algorithm 887: + CHOLMOD, supernodal sparse Cholesky factorization and update/downdate, ACM + Trans. on Mathematical Software, 35(3), 2008, pp. 22:1--22:14. + https://dl.acm.org/doi/abs/10.1145/1391989.1391995 - T. A. Davis and William W. Hager, Row Modifications of a Sparse - Cholesky Factorization SIAM Journal on Matrix Analysis and Applications - 2005 26:3, 621-639 - https://doi.org/10.1137/S089547980343641X + T. A. Davis and W. W. Hager, Dynamic supernodes in sparse Cholesky + update/downdate and triangular solves, ACM Trans. on Mathematical Software, + 35(4), 2009, pp. 27:1--27:23. https://doi.org/10.1145/1462173.1462176 - T. A. Davis and William W. Hager, Multiple-Rank Modifications of a - Sparse Cholesky Factorization SIAM Journal on Matrix Analysis and - Applications 2001 22:4, 997-1013 - https://doi.org/10.1137/S0895479899357346 +* for CHOLMOD/Modify Module: (also cite AMD, COLAMD): - T. A. Davis and William W. Hager, Modifying a Sparse Cholesky - Factorization, SIAM Journal on Matrix Analysis and Applications 1999 - 20:3, 606-627 - https://doi.org/10.1137/S0895479897321076 + T. A. Davis and William W. Hager, Row Modifications of a Sparse Cholesky + Factorization SIAM Journal on Matrix Analysis and Applications 2005 26:3, + 621-639. https://doi.org/10.1137/S089547980343641X - * for CHOLMOD/GPU Modules: + T. A. Davis and William W. Hager, Multiple-Rank Modifications of a Sparse + Cholesky Factorization SIAM Journal on Matrix Analysis and Applications 2001 + 22:4, 997-1013. https://doi.org/10.1137/S0895479899357346 - Steven C. Rennich, Darko Stosic, Timothy A. Davis, Accelerating sparse - Cholesky factorization on GPUs, Parallel Computing, Vol 59, 2016, pp - 140-150. - https://doi.org/10.1016/j.parco.2016.06.004 + T. A. Davis and William W. Hager, Modifying a Sparse Cholesky Factorization, + SIAM Journal on Matrix Analysis and Applications 1999 20:3, 606-627. + https://doi.org/10.1137/S0895479897321076 - * for AMD and CAMD: +* for CHOLMOD/GPU Modules: - P. Amestoy, T. A. Davis, and I. S. Duff, Algorithm 837: An approximate - minimum degree ordering algorithm, ACM Trans. on Mathematical Software, - 30(3), 2004, pp. 381--388. - https://dl.acm.org/doi/abs/10.1145/1024074.1024081 + Steven C. Rennich, Darko Stosic, Timothy A. Davis, Accelerating sparse + Cholesky factorization on GPUs, Parallel Computing, Vol 59, 2016, pp 140-150. + https://doi.org/10.1016/j.parco.2016.06.004 - P. Amestoy, T. A. Davis, and I. S. Duff, An approximate minimum degree - ordering algorithm, SIAM J. Matrix Analysis and Applications, 17(4), - 1996, pp. 886--905. - https://doi.org/10.1137/S0895479894278952 +* for AMD and CAMD: - * for COLAMD, SYMAMD, CCOLAMD, and CSYMAMD: + P. Amestoy, T. A. Davis, and I. S. Duff, Algorithm 837: An approximate + minimum degree ordering algorithm, ACM Trans. on Mathematical Software, + 30(3), 2004, pp. 381--388. + https://dl.acm.org/doi/abs/10.1145/1024074.1024081 - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, - an approximate column minimum degree ordering algorithm, ACM Trans. on - Mathematical Software, 30(3), 2004, pp. 377--380. - https://doi.org/10.1145/1024074.1024080 + P. Amestoy, T. A. Davis, and I. S. Duff, An approximate minimum degree + ordering algorithm, SIAM J. Matrix Analysis and Applications, 17(4), 1996, + pp. 886--905. https://doi.org/10.1137/S0895479894278952 - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, A column approximate - minimum degree ordering algorithm, ACM Trans. on Mathematical Software, - 30(3), 2004, pp. 353--376. - https://doi.org/10.1145/1024074.1024079 +* for COLAMD, SYMAMD, CCOLAMD, and CSYMAMD: - * for UMFPACK: (also cite AMD and COLAMD): + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, an + approximate column minimum degree ordering algorithm, ACM Trans. on + Mathematical Software, 30(3), 2004, pp. 377--380. + https://doi.org/10.1145/1024074.1024080 - T. A. Davis, Algorithm 832: UMFPACK - an unsymmetric-pattern - multifrontal method with a column pre-ordering strategy, ACM Trans. on - Mathematical Software, 30(2), 2004, pp. 196--199. - https://dl.acm.org/doi/abs/10.1145/992200.992206 + T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, A column approximate minimum + degree ordering algorithm, ACM Trans. on Mathematical Software, 30(3), 2004, + pp. 353--376. https://doi.org/10.1145/1024074.1024079 - T. A. Davis, A column pre-ordering strategy for the unsymmetric-pattern - multifrontal method, ACM Trans. on Mathematical Software, 30(2), 2004, - pp. 165--195. - https://dl.acm.org/doi/abs/10.1145/992200.992205 +* for UMFPACK: (also cite AMD and COLAMD): - T. A. Davis and I. S. Duff, A combined unifrontal/multifrontal method - for unsymmetric sparse matrices, ACM Trans. on Mathematical Software, - 25(1), 1999, pp. 1--19. - https://doi.org/10.1145/305658.287640 + T. A. Davis, Algorithm 832: UMFPACK - an unsymmetric-pattern multifrontal + method with a column pre-ordering strategy, ACM Trans. on Mathematical + Software, 30(2), 2004, pp. 196--199. + https://dl.acm.org/doi/abs/10.1145/992200.992206 - T. A. Davis and I. S. Duff, An unsymmetric-pattern multifrontal method - for sparse LU factorization, SIAM J. Matrix Analysis and Computations, - 18(1), 1997, pp. 140--158. - https://doi.org/10.1137/S0895479894246905 + T. A. Davis, A column pre-ordering strategy for the unsymmetric-pattern + multifrontal method, ACM Trans. on Mathematical Software, 30(2), 2004, pp. + 165--195. https://dl.acm.org/doi/abs/10.1145/992200.992205 - * for the FACTORIZE m-file: + T. A. Davis and I. S. Duff, A combined unifrontal/multifrontal method for + unsymmetric sparse matrices, ACM Trans. on Mathematical Software, 25(1), + 1999, pp. 1--19. https://doi.org/10.1145/305658.287640 - T. A. Davis, Algorithm 930: FACTORIZE, an object-oriented linear system - solver for MATLAB, ACM Trans. on Mathematical Software, 39(4), 2013, - pp. 28:1-28:18. - https://doi.org/10.1145/2491491.2491498 + T. A. Davis and I. S. Duff, An unsymmetric-pattern multifrontal method for + sparse LU factorization, SIAM J. Matrix Analysis and Computations, 18(1), + 1997, pp. 140--158. https://doi.org/10.1137/S0895479894246905 - * for KLU and BTF (also cite AMD and COLAMD): +* for the FACTORIZE m-file: - T. A. Davis and Ekanathan Palamadai Natarajan. 2010. Algorithm 907: - KLU, A Direct Sparse Solver for Circuit Simulation Problems. ACM Trans. - Math. Softw. 37, 3, Article 36 (September 2010), 17 pages. - https://dl.acm.org/doi/abs/10.1145/1824801.1824814 + T. A. Davis, Algorithm 930: FACTORIZE, an object-oriented linear system + solver for MATLAB, ACM Trans. on Mathematical Software, 39(4), 2013, pp. + 28:1-28:18. https://doi.org/10.1145/2491491.2491498 - * for LDL: +* for KLU and BTF (also cite AMD and COLAMD): - T. A. Davis. Algorithm 849: A concise sparse Cholesky factorization - package. ACM Trans. Math. Softw. 31, 4 (December 2005), 587–591. - https://doi.org/10.1145/1114268.1114277 + T. A. Davis and Ekanathan Palamadai Natarajan. 2010. Algorithm 907: KLU, A + Direct Sparse Solver for Circuit Simulation Problems. ACM Trans. Math. + Softw. 37, 3, Article 36 (September 2010), 17 pages. + https://dl.acm.org/doi/abs/10.1145/1824801.1824814 - * for ssget and the SuiteSparse Matrix Collection: +* for LDL: - T. A. Davis and Yifan Hu. 2011. The University of Florida sparse - matrix collection. ACM Trans. Math. Softw. 38, 1, Article 1 (November - 2011), 25 pages. - https://doi.org/10.1145/2049662.2049663 + T. A. Davis. Algorithm 849: A concise sparse Cholesky factorization package. + ACM Trans. Math. Softw. 31, 4 (December 2005), 587–591. + https://doi.org/10.1145/1114268.1114277 - Kolodziej et al., (2019). The SuiteSparse Matrix Collection Website - Interface. Journal of Open Source Software, 4(35), 1244, - https://doi.org/10.21105/joss.01244 +* for ssget and the SuiteSparse Matrix Collection: - * for `spqr_rank`: + T. A. Davis and Yifan Hu. 2011. The University of Florida sparse matrix + collection. ACM Trans. Math. Softw. 38, 1, Article 1 (November 2011), 25 + pages. https://doi.org/10.1145/2049662.2049663 - Leslie V. Foster and T. A. Davis. 2013. Algorithm 933: Reliable - calculation of numerical rank, null space bases, pseudoinverse - solutions, and basic solutions using suitesparseQR. ACM Trans. Math. - Softw. 40, 1, Article 7 (September 2013), 23 pages. - https://doi.org/10.1145/2513109.2513116 + Kolodziej et al., (2019). The SuiteSparse Matrix Collection Website + Interface. Journal of Open Source Software, 4(35), 1244. + https://doi.org/10.21105/joss.01244 - * for Mongoose: +* for `spqr_rank`: - T. A. Davis, William W. Hager, Scott P. Kolodziej, and S. Nuri Yeralan. - 2020. Algorithm 1003: Mongoose, a Graph Coarsening and Partitioning - Library. ACM Trans. Math. Softw. 46, 1, Article 7 (March 2020), 18 - pages. - https://doi.org/10.1145/3337792 + Leslie V. Foster and T. A. Davis. 2013. Algorithm 933: Reliable calculation + of numerical rank, null space bases, pseudoinverse solutions, and basic + solutions using suitesparseQR. ACM Trans. Math. Softw. 40, 1, Article 7 + (September 2013), 23 pages. https://doi.org/10.1145/2513109.2513116 - * for SPEX: +* for Mongoose: - Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and T. A. - Davis. 2022. Algorithm 1021: SPEX Left LU, Exactly Solving Sparse - Linear Systems via a Sparse Left-Looking Integer-Preserving LU - Factorization. ACM Trans. Math. Softw. June 2022. - https://doi.org/10.1145/3519024 + T. A. Davis, William W. Hager, Scott P. Kolodziej, and S. Nuri Yeralan. + 2020. Algorithm 1003: Mongoose, a Graph Coarsening and Partitioning Library. + ACM Trans. Math. Softw. 46, 1, Article 7 (March 2020), 18 pages. + https://doi.org/10.1145/3337792 + +* for SPEX: + + Christopher Lourenco, Jinhao Chen, Erick Moreno-Centeno, and T. A. Davis. + 2022. Algorithm 1021: SPEX Left LU, Exactly Solving Sparse Linear Systems via + a Sparse Left-Looking Integer-Preserving LU Factorization. ACM Trans. Math. + Softw. June 2022. https://doi.org/10.1145/3519024 ----------------------------------------------------------------------------- About the BLAS and LAPACK libraries ----------------------------------------------------------------------------- -NOTE: Use of the Intel MKL BLAS is strongly recommended. In a 2019 test, -OpenBLAS caused result in severe performance degradation. The reason for this -is being investigated, and this may be resolved in the near future. +NOTE: if you use OpenBLAS, be sure to use version 0.3.27 or later. To select your BLAS/LAPACK, see the instructions in SuiteSparseBLAS.cmake in `SuiteSparse_config/cmake_modules`. If `SuiteSparse_config` finds a BLAS with @@ -234,15 +694,17 @@ To select your BLAS/LAPACK, see the instructions in SuiteSparseBLAS.cmake in `SuiteSparse_config.h` with the `SUITESPARSE_BLAS_INT` defined as `int64_t`. Otherwise, if a 32-bit BLAS is found, this type is defined as `int32_t`. If later on, UMFPACK, CHOLMOD, or SPQR are compiled and linked with a BLAS that -has a different integer size, you must override the definition with -DBLAS64 -(to assert the use of 64-bit integers in the BLAS) or -DBLAS32, (to assert the -use of 32-bit integers in the BLAS). +has a different integer size, you must override the definition with `-DBLAS64` +(to assert the use of 64-bit integers in the BLAS) or `-DBLAS32`, (to assert +the use of 32-bit integers in the BLAS). + +The size of the BLAS integer has nothing to do with `sizeof(void *)`. When distributed in a binary form (such as a Debian, Ubuntu, Spack, or Brew package), SuiteSparse should probably be compiled to expect a 32-bit BLAS, since this is the most common case. The default is to use a 32-bit BLAS, but -this can be changed in SuiteSparseBLAS.cmake or by compiling with -`-DALLOW_64BIT_BLAS=1`. +this can be changed by setting the cmake variable +`SUITESPARSE_USE_64BIT_BLAS` to `ON`. By default, SuiteSparse hunts for a suitable BLAS library. To enforce a particular BLAS library use either: @@ -251,263 +713,140 @@ particular BLAS library use either: cd Package ; cmake -DBLA_VENDOR=OpenBLAS .. make To use the default (hunt for a BLAS), do not set `BLA_VENDOR`, or set it to -ANY. In this case, if `ALLOW_64BIT_BLAS` is set, preference is given to a -64-bit BLAS, but a 32-bit BLAS library will be used if no 64-bit library is -found. +`ANY`. In this case, if `SUITESPARSE_USE_64BIT_BLAS` is ON, preference is +given to a 64-bit BLAS, but a 32-bit BLAS library will be used if no 64-bit +library is found. However, if both `SUITESPARSE_USE_64BIT_BLAS` and +`SUITESPARSE_USE_STRICT` are ON, then only a 64-bit BLAS is considered. -When selecting a particular BLAS library, the `ALLOW_64BIT_BLAS` setting is -strictly followed. If set to true, only a 64-bit BLAS library will be used. -If false (the default), only a 32-bit BLAS library will be used. If no such -BLAS is found, the build will fail. +When selecting a particular BLAS library, the `SUITESPARSE_USE_64BIT_BLAS` +setting is strictly followed. If set to true, only a 64-bit BLAS library will +be used. If false (the default), only a 32-bit BLAS library will be used. If +no such BLAS is found, the build will fail. ------------------- -SuiteSparse/README ------------------- +----------------------------------------------------------------------------- +QUICK START FOR THE C/C++ LIBRARIES: +----------------------------------------------------------------------------- -Packages in SuiteSparse, and files in this directory: +Type the following in this directory (requires system priviledge to do the +`sudo make install`): +``` + mkdir -p build && cd build + cmake .. + cmake --build . + sudo cmake --install . +``` + +All libraries will be created and installed into the default system-wide folder +(/usr/local/lib on Linux). All include files needed by the applications that +use SuiteSparse are installed into /usr/local/include/suitesparse (on Linux). + +To build only a subset of libraries, set `SUITESPARSE_ENABLE_PROJECTS` when +configuring with CMake. E.g., to build and install CHOLMOD and CXSparse +(including their dependencies), use the following commands: +``` + mkdir -p build && cd build + cmake -DSUITESPARSE_ENABLE_PROJECTS="cholmod;cxsparse" .. + cmake --build . + sudo cmake --install . +``` + +For Windows (MSVC), import the `CMakeLists.txt` file into MS Visual Studio. +Be sure to specify the build type as Release; for example, to build SuiteSparse +on Windows in the command window, run: +``` + mkdir -p build && cd build + cmake .. + cmake --build . --config Release + cmake --install . +``` - GraphBLAS graph algorithms in the language of linear algebra. - https://graphblas.org - author: Tim Davis - - SPEX solves sparse linear systems in exact arithmetic. - Requires the GNU GMP and MPRF libraries. - This will be soon replaced by a more general package, SPEX v3 - that includes this method (exact sparse LU) and others (sparse - exact Cholesky, and sparse exact update/downdate). The API - of v3 will be changing significantly. - - AMD approximate minimum degree ordering. This is the built-in AMD - function in MATLAB. - authors: Tim Davis, Patrick Amestoy, Iain Duff - - bin where programs are placed when compiled - - BTF permutation to block triangular form - authors: Tim Davis, Ekanathan Palamadai - - CAMD constrained approximate minimum degree ordering - authors: Tim Davis, Patrick Amestoy, Iain Duff, Yanqing Chen - - CCOLAMD constrained column approximate minimum degree ordering - authors: Tim Davis, Sivasankaran Rajamanickam, Stefan Larimore. - Algorithm design collaborators: Esmond Ng, John Gilbert - (for COLAMD) - - ChangeLog a summary of changes to SuiteSparse. See */Doc/ChangeLog - for details for each package. - - CHOLMOD sparse Cholesky factorization. Requires AMD, COLAMD, CCOLAMD, - the BLAS, and LAPACK. Optionally uses METIS. This is chol and - x=A\b in MATLAB. - author for all modules: Tim Davis - CHOLMOD/Modify module authors: Tim Davis and William W. Hager - - COLAMD column approximate minimum degree ordering. This is the - built-in COLAMD function in MATLAB. - authors (of the code): Tim Davis and Stefan Larimore - Algorithm design collaborators: Esmond Ng, John Gilbert - - Contents.m a list of contents for 'help SuiteSparse' in MATLAB. - - CSparse a concise sparse matrix package, developed for my - book, "Direct Methods for Sparse Linear Systems", - published by SIAM. Intended primarily for teaching. - Note that the code is (c) Tim Davis, as stated in the book. - For production, use CXSparse instead. In particular, both - CSparse and CXSparse have the same include filename: cs.h. - This package is used for the built-in DMPERM in MATLAB. - author: Tim Davis - - CXSparse CSparse Extended. Includes support for complex matrices - and both int or long integers. Use this instead of CSparse - for production use; it creates a libcsparse.so (or *dylib on - the Mac) with the same name as CSparse. It is a superset - of CSparse. Any code that links against CSparse should - also be able to link against CXSparse instead. - author: Tim Davis, David Bateman - - include 'make install' places user-visible include files for each - package here, after 'make local' - - KLU sparse LU factorization, primarily for circuit simulation. - Requires AMD, COLAMD, and BTF. Optionally uses CHOLMOD, - CAMD, CCOLAMD, and METIS. - authors: Tim Davis, Ekanathan Palamadai - - LDL a very concise LDL' factorization package - author: Tim Davis - - lib 'make install' places shared libraries for each package - here, after 'make local' - - Makefile to compile all of SuiteSparse - - make compiles SuiteSparse libraries. - Subsequent "make install" will install - in just CMAKE_INSTALL_PATH (defaults to - /usr/local/lib on Linux or Mac). - - make both compiles SuiteSparse, and then "make install" - will instal in both ./lib and - CMAKE_INSTALL_PATH). - - make local compiles SuiteSparse. - Subsequent "make install will install only - in ./lib, ./include only. - Does not install in CMAKE_INSTALL_PATH. - - make global compiles SuiteSparse libraries. - Subsequent "make install" will install in - just /usr/local/lib (or whatever your - CMAKE_INSTALL_PREFIX is). - Does not install in ./lib and ./include. - - make install installs in the current directory - (./lib, ./include), and/or in - /usr/local/lib and /usr/local/include, - depending on whether "make", "make local", - "make global", or "make both", - etc has been done. - - make uninstall undoes 'make install' - - make distclean removes all files not in distribution, including - ./bin, ./share, ./lib, and ./include. - - make purge same as 'make distclean' - - make clean removes all files not in distribution, but - keeps compiled libraries and demoes, ./lib, - ./share, and ./include. - - Each individual package also has each of the above 'make' - targets. - - Things you don't need to do: - make docs creates user guides from LaTeX files - make cov runs statement coverage tests (Linux only) - - MATLAB_Tools various m-files for use in MATLAB - author: Tim Davis (all parts) - for spqr_rank: author Les Foster and Tim Davis - - Contents.m list of contents - dimacs10 loads matrices for DIMACS10 collection - Factorize object-oriented x=A\b for MATLAB - find_components finds connected components in an image - GEE simple Gaussian elimination - getversion.m determine MATLAB version - gipper.m create MATLAB archive - hprintf.m print hyperlinks in command window - LINFACTOR predecessor to Factorize package - MESHND nested dissection ordering of regular meshes - pagerankdemo.m illustrates how PageRank works - SFMULT C=S*F where S is sparse and F is full - shellgui display a seashell - sparseinv sparse inverse subset - spok check if a sparse matrix is valid - spqr_rank SPQR_RANK package. MATLAB toolbox for rank - deficient sparse matrices: null spaces, - reliable factorizations, etc. With Leslie - Foster, San Jose State Univ. - SSMULT C=A*B where A and B are both sparse - SuiteSparseCollection for the SuiteSparse Matrix Collection - waitmex waitbar for use inside a mexFunction - - The SSMULT and SFMULT functions are the basis for the - built-in C=A*B functions in MATLAB. - - Mongoose graph partitioning. - authors: Nuri Yeralan, Scott Kolodziej, William Hager, Tim Davis - - CHOLMOD/SuiteSparse_metis: a modified version of METIS, embedded into - the CHOLMOD library. See the README.txt files - for details. author: George Karypis. This is a slightly - modified copy included with SuiteSparse via the open-source - license provided by George Karypis. SuiteSparse cannot use - an unmodified copy METIS. - - RBio read/write sparse matrices in Rutherford/Boeing format - author: Tim Davis - - README.txt this file - - SPQR sparse QR factorization. This the built-in qr and x=A\b in - MATLAB. Also called SuiteSparseQR. - author of the CPU code: Tim Davis - author of GPU modules: Tim Davis, Nuri Yeralan, - Wissam Sid-Lakhdar, Sanjay Ranka - - GPUQREngine: GPU support package for SPQR - (not built into MATLAB, however) - authors: Tim Davis, Nuri Yeralan, Sanjay Ranka, - Wissam Sid-Lakhdar - - SuiteSparse_config configuration file for all the above packages. - CSparse and MATLAB_Tools do not use SuiteSparse_config. - author: Tim Davis - - SuiteSparse_GPURuntime GPU support package for SPQR and CHOLMOD - (not builtin to MATLAB, however). - - SuiteSparse_install.m install SuiteSparse for MATLAB - SuiteSparse_paths.m set paths for SuiteSparse MATLAB mexFunctions - - SuiteSparse_test.m exhaustive test for SuiteSparse in MATLAB - - ssget MATLAB interface to the SuiteSparse Matrix Collection - author: Tim Davis - - UMFPACK sparse LU factorization. Requires AMD and the BLAS. - This is the built-in lu and x=A\b in MATLAB. - author: Tim Davis - algorithm design collaboration: Iain Duff - -Some codes optionally use METIS 5.1.0. This package is located in SuiteSparse -in the `CHOLMOD/SuiteSparse_metis` directory. Its use is optional. To compile -CHOLMOD without it, use the CMAKE_OPTIONS="-DNPARTITION=1" setting. The use of -METIS can improve ordering quality for some matrices, particularly large 3D -discretizations. METIS has been slightly modified for use in SuiteSparse; see -the `CHOLMOD/SuiteSparse_metis/README.txt` file for details. +Be sure to first install all required libraries: BLAS and LAPACK for UMFPACK, +CHOLMOD, and SPQR, and GMP and MPFR for SPEX. Be sure to use the latest +libraries; SPEX requires MPFR 4.0.2 and GMP 6.1.2 (these version numbers +do NOT correspond to the X.Y.Z suffix of libgmp.so.X.Y.Z and libmpfr.so.X.Y.Z; +see the SPEX user guide for details). -Refer to each package for license, copyright, and author information. All -codes are authored or co-authored by Timothy A. Davis (email: davis@tamu.edu), -except for METIS (by George Karypis), GraphBLAS/cpu_features (by Google), -GraphBLAS/lz4 and zstd (by Yann Collet, now at Facebook), and -GraphBLAS/CUDA/jitify.hpp (by NVIDIA). Parts of GraphBLAS/CUDA are -Copyright (c) by NVIDIA. Please refer to each of these licenses. +To compile the libraries and install them only in SuiteSparse/lib (not +/usr/local/lib), do this instead in the top-level of SuiteSparse: +``` + mkdir -p build && cd build + cmake -DCMAKE_INSTALL_PREFIX=.. .. + cmake --build . + cmake --install . +``` + +If you add /home/me/SuiteSparse/lib to your library search path +(`LD_LIBRARY_PATH` in Linux), you can do the following (for example): +``` + S = /home/me/SuiteSparse + cc myprogram.c -I$(S)/include/suitesparse -lumfpack -lamd -lcholmod -lsuitesparseconfig -lm +``` + +To change the C and C++ compilers, and to compile in parallel use: +``` + cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER==g++ .. +``` + +for example, which changes the compiler to gcc and g++. + +This will work on Linux/Unix and the Mac. It should automatically detect if +you have the Intel compilers or not, and whether or not you have CUDA. + +See `SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake` to select your BLAS. + +You may also need to add SuiteSparse/lib to your path. If your copy of +SuiteSparse is in /home/me/SuiteSparse, for example, then add this to your +`~/.bashrc` file: + +``` +LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/SuiteSparse/lib +export LD_LIBRARY_PATH +``` -Licenses for each package are located in the following files, all in -PACKAGENAME/Doc/License.txt, and these files are also concatenated into -the top-level LICENSE.txt file. +For the Mac, use this instead: +``` +DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/home/me/SuiteSparse/lib +export DYLD_LIBRARY_PATH +``` + +Default install location of files is below, where PACKAGE is one of the +packages in SuiteSparse: + + * `CMAKE_INSTALL_PREFIX/include/suitesparse/`: include files + * `CMAKE_INSTALL_PREFIX/lib/`: compiled libraries + * `CMAKE_INSTALL_PREFIX/lib/cmake/SuiteSparse/`: `*.cmake` scripts + for all of SuiteSparse + * `CMAKE_INSTALL_PREFIX/lib/cmake/PACKAGE/`: `*Config.cmake` scripts for a + specific package + * `CMAKE_INSTALL_PREFIX/lib/pkgconfig/PACKAGE.pc`: `.pc` scripts for + a specific package pkgconfig ----------------------------------------------------------------------------- QUICK START FOR MATLAB USERS (Linux or Mac): ----------------------------------------------------------------------------- -Uncompress the SuiteSparse.zip or SuiteSparse.tar.gz archive file (they contain -the same thing). Suppose you place SuiteSparse in the /home/me/SuiteSparse -folder. - -Add the SuiteSparse/lib folder to your run-time library path. On Linux, add -this to your ~/.bashrc script, assuming /home/me/SuiteSparse is the location of -your copy of SuiteSparse: +Suppose you place SuiteSparse in the `/home/me/SuiteSparse` folder. +Add the `SuiteSparse/lib` folder to your run-time library path. On Linux, add +this to your `~/.bashrc` script, assuming `/home/me/SuiteSparse` is the +location of your copy of SuiteSparse: +``` LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/SuiteSparse/lib export LD_LIBRARY_PATH +``` -For the Mac, use this instead, in your ~/.zshrc script, assuming you place -SuiteSparse in /Users/me/SuiteSparse: - +For the Mac, use this instead, in your `~/.zshrc` script, assuming you place +SuiteSparse in `/Users/me/SuiteSparse`: +``` DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Users/me/SuiteSparse/lib export DYLD_LIBRARY_PATH +``` -Compile all of SuiteSparse with "make local". +Compile all of SuiteSparse with `make local`. Next, compile the GraphBLAS MATLAB library. In the system shell while in the -SuiteSparse folder, type "make gbmatlab" if you want to install it system-wide -with "make install", or "make gblocal" if you want to use the library in +SuiteSparse folder, type `make gbmatlab` if you want to install it system-wide +with `make install`, or `make gblocal` if you want to use the library in your own SuiteSparse/lib. Then in the MATLAB Command Window, cd to the SuiteSparse directory and type @@ -521,162 +860,360 @@ Documents/MATLAB/startup.m. You can also use the `SuiteSparse_paths` m-file to set all your paths at the start of each MATLAB session. ----------------------------------------------------------------------------- -QUICK START FOR THE C/C++ LIBRARIES: +Compilation options ----------------------------------------------------------------------------- -For Linux and Mac: type the following in this directory (requires system -priviledge to do the `sudo make install`): +You can set specific options for CMake with the command (for example): +``` + cmake -DCHOLMOD_PARTITION=OFF -DBUILD_STATIC_LIBS=OFF -DCMAKE_BUILD_TYPE=Debug .. +``` - make - sudo make install +That command will compile all of SuiteSparse except for CHOLMOD/Partition +Module (because of `-DCHOLMOD_PARTITION=OFF`). Debug mode will be used (the +build type). The static libraries will not be built (since +`-DBUILD_STATIC_LIBS=OFF` is set). -All libraries will be created and copied into SuiteSparse/lib and into -/usr/local/lib. All include files need by the applications that use -SuiteSparse are copied into SuiteSparse/include and into /usr/local/include. +* `SUITESPARSE_ENABLE_PROJECTS`: -For Windows, import each `*/CMakeLists.txt` file into MS Visual Studio. + Semicolon separated list of projects to be built or `all`. + Default: `all` in which case the following projects are built: -Be sure to first install all required libraries: BLAS and LAPACK for UMFPACK, -CHOLMOD, and SPQR, and GMP and MPFR for SPEX. Be sure to use the latest -libraries; SPEX requires MPFR 4.0.2 and GMP 6.1.2 (these version numbers -do NOT correspond to the X.Y.Z suffix of libgmp.so.X.Y.Z and libmpfr.so.X.Y.Z; -see the SPEX user guide for details). + `suitesparse_config;mongoose;amd;btf;camd;ccolamd;colamd;cholmod;cxsparse;ldl;klu;umfpack;paru;rbio;spqr;spex;graphblas;lagraph` -To compile the libraries and install them only in SuiteSparse/lib (not -/usr/local/lib), do this instead in the top-level of SuiteSparse: + Additionally, `csparse` can be included in that list to build CSparse. - make local +* `CMAKE_BUILD_TYPE`: -If you add /home/me/SuiteSparse/lib to your library search path -(`LD_LIBRARY_PATH` in Linux), you can do the following (for example): + Default: `Release`, use `Debug` for debugging. - S = /home/me/SuiteSparse - cc myprogram.c -I$(S)/include -lumfpack -lamd -lcholmod -lsuitesparseconfig -lm +* `SUITESPARSE_USE_STRICT`: -To change the C and C++ compilers, and to compile in parallel use: + SuiteSparse has many user-definable settings of the form `SUITESPARSE_USE_*` + or `(package)_USE_*` for some particular package. In general, these settings + are not strict. For example, if `SUITESPARSE_USE_OPENMP` is `ON` then OpenMP + is preferred, but SuiteSparse can be used without OpenMP so no error is + generated if OpenMP is not found. However, if `SUITESPARSE_USE_STRICT` is + `ON` then all `*_USE_*` settings are treated strictly and an error occurs + if any are set to `ON` but the corresponding package or setting is not + available. The `*_USE_SYSTEM_*` settings are always treated as strict. + Default: `OFF`. - CC=gcc CX=g++ JOBS=32 make +* `SUITESPARSE_USE_CUDA`: -for example, which changes the compiler to gcc and g++, and runs make with -'make -j32', in parallel with 32 jobs. + If set to `ON`, CUDA is enabled for all of SuiteSparse. Default: `ON`, -This will work on Linux/Unix and the Mac. It should automatically detect if -you have the Intel compilers or not, and whether or not you have CUDA. + CUDA on Windows with MSVC appears to be working with this release, but it + should be considered as a prototype and may not be fully functional. I have + limited resources for testing CUDA on Windows. If you encounter issues, + disable CUDA and post this as an issue on GitHub. -NOTE: Use of the Intel MKL BLAS is strongly recommended. The OpenBLAS can -(rarely) result in severe performance degradation, in CHOLMOD in particular. -The reason for this is still under investigation and might already be resolved -in the current version of OpenBLAS. See -`SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake` to select your BLAS. +* `CHOLMOD_USE_CUDA`: -You may also need to add SuiteSparse/lib to your path. If your copy of -SuiteSparse is in /home/me/SuiteSparse, for example, then add this to your -~/.bashrc file: + Default: `ON`. Both `SUITESPARSE_USE_CUDA` and `CHOLMOD_USE_CUDA` must be + enabled to use CUDA in CHOLMOD. - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/me/SuiteSparse/lib - export LD_LIBRARY_PATH +* `SPQR_USE_CUDA`: -For the Mac, use this instead: + Default: `ON`. Both `SUITESPARSE_USE_CUDA` and `SPQR_USE_CUDA` must be + enabled to use CUDA in SPQR. - DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/home/me/SuiteSparse/lib - export DYLD_LIBRARY_PATH +* `CMAKE_INSTALL_PREFIX`: ------------------------------------------------------------------------------ -Python interface ------------------------------------------------------------------------------ + Defines the install location (default on Linux is `/usr/local`). For example, + this command while in a folder `build` in the top level SuiteSparse folder + will set the install directory to `/stuff`, used by the subsequent + `sudo cmake --install .`: +``` + cmake -DCMAKE_INSTALL_PREFIX=/stuff .. + sudo cmake --install . +``` -See scikit-sparse and scikit-umfpack for the Python interface via SciPy: +* `SUITESPARSE_PKGFILEDIR`: -https://github.com/scikit-sparse/scikit-sparse + Directory where CMake Config and pkg-config files will be installed. By + default, CMake Config files will be installed in the subfolder `cmake` of the + directory where the (static) libraries will be installed (e.g., `lib`). The + `.pc` files for pkg-config will be installed in the subfolder `pkgconfig` of + the directory where the (static) libraries will be installed. -https://github.com/scikit-umfpack/scikit-umfpack + This option allows to install them at a location different from the (static) + libraries. This allows to install multiple configurations of the SuiteSparse + libraries at the same time (e.g., by also setting a different + `CMAKE_RELEASE_POSTFIX` and `CMAKE_INSTALL_LIBDIR` for each of them). To pick + up the respective configuration in downstream projects, set, e.g., + `CMAKE_PREFIX_PATH` (for CMake) or `PKG_CONFIG_PATH` (for build systems using + pkg-config) to the path containing the respective CMake Config files or + pkg-config files. + +* `SUITESPARSE_INCLUDEDIR_POSTFIX`: + + Postfix for installation target of header from SuiteSparse. Default: + suitesparse, so the default include directory is: + `CMAKE_INSTALL_PREFIX/include/suitesparse` + +* `BUILD_SHARED_LIBS`: + + If `ON`, shared libraries are built. + Default: `ON`. + +* `BUILD_STATIC_LIBS`: + + If `ON`, static libraries are built. + Default: `ON`, except for GraphBLAS, which takes a long time to compile so + the default for GraphBLAS is `OFF` unless `BUILD_SHARED_LIBS` is `OFF`. + +* `SUITESPARSE_CUDA_ARCHITECTURES`: + + A string, such as `"all"` or `"35;50;75;80"` that lists the CUDA + architectures to use when compiling CUDA kernels with `nvcc`. The `"all"` + option requires CMake 3.23 or later. Default: `"52;75;80"`. + +* `BLA_VENDOR`: + + A string. Leave unset, or use `"ANY"` to select any BLAS library (the + default). Or set to the name of a `BLA_VENDOR` defined by FindBLAS.cmake. + See: + https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors + +* `SUITESPARSE_USE_64BIT_BLAS`: + + If `ON`, look for a 64-bit BLAS. If `OFF`: 32-bit only. Default: `OFF`. + +* `SUITESPARSE_USE_OPENMP`: + + If `ON`, OpenMP is used by default if it is available. Default: `ON`. + + GraphBLAS, LAGraph, and ParU will be vastly slower if OpenMP is not used. + CHOLMOD will be somewhat slower without OpenMP (as long as it still has a + parallel BLAS/LAPACK). Three packages (UMFPACK, CHOLMOD, and SPQR) rely + heavily on parallel BLAS/LAPACK libraries and those libraries may use OpenMP + internally. If you wish to disable OpenMP in an entire application, select a + single-threaded BLAS/LAPACK, or a parallel BLAS/LAPACK that does not use + OpenMP (such as the Apple Accelerate Framework). Using a single-threaded + BLAS/LAPACK library will cause UMFPACK, CHOLMOD, and SPQR to be vastly + slower. + + WARNING: GraphBLAS may not be thread-safe if built without OpenMP or pthreads + (see the GraphBLAS User Guide for details). + +* `SUITESPARSE_CONFIG_USE_OPENMP`: + + If `ON`, `SuiteSparse_config` uses OpenMP if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + It is not essential and only used to let `SuiteSparse_time` call + `omp_get_wtime`. + +* `CHOLMOD_USE_OPENMP`: + + If `ON`, OpenMP is used in CHOLMOD if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `GRAPHBLAS_USE_OPENMP`: + + If `ON`, OpenMP is used in GraphBLAS if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `LAGRAPH_USE_OPENMP`: + + If `ON`, OpenMP is used in LAGraph if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `PARU_USE_OPENMP`: + + If `ON`, OpenMP is used in ParU if it is available. + Default: `SUITESPARSE_USE_OPENMP`. + +* `SUITESPARSE_DEMOS`: + + If `ON`, build the demo programs for each package. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_BTF`: + + If `ON`, use BTF libraries installed on the build system. If `OFF`, + automatically build BTF as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_CHOLMOD`: + + If `ON`, use CHOLMOD libraries installed on the build system. If `OFF`, + automatically build CHOLMOD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_AMD`: + + If `ON`, use AMD libraries installed on the build system. If `OFF`, + automatically build AMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_COLAMD`: + + If `ON`, use COLAMD libraries installed on the build system. If `OFF`, + automatically build COLAMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_CAMD`: + + If `ON`, use CAMD libraries installed on the build system. If `OFF`, + automatically build CAMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_CCOLAMD`: + + If `ON`, use CCOLAMD libraries installed on the build system. If `OFF`, + automatically build CCOLAMD as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_GRAPHBLAS`: + + If `ON`, use GraphBLAS libraries installed on the build system. If `OFF`, + automatically build GraphBLAS as dependency if needed. Default: `OFF`. + +* `SUITESPARSE_USE_SYSTEM_SUITESPARSE_CONFIG`: + + If `ON`, use `SuiteSparse_config` libraries installed on the build system. If + `OFF`, automatically build `SuiteSparse_config` as dependency if needed. + Default: `OFF`. + +* `SUITESPARSE_USE_FORTRAN` + + If `ON`, use the Fortran compiler to determine how C calls Fortan, and to + build several optional Fortran routines. If `OFF`, use + `SUITESPARSE_C_TO_FORTRAN` to define how C calls Fortran (see + `SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake` for details). + Default: `ON`. + +Additional options are available for specific packages: + +* `UMFPACK_USE_CHOLMOD`: + + If `ON`, UMFPACK uses CHOLMOD for additional (optional) + ordering options. Default: `ON`. + +* `KLU_USE_CHOLMOD`: + + If `ON`, KLU uses CHOLMOD for additional (optional) + ordering options. Default: `ON`. + +CHOLMOD is composed of a set of Modules that can be independently selected; +all options default to `ON`: + +* `CHOLMOD_GPL` + + If `OFF`, do not build any GPL-licensed module (MatrixOps, Modify, Supernodal, + and GPU modules) + +* `CHOLMOD_CHECK` + + If `OFF`, do not build the Check module. + +* `CHOLMOD_MATRIXOPS` + + If `OFF`, do not build the MatrixOps module. + +* `CHOLMOD_CHOLESKY` + If `OFF`, do not build the Cholesky module. This also disables the Supernodal + and Modify modules. + +* `CHOLMOD_MODIFY` + + If `OFF`, do not build the Modify module. + +* `CHOLMOD_CAMD` + + If `OFF`, do not link against CAMD and CCOLAMD. This also disables the + Partition module. + +* `CHOLMOD_PARTITION` + + If `OFF`, do not build the Partition module. + +* `CHOLMOD_SUPERNODAL` + + If `OFF`, do not build the Supernodal module. ----------------------------------------------------------------------------- -Compilation options +Possible build/install issues ----------------------------------------------------------------------------- -You can set specific options for CMake with the command (for example): +One common issue can affect all packages: getting the right #include files +that match the current libraries being built. It's possible that your Linux +distro has an older copy of SuiteSparse headers in /usr/include or +/usr/local/include, or that Homebrew has installed its suite-sparse bundle into +/opt/homebrew/include or other places. Old libraries can appear in in +/usr/local/lib, /usr/lib, etc. When building a new copy of SuiteSparse, the +cmake build system is normally (or always?) able to avoid these, and use the +right header for the right version of each library. + +As an additional guard against this possible error, each time one SuiteSparse +package #include's a header from another one, it checks the version number in +the header file, and reports an #error to the compiler if a stale version is +detected. In addition, the Example package checks both the header version and +the library version (by calling a function in each library). If the versions +mismatch in any way, the Example package reports an error at run time. + +For example, CHOLMOD 5.1.0 requires AMD 3.3.0 or later. If it detects an +older one in `amd.h`, it will report an `#error`: + +``` + #include "amd.h" + #if ( ... AMD version is stale ... ) + #error "CHOLMOD 5.1.0 requires AMD 3.3.0 or later" + #endif +``` + +and the compilation will fail. The Example package makes another check, +by calling `amd_version` and comparing it with the versions from the `amd.h` +header file. + +If this error or one like it occurs, check to see if you have an old copy of +SuiteSparse, and uninstall it before compiling your new copy of SuiteSparse. + +There are other many possible build/install issues that are covered by the +corresponding user guides for each package, such as finding the right BLAS, +OpenMP, and other libraries, and how to compile on the Mac when using GraphBLAS +inside MATLAB, and so on. Refer to the User Guides for more details. - CMAKE_OPTIONS="-DNPARTITION=1 -DNSTATIC=1 -DCMAKE_BUILD_TYPE=Debug" make +----------------------------------------------------------------------------- +Interfaces to SuiteSparse +----------------------------------------------------------------------------- -That command will compile all of SuiteSparse except for CHOLMOD/Partition -Module. Debug mode will be used. The static libraries will not be built -(NSTATIC is true). - - CMAKE_BUILD_TYPE: Default: "Release", use "Debug" for debugging. - - ENABLE_CUDA: if set to true, CUDA is enabled for the project. - Default: true for CHOLMOD and SPQR; false otherwise - - LOCAL_INSTALL: if true, "cmake --install" will install - into SuiteSparse/lib and SuiteSparse/include. - if false, "cmake --install" will install into the - default prefix (or the one configured with - CMAKE_INSTALL_PREFIX). - Default: false - - NSTATIC: if true, static libraries are not built. - Default: false, except for GraphBLAS, which - takes a long time to compile so the default for - GraphBLAS is true. For Mongoose, the NSTATIC setting - is treated as if it always false, since the mongoose - program is built with the static library. - - SUITESPARSE_CUDA_ARCHITECTURES: a string, such as "all" or - "35;50;75;80" that lists the CUDA architectures to use - when compiling CUDA kernels with nvcc. The "all" - option requires cmake 3.23 or later. - Default: "52;75;80". - - BLA_VENDOR a string. Leave unset, or use "ANY" to select any BLAS - library (the default). Or set to the name of a - BLA_VENDOR defined by FindBLAS.cmake. See: - https://cmake.org/cmake/help/latest/module/FindBLAS.html#blas-lapack-vendors - - ALLOW_64BIT_BLAS if true: look for a 64-bit BLAS. If false: 32-bit only. - Default: false. - - NOPENMP if true: OpenMP is not used. Default: false. - UMFPACK, CHOLMOD, SPQR, and GraphBLAS will be slow. - Note that BLAS and LAPACK may still use OpenMP - internally; if you wish to disable OpenMP in an entire - application, select a single-threaded BLAS/LAPACK. - WARNING: GraphBLAS may not be thread-safe if built - without OpenMP (see the User Guide for details). - - DEMO if true: build the demo programs for each package. - Default: false. - -Additional options are available within specific packages: - - NCHOLMOD if true, UMFPACK and KLU do not use CHOLMOD for - additional (optional) ordering options +MATLAB/Octave/R/Mathematica interfaces: -CHOLMOD is composed of a set of Modules that can be independently selected; -all options default to false: - - NGL if true: do not build any GPL-licensed module - (MatrixOps, Modify, Supernodal, and GPU modules) - NCHECK if true: do not build the Check module. - NMATRIXOPS if true: do not build the MatrixOps module. - NCHOLESKY if true: do not build the Cholesky module. - This also disables the Supernodal and Modify modules. - NMODIFY if true: do not build the Modify module. - NCAMD if true: do not link against CAMD and CCOLAMD. - This also disables the Partition module. - NPARTITION if true: do not build the Partition module. - NSUPERNODAL if true: do not build the Supernodal module. + Many built-in methods in MATLAB and Octave rely on SuiteSparse, including + `C=A*B` `x=A\b`, `L=chol(A)`, `[L,U,P,Q]=lu(A)`, `R=qr(A)`, `dmperm(A)`, + `p=amd(A)`, `p=colamd(A)`, ... + See also Mathematica, R, and many many more. The list is too long. + +Julia interface: + + https://github.com/JuliaSparse/SparseArrays.jl + +python interface to GraphBLAS by Anaconda and NVIDIA: + + https://pypi.org/project/python-graphblas + +Intel's Go interface to GraphBLAS: + + https://pkg.go.dev/github.com/intel/forGraphBLASGo + +See scikit-sparse and scikit-umfpack for the Python interface via SciPy: + + https://github.com/scikit-sparse/scikit-sparse + https://github.com/scikit-umfpack/scikit-umfpack + +See russell for a Rust interface: + + https://github.com/cpmech/russell ----------------------------------------------------------------------------- Acknowledgements ----------------------------------------------------------------------------- -I would like to thank François Bissey, Sebastien Villemot, Erik Welch, Jim -Kitchen, Markus Mützel, and Fabian Wein for their valuable feedback on the +Markus Mützel contributed the most recent update of the SuiteSparse build +system for all SuiteSparse packages, extensively porting it and modernizing it. + +I would also like to thank François Bissey, Sebastien Villemot, Erik Welch, Jim +Kitchen, and Fabian Wein for their valuable feedback on the SuiteSparse build system and how it works with various Linux / Python distros and other package managers. If you are a maintainer of a SuiteSparse packaging for a Linux distro, conda-forge, R, spack, brew, vcpkg, etc, please feel free to contact me if there's anything I can do to make your life easier. +I would also like to thank Raye Kimmerer for adding support for 32-bit +row/column indices in SPQR v4.2.0. See also the various Acknowledgements within each package. diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.h.in b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.h.in index 09d05c9222..0d203f55e6 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.h.in +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.h.in @@ -368,13 +368,24 @@ int SuiteSparse_divcomplex // determine which timer to use, if any #ifndef NTIMER + // SuiteSparse_config itself can be compiled without OpenMP, + // but other packages can themselves use OpenMP. In this case, + // those packages should use omp_get_wtime() directly. This can + // be done via the SUITESPARSE_TIME macro, defined below: + #cmakedefine SUITESPARSE_HAVE_CLOCK_GETTIME #if defined ( _OPENMP ) #define SUITESPARSE_TIMER_ENABLED - #elif defined ( _POSIX_C_SOURCE ) - #if _POSIX_C_SOURCE >= 199309L + #define SUITESPARSE_TIME (omp_get_wtime ( )) + #elif defined ( SUITESPARSE_HAVE_CLOCK_GETTIME ) #define SUITESPARSE_TIMER_ENABLED - #endif + #define SUITESPARSE_TIME (SuiteSparse_time ( )) + #else + // No timer is available + #define SUITESPARSE_TIME (0) #endif +#else + // The timer is explictly disabled + #define SUITESPARSE_TIME (0) #endif // SuiteSparse printf macro @@ -414,9 +425,14 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_SUB_VERSION @SUITESPARSE_VERSION_MINOR@ #define SUITESPARSE_SUBSUB_VERSION @SUITESPARSE_VERSION_SUB@ +// version format x.y #define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_VERSION \ - SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) +#define SUITESPARSE_VERSION SUITESPARSE_VER_CODE(@SUITESPARSE_VERSION_MAJOR@, @SUITESPARSE_VERSION_MINOR@) + +// version format x.y.z +#define SUITESPARSE__VERCODE(main,sub,patch) \ + (((main)*1000ULL + (sub))*1000ULL + (patch)) +#define SUITESPARSE__VERSION SUITESPARSE__VERCODE(@SUITESPARSE_VERSION_MAJOR@,@SUITESPARSE_VERSION_MINOR@,@SUITESPARSE_VERSION_SUB@) //============================================================================== // SuiteSparse interface to the BLAS and LAPACK libraries @@ -469,7 +485,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #elif defined ( BLAS_UNDERSCORE ) - // append an undescore, use lower case + // append an underscore, use lower case #define SUITESPARSE_FORTRAN(name,NAME) name ## _ #define SUITESPARSE__FORTRAN(name,NAME) name ## _ @@ -529,12 +545,12 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION // If the suffix does not contain "_", use (Sun Perf., for example): -// cd build ; cmake -DBLAS64_SUFFIX="64" .. +// cd build && cmake -DBLAS64_SUFFIX="64" .. // If the suffix contains "_" (OpenBLAS in spack for example), use the // following: -// cd build ; cmake -DBLAS64_SUFFIX="_64" .. +// cd build && cmake -DBLAS64_SUFFIX="_64" .. // This setting could be used by the spack packaging of SuiteSparse when linked // with the spack-installed OpenBLAS with 64-bit integers. See @@ -572,6 +588,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION // C names of Fortan BLAS and LAPACK functions used by SuiteSparse //------------------------------------------------------------------------------ +// double #define SUITESPARSE_BLAS_DTRSV SUITESPARSE_BLAS ( dtrsv , DTRSV ) #define SUITESPARSE_BLAS_DGEMV SUITESPARSE_BLAS ( dgemv , DGEMV ) #define SUITESPARSE_BLAS_DTRSM SUITESPARSE_BLAS ( dtrsm , DTRSM ) @@ -579,8 +596,15 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_DSYRK SUITESPARSE_BLAS ( dsyrk , DSYRK ) #define SUITESPARSE_BLAS_DGER SUITESPARSE_BLAS ( dger , DGER ) #define SUITESPARSE_BLAS_DSCAL SUITESPARSE_BLAS ( dscal , DSCAL ) +#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) + #define SUITESPARSE_LAPACK_DPOTRF SUITESPARSE_BLAS ( dpotrf , DPOTRF ) +#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) +#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) +#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) +#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) +// double complex #define SUITESPARSE_BLAS_ZTRSV SUITESPARSE_BLAS ( ztrsv , ZTRSV ) #define SUITESPARSE_BLAS_ZGEMV SUITESPARSE_BLAS ( zgemv , ZGEMV ) #define SUITESPARSE_BLAS_ZTRSM SUITESPARSE_BLAS ( ztrsm , ZTRSM ) @@ -588,20 +612,46 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_ZHERK SUITESPARSE_BLAS ( zherk , ZHERK ) #define SUITESPARSE_BLAS_ZGERU SUITESPARSE_BLAS ( zgeru , ZGERU ) #define SUITESPARSE_BLAS_ZSCAL SUITESPARSE_BLAS ( zscal , ZSCAL ) -#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) - -#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) -#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) -#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) -#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) -#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) - #define SUITESPARSE_BLAS_DZNRM2 SUITESPARSE_BLAS ( dznrm2 , DZNRM2 ) + +#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) #define SUITESPARSE_LAPACK_ZLARF SUITESPARSE_BLAS ( zlarf , ZLARF ) #define SUITESPARSE_LAPACK_ZLARFG SUITESPARSE_BLAS ( zlarfg , ZLARFG ) #define SUITESPARSE_LAPACK_ZLARFT SUITESPARSE_BLAS ( zlarft , ZLARFT ) #define SUITESPARSE_LAPACK_ZLARFB SUITESPARSE_BLAS ( zlarfb , ZLARFB ) +// single +#define SUITESPARSE_BLAS_STRSV SUITESPARSE_BLAS ( strsv , STRSV ) +#define SUITESPARSE_BLAS_SGEMV SUITESPARSE_BLAS ( sgemv , SGEMV ) +#define SUITESPARSE_BLAS_STRSM SUITESPARSE_BLAS ( strsm , STRSM ) +#define SUITESPARSE_BLAS_SGEMM SUITESPARSE_BLAS ( sgemm , SGEMM ) +#define SUITESPARSE_BLAS_SSYRK SUITESPARSE_BLAS ( ssyrk , SSYRK ) +#define SUITESPARSE_BLAS_SGER SUITESPARSE_BLAS ( sger , SGER ) +#define SUITESPARSE_BLAS_SSCAL SUITESPARSE_BLAS ( sscal , SSCAL ) +#define SUITESPARSE_BLAS_SNRM2 SUITESPARSE_BLAS ( snrm2 , SNRM2 ) + +#define SUITESPARSE_LAPACK_SPOTRF SUITESPARSE_BLAS ( spotrf , SPOTRF ) +#define SUITESPARSE_LAPACK_SLARF SUITESPARSE_BLAS ( slarf , SLARF ) +#define SUITESPARSE_LAPACK_SLARFG SUITESPARSE_BLAS ( slarfg , SLARFG ) +#define SUITESPARSE_LAPACK_SLARFT SUITESPARSE_BLAS ( slarft , SLARFT ) +#define SUITESPARSE_LAPACK_SLARFB SUITESPARSE_BLAS ( slarfb , SLARFB ) + +// single complex +#define SUITESPARSE_BLAS_CTRSV SUITESPARSE_BLAS ( ctrsv , CTRSV ) +#define SUITESPARSE_BLAS_CGEMV SUITESPARSE_BLAS ( cgemv , CGEMV ) +#define SUITESPARSE_BLAS_CTRSM SUITESPARSE_BLAS ( ctrsm , CTRSM ) +#define SUITESPARSE_BLAS_CGEMM SUITESPARSE_BLAS ( cgemm , CGEMM ) +#define SUITESPARSE_BLAS_CHERK SUITESPARSE_BLAS ( cherk , CHERK ) +#define SUITESPARSE_BLAS_CGERU SUITESPARSE_BLAS ( cgeru , CGERU ) +#define SUITESPARSE_BLAS_CSCAL SUITESPARSE_BLAS ( cscal , CSCAL ) +#define SUITESPARSE_BLAS_SCNRM2 SUITESPARSE_BLAS ( scnrm2 , SCNRM2 ) + +#define SUITESPARSE_LAPACK_CPOTRF SUITESPARSE_BLAS ( cpotrf , CPOTRF ) +#define SUITESPARSE_LAPACK_CLARF SUITESPARSE_BLAS ( clarf , CLARF ) +#define SUITESPARSE_LAPACK_CLARFG SUITESPARSE_BLAS ( clarfg , CLARFG ) +#define SUITESPARSE_LAPACK_CLARFT SUITESPARSE_BLAS ( clarft , CLARFT ) +#define SUITESPARSE_LAPACK_CLARFB SUITESPARSE_BLAS ( clarfb , CLARFB ) + //------------------------------------------------------------------------------ // prototypes of BLAS and SUITESPARSE_LAPACK functions //------------------------------------------------------------------------------ @@ -627,7 +677,11 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #if defined ( SUITESPARSE_BLAS_DEFINITIONS ) -void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ +// gemv: Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMV ( // input: const char *trans, @@ -659,7 +713,39 @@ void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y } \ } -void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y +void SUITESPARSE_BLAS_SGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *beta, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGEMV ( // input: const char *trans, @@ -691,7 +777,43 @@ void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y } \ } -void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b +void SUITESPARSE_BLAS_CGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *beta, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsv: solve Lx=b, Ux=b, L'x=b, or U'x=b +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSV ( // input: const char *uplo, @@ -718,7 +840,34 @@ void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b } \ } -void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b +void SUITESPARSE_BLAS_STRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_strsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSV ( // input: const char *uplo, @@ -745,7 +894,38 @@ void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b } \ } -void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B +void SUITESPARSE_BLAS_CTRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_ctrsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsm: solve LX=B, UX=B, L'X=B, or U'X=B +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSM ( // input: const char *side, @@ -776,7 +956,38 @@ void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B } \ } -void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B +void SUITESPARSE_BLAS_STRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_strsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSM ( // input: const char *side, @@ -807,7 +1018,42 @@ void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B } \ } -void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_CTRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_ctrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// gemm: C = alpha*A*B + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMM ( // input: const char *transa, @@ -844,7 +1090,7 @@ void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C } \ } -void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_SGEMM ( // input: const char *transa, @@ -852,19 +1098,19 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const void *alpha, - const void *A, + const float *alpha, + const float *A, const SUITESPARSE_BLAS_INT *lda, - const void *B, + const float *B, const SUITESPARSE_BLAS_INT *ldb, - const void *beta, + const float *beta, // input/output: - void *C, + float *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ +#define SUITESPARSE_BLAS_sgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ @@ -875,52 +1121,62 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + SUITESPARSE_BLAS_SGEMM (transa, transb, &M_blas_int, &N_blas_int, \ &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_DSYRK // C = alpha*A*A' + beta*C, or A'A +void SUITESPARSE_BLAS_ZGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const double *alpha, - const double *A, + const void *alpha, + const void *A, const SUITESPARSE_BLAS_INT *lda, - const double *beta, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, + const void *beta, // input/output: - double *C, + void *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A +void SUITESPARSE_BLAS_CGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, const void *alpha, const void *A, const SUITESPARSE_BLAS_INT *lda, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, const void *beta, // input/output: void *C, @@ -928,47 +1184,206 @@ void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_cgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_CGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_DPOTRF // Cholesky factorization +//------------------------------------------------------------------------------ +// syrk/herk: C = alpha*A*A' + beta*C ; or C = alpha*A'*A + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSYRK ( // input: const char *uplo, + const char *trans, const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const double *alpha, + const double *A, + const SUITESPARSE_BLAS_INT *lda, + const double *beta, // input/output: - double *A, + double *C, // input: - const SUITESPARSE_BLAS_INT *lda, - // output: - SUITESPARSE_BLAS_INT *info + const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ - info = 1 ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ - SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ - &LAPACK_Info) ; \ - info = (Int) LAPACK_Info ; \ + SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization +void SUITESPARSE_BLAS_SSYRK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *beta, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_ssyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_CHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_cherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// potrf: Cholesky factorization +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + double *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_SPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_spotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_SPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZPOTRF ( // input: const char *uplo, @@ -995,7 +1410,38 @@ void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization } \ } -void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y +void SUITESPARSE_LAPACK_CPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_cpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_CPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = LAPACK_Info ; \ + } \ +} + +//------------------------------------------------------------------------------ +// scal: Y = alpha*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1016,7 +1462,28 @@ void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y +void SUITESPARSE_BLAS_SSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1037,7 +1504,32 @@ void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A +void SUITESPARSE_BLAS_CSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// ger/geru: A = alpha*x*y' + A +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGER ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1067,7 +1559,37 @@ void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A } \ } -void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A +void SUITESPARSE_BLAS_SGER +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_sger(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGER (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGERU ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1097,7 +1619,41 @@ void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A } \ } -void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor +void SUITESPARSE_BLAS_CGERU +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_cgeru(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGERU (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larft: T = block Householder factor +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFT ( // input: const char *direct, @@ -1126,7 +1682,36 @@ void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor +void SUITESPARSE_LAPACK_SLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *Tau, + // output: + float *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_slarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFT ( // input: const char *direct, @@ -1155,7 +1740,40 @@ void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_CLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *Tau, + // output: + void *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_clarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfb: apply block Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFB ( // input: const char *side, @@ -1197,7 +1815,49 @@ void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_SLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_slarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFB ( // input: const char *side, @@ -1239,7 +1899,53 @@ void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector } \ } -double SUITESPARSE_BLAS_DNRM2 // vector 2-norm +void SUITESPARSE_LAPACK_CLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_clarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// nrm2: vector 2-norm +//------------------------------------------------------------------------------ + +double SUITESPARSE_BLAS_DNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1258,7 +1964,26 @@ double SUITESPARSE_BLAS_DNRM2 // vector 2-norm } \ } -double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm +float SUITESPARSE_BLAS_SNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_snrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +double SUITESPARSE_BLAS_DZNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1277,7 +2002,30 @@ double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm } \ } -void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector +float SUITESPARSE_BLAS_SCNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_scnrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SCNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfg: generate Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1301,7 +2049,31 @@ void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector +void SUITESPARSE_LAPACK_SLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *alpha, + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + float *tau +) ; + +#define SUITESPARSE_LAPACK_slarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1325,7 +2097,35 @@ void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_DLARF // apply Householder reflector +void SUITESPARSE_LAPACK_CLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *alpha, + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + void *tau +) ; + +#define SUITESPARSE_LAPACK_clarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larf: apply Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARF ( // input: const char *side, @@ -1355,7 +2155,37 @@ void SUITESPARSE_LAPACK_DLARF // apply Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector +void SUITESPARSE_LAPACK_SLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *V, + const SUITESPARSE_BLAS_INT *incv, + const float *tau, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work +) ; + +#define SUITESPARSE_LAPACK_slarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARF ( // input: const char *side, @@ -1385,6 +2215,36 @@ void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector } \ } +void SUITESPARSE_LAPACK_CLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *V, + const SUITESPARSE_BLAS_INT *incv, + const void *tau, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work +) ; + +#define SUITESPARSE_LAPACK_clarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + #endif //------------------------------------------------------------------------------ diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.pc.in b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.pc.in new file mode 100644 index 0000000000..f082c22602 --- /dev/null +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.pc.in @@ -0,0 +1,16 @@ +# SuiteSparse_config, Copyright (c) 2012-2023, Timothy A. Davis. +# All Rights Reserved. +# SPDX-License-Identifier: BSD-3-clause + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: SuiteSparseConfig +URL: https://github.com/DrTimothyAldenDavis/SuiteSparse +Description: Configuration for SuiteSparse +Version: @SUITESPARSE_VERSION_MAJOR@.@SUITESPARSE_VERSION_MINOR@.@SUITESPARSE_VERSION_SUB@ +Libs: -L${libdir} -l@SUITESPARSE_LIB_BASE_NAME@ +Libs.private: @SUITESPARSE_CONFIG_STATIC_LIBS@ +Cflags: -I${includedir} diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_configConfig.cmake.in b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_configConfig.cmake.in new file mode 100644 index 0000000000..1831e466ab --- /dev/null +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_configConfig.cmake.in @@ -0,0 +1,171 @@ +#------------------------------------------------------------------------------- +# SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse_configConfig.cmake +#------------------------------------------------------------------------------- + +# The following copyright and license applies to just this file only, not to +# the library itself: +# SuiteSparse_configConfig.cmake, Copyright (c) 2023, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: BSD-3-clause + +#------------------------------------------------------------------------------- + +# Finds the SuiteSparse_config include file and compiled library. +# The following targets are defined: +# SuiteSparseConfig - for the shared library (if available) +# SuiteSparseConfig_static - for the static library (if available) + +# For backward compatibility the following variables are set: + +# SUITESPARSE_CONFIG_INCLUDE_DIR - where to find SuiteSparse_config.h +# SUITESPARSE_CONFIG_LIBRARY - dynamic SuiteSparse_config library +# SUITESPARSE_CONFIG_STATIC - static SuiteSparse_config library +# SUITESPARSE_CONFIG_LIBRARIES - libraries when using SuiteSparse_config +# SUITESPARSE_CONFIG_FOUND - true if SuiteSparse_config found + +# Set ``CMAKE_MODULE_PATH`` to the parent folder where this module file is +# installed. + +#------------------------------------------------------------------------------- + +@PACKAGE_INIT@ + +set ( SUITESPARSE_DATE "@SUITESPARSE_DATE@" ) +set ( SUITESPARSE_CONFIG_VERSION_MAJOR @SUITESPARSE_VERSION_MAJOR@ ) +set ( SUITESPARSE_CONFIG_VERSION_MINOR @SUITESPARSE_VERSION_MINOR@ ) +set ( SUITESPARSE_CONFIG_VERSION_PATCH @SUITESPARSE_VERSION_SUB@ ) +set ( SUITESPARSE_CONFIG_VERSION "@SUITESPARSE_VERSION_MAJOR@.@SUITESPARSE_VERSION_MINOR@.@SUITESPARSE_VERSION_SUB@" ) + +# Check for dependent targets +include ( CMakeFindDependencyMacro ) +set ( _dependencies_found ON ) + +# Look for OpenMP +if ( @SUITESPARSE_CONFIG_HAS_OPENMP@ AND NOT OpenMP_C_FOUND ) + find_dependency ( OpenMP COMPONENTS C ) + if ( NOT OpenMP_C_FOUND ) + set ( _dependencies_found OFF ) + endif ( ) +endif ( ) + +if ( NOT _dependencies_found ) + set ( SuiteSparse_config_FOUND OFF ) + return ( ) +endif ( ) + + +# Import target +include ( ${CMAKE_CURRENT_LIST_DIR}/SuiteSparse_configTargets.cmake ) + +if ( @SUITESPARSE_CONFIG_HAS_OPENMP@ ) + if ( TARGET SuiteSparse::SuiteSparseConfig ) + get_property ( _suitesparse_config_aliased TARGET SuiteSparse::SuiteSparseConfig + PROPERTY ALIASED_TARGET ) + if ( "${_suitesparse_config_aliased}" STREQUAL "" ) + target_include_directories ( SuiteSparse::SuiteSparseConfig SYSTEM AFTER INTERFACE + "$" ) + else ( ) + target_include_directories ( ${_suitesparse_config_aliased} SYSTEM AFTER INTERFACE + "$" ) + endif ( ) + endif ( ) + if ( TARGET SuiteSparse::SuiteSparseConfig_static ) + get_property ( _suitesparse_config_aliased TARGET SuiteSparse::SuiteSparseConfig_static + PROPERTY ALIASED_TARGET ) + if ( "${_suitesparse_config_aliased}" STREQUAL "" ) + target_include_directories ( SuiteSparse::SuiteSparseConfig_static SYSTEM AFTER INTERFACE + "$" ) + else ( ) + target_include_directories ( ${_suitesparse_config_aliased} SYSTEM AFTER INTERFACE + "$" ) + endif ( ) + endif ( ) +endif ( ) + + +# The following is only for backward compatibility with FindSuiteSparse_config. + +set ( _target_shared SuiteSparse::SuiteSparseConfig ) +set ( _target_static SuiteSparse::SuiteSparseConfig_static ) +set ( _var_prefix "SUITESPARSE_CONFIG" ) + +if ( NOT @BUILD_SHARED_LIBS@ AND NOT TARGET ${_target_shared} ) + # make sure there is always an import target without suffix ) + add_library ( ${_target_shared} ALIAS ${_target_static} ) +endif ( ) + +get_target_property ( ${_var_prefix}_INCLUDE_DIR ${_target_shared} INTERFACE_INCLUDE_DIRECTORIES ) +if ( ${_var_prefix}_INCLUDE_DIR ) + # First item in SuiteSparse targets contains the "main" header directory. + list ( GET ${_var_prefix}_INCLUDE_DIR 0 ${_var_prefix}_INCLUDE_DIR ) +endif ( ) +get_target_property ( ${_var_prefix}_LIBRARY ${_target_shared} IMPORTED_IMPLIB ) +if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} IMPORTED_LOCATION ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) +endif ( ) +if ( TARGET ${_target_static} ) + get_target_property ( ${_var_prefix}_STATIC ${_target_static} IMPORTED_LOCATION ) +endif ( ) + +# Check for most common build types +set ( _config_types "Debug" "Release" "RelWithDebInfo" "MinSizeRel" "None" ) + +get_property ( _isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG ) +if ( _isMultiConfig ) + # For multi-configuration generators (e.g., Visual Studio), prefer those + # configurations. + list ( PREPEND _config_types ${CMAKE_CONFIGURATION_TYPES} ) +else ( ) + # For single-configuration generators, prefer the current configuration. + list ( PREPEND _config_types ${CMAKE_BUILD_TYPE} ) +endif ( ) + +list ( REMOVE_DUPLICATES _config_types ) + +foreach ( _config ${_config_types} ) + string ( TOUPPER ${_config} _uc_config ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_IMPLIB_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( NOT ${_var_prefix}_LIBRARY ) + get_target_property ( _library_chk ${_target_shared} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_LIBRARY ${_library_chk} ) + endif ( ) + endif ( ) + if ( TARGET ${_target_static} AND NOT ${_var_prefix}_STATIC ) + get_target_property ( _library_chk ${_target_static} + IMPORTED_LOCATION_${_uc_config} ) + if ( EXISTS ${_library_chk} ) + set ( ${_var_prefix}_STATIC ${_library_chk} ) + endif ( ) + endif ( ) +endforeach ( ) + +set ( SUITESPARSE_CONFIG_LIBRARIES ${SUITESPARSE_CONFIG_LIBRARY} ) + +macro ( suitesparse_check_exist _var _files ) + # ignore generator expressions + string ( GENEX_STRIP "${_files}" _files2 ) + + foreach ( _file ${_files2} ) + if ( NOT EXISTS "${_file}" ) + message ( FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist!" ) + endif ( ) + endforeach () +endmacro ( ) + +suitesparse_check_exist ( SUITESPARSE_CONFIG_INCLUDE_DIR ${SUITESPARSE_CONFIG_INCLUDE_DIR} ) +suitesparse_check_exist ( SUITESPARSE_CONFIG_LIBRARY ${SUITESPARSE_CONFIG_LIBRARY} ) + +message ( STATUS "SuiteSparse_config version: ${SUITESPARSE_CONFIG_VERSION}" ) +message ( STATUS "SuiteSparse_config include: ${SUITESPARSE_CONFIG_INCLUDE_DIR}" ) +message ( STATUS "SuiteSparse_config library: ${SUITESPARSE_CONFIG_LIBRARY}" ) +message ( STATUS "SuiteSparse_config static: ${SUITESPARSE_CONFIG_STATIC}" ) diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile b/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile index 9893afe789..a14ac2fdf4 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/Makefile @@ -37,18 +37,18 @@ default: library # default is to install only in /usr/local library: - ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) .. && cmake --build . --config Release -j${JOBS} ) # install only in SuiteSparse/lib and SuiteSparse/include local: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=1 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=1 .. && cmake --build . --config Release -j${JOBS} ) # install only in /usr/local (default) global: - ( cd build && cmake $(CMAKE_OPTIONS) -DLOCAL_INSTALL=0 .. && cmake --build . -j${JOBS} ) + ( cd build && cmake $(CMAKE_OPTIONS) -USUITESPARSE_PKGFILEDIR -DSUITESPARSE_LOCAL_INSTALL=0 .. && cmake --build . --config Release -j${JOBS} ) debug: - ( cd build ; cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. ; cmake --build . ) + ( cd build && cmake $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Debug .. ; cmake --build . --config Debug ) all: library @@ -56,14 +56,14 @@ demos: library # just compile after running cmake; do not run cmake again remake: - ( cd build ; cmake --build . ) + ( cd build && cmake --build . ) # just run cmake to set things up setup: - ( cd build ; cmake $(CMAKE_OPTIONS) .. ) + ( cd build && cmake $(CMAKE_OPTIONS) .. ) install: - ( cd build ; cmake --install . ) + ( cd build && cmake --install . ) # remove any installed libraries and #include files uninstall: diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt b/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt index 4ff01953f8..9d306c9e2a 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/README.txt @@ -1,4 +1,4 @@ -SuiteSparse_config, Copyright (c) 2012-2023, Timothy A. Davis. +SuiteSparse_config, Copyright (c) 2012-2024, Timothy A. Davis. All Rights Reserved. SPDX-License-Identifier: BSD-3-clause diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c b/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c index 079093716a..ee220a77f9 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.c @@ -11,7 +11,6 @@ /* SuiteSparse configuration : memory manager and printf functions. */ -#define SUITESPARSE_LIBRARY #include "SuiteSparse_config.h" /* -------------------------------------------------------------------------- */ @@ -496,7 +495,7 @@ void *SuiteSparse_free /* always returns NULL */ tic [1] = 0 ; } -#else +#else /* ---------------------------------------------------------------------- */ /* POSIX timer */ @@ -617,7 +616,7 @@ double SuiteSparse_hypot (double x, double y) r = x / y ; s = y * sqrt (1.0 + r*r) ; } - } + } return (s) ; } @@ -760,6 +759,10 @@ const char *SuiteSparse_BLAS_library ( void ) return ((sizeof (SUITESPARSE_BLAS_INT) == 8) ? "OpenBLAS (64-bit integers)" : "OpenBLAS (32-bit integers)") ; + #elif defined ( BLAS_FLAME ) + return ((sizeof (SUITESPARSE_BLAS_INT) == 8) ? + "FLAME (64-bit integers)" : + "FLAME (32-bit integers)") ; #elif defined ( BLAS_Generic ) return ((sizeof (SUITESPARSE_BLAS_INT) == 8) ? "Reference BLAS (64-bit integers)" : diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h b/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h index 2b917bdeda..d2300dcfc6 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/SuiteSparse_config.h @@ -368,13 +368,24 @@ int SuiteSparse_divcomplex // determine which timer to use, if any #ifndef NTIMER + // SuiteSparse_config itself can be compiled without OpenMP, + // but other packages can themselves use OpenMP. In this case, + // those packages should use omp_get_wtime() directly. This can + // be done via the SUITESPARSE_TIME macro, defined below: + #define SUITESPARSE_HAVE_CLOCK_GETTIME #if defined ( _OPENMP ) #define SUITESPARSE_TIMER_ENABLED - #elif defined ( _POSIX_C_SOURCE ) - #if _POSIX_C_SOURCE >= 199309L + #define SUITESPARSE_TIME (omp_get_wtime ( )) + #elif defined ( SUITESPARSE_HAVE_CLOCK_GETTIME ) #define SUITESPARSE_TIMER_ENABLED - #endif + #define SUITESPARSE_TIME (SuiteSparse_time ( )) + #else + // No timer is available + #define SUITESPARSE_TIME (0) #endif +#else + // The timer is explictly disabled + #define SUITESPARSE_TIME (0) #endif // SuiteSparse printf macro @@ -409,14 +420,19 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_HAS_VERSION_FUNCTION -#define SUITESPARSE_DATE "Jan 20, 2023" +#define SUITESPARSE_DATE "Jan 20, 2024" #define SUITESPARSE_MAIN_VERSION 7 -#define SUITESPARSE_SUB_VERSION 0 -#define SUITESPARSE_SUBSUB_VERSION 1 +#define SUITESPARSE_SUB_VERSION 6 +#define SUITESPARSE_SUBSUB_VERSION 0 +// version format x.y #define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_VERSION \ - SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) +#define SUITESPARSE_VERSION SUITESPARSE_VER_CODE(7, 6) + +// version format x.y.z +#define SUITESPARSE__VERCODE(main,sub,patch) \ + (((main)*1000ULL + (sub))*1000ULL + (patch)) +#define SUITESPARSE__VERSION SUITESPARSE__VERCODE(7,6,0) //============================================================================== // SuiteSparse interface to the BLAS and LAPACK libraries @@ -469,7 +485,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #elif defined ( BLAS_UNDERSCORE ) - // append an undescore, use lower case + // append an underscore, use lower case #define SUITESPARSE_FORTRAN(name,NAME) name ## _ #define SUITESPARSE__FORTRAN(name,NAME) name ## _ @@ -529,12 +545,12 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION // If the suffix does not contain "_", use (Sun Perf., for example): -// cd build ; cmake -DBLAS64_SUFFIX="64" .. +// cd build && cmake -DBLAS64_SUFFIX="64" .. // If the suffix contains "_" (OpenBLAS in spack for example), use the // following: -// cd build ; cmake -DBLAS64_SUFFIX="_64" .. +// cd build && cmake -DBLAS64_SUFFIX="_64" .. // This setting could be used by the spack packaging of SuiteSparse when linked // with the spack-installed OpenBLAS with 64-bit integers. See @@ -572,6 +588,7 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION // C names of Fortan BLAS and LAPACK functions used by SuiteSparse //------------------------------------------------------------------------------ +// double #define SUITESPARSE_BLAS_DTRSV SUITESPARSE_BLAS ( dtrsv , DTRSV ) #define SUITESPARSE_BLAS_DGEMV SUITESPARSE_BLAS ( dgemv , DGEMV ) #define SUITESPARSE_BLAS_DTRSM SUITESPARSE_BLAS ( dtrsm , DTRSM ) @@ -579,8 +596,15 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_DSYRK SUITESPARSE_BLAS ( dsyrk , DSYRK ) #define SUITESPARSE_BLAS_DGER SUITESPARSE_BLAS ( dger , DGER ) #define SUITESPARSE_BLAS_DSCAL SUITESPARSE_BLAS ( dscal , DSCAL ) +#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) + #define SUITESPARSE_LAPACK_DPOTRF SUITESPARSE_BLAS ( dpotrf , DPOTRF ) +#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) +#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) +#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) +#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) +// double complex #define SUITESPARSE_BLAS_ZTRSV SUITESPARSE_BLAS ( ztrsv , ZTRSV ) #define SUITESPARSE_BLAS_ZGEMV SUITESPARSE_BLAS ( zgemv , ZGEMV ) #define SUITESPARSE_BLAS_ZTRSM SUITESPARSE_BLAS ( ztrsm , ZTRSM ) @@ -588,20 +612,46 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #define SUITESPARSE_BLAS_ZHERK SUITESPARSE_BLAS ( zherk , ZHERK ) #define SUITESPARSE_BLAS_ZGERU SUITESPARSE_BLAS ( zgeru , ZGERU ) #define SUITESPARSE_BLAS_ZSCAL SUITESPARSE_BLAS ( zscal , ZSCAL ) -#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) - -#define SUITESPARSE_BLAS_DNRM2 SUITESPARSE_BLAS ( dnrm2 , DNRM2 ) -#define SUITESPARSE_LAPACK_DLARF SUITESPARSE_BLAS ( dlarf , DLARF ) -#define SUITESPARSE_LAPACK_DLARFG SUITESPARSE_BLAS ( dlarfg , DLARFG ) -#define SUITESPARSE_LAPACK_DLARFT SUITESPARSE_BLAS ( dlarft , DLARFT ) -#define SUITESPARSE_LAPACK_DLARFB SUITESPARSE_BLAS ( dlarfb , DLARFB ) - #define SUITESPARSE_BLAS_DZNRM2 SUITESPARSE_BLAS ( dznrm2 , DZNRM2 ) + +#define SUITESPARSE_LAPACK_ZPOTRF SUITESPARSE_BLAS ( zpotrf , ZPOTRF ) #define SUITESPARSE_LAPACK_ZLARF SUITESPARSE_BLAS ( zlarf , ZLARF ) #define SUITESPARSE_LAPACK_ZLARFG SUITESPARSE_BLAS ( zlarfg , ZLARFG ) #define SUITESPARSE_LAPACK_ZLARFT SUITESPARSE_BLAS ( zlarft , ZLARFT ) #define SUITESPARSE_LAPACK_ZLARFB SUITESPARSE_BLAS ( zlarfb , ZLARFB ) +// single +#define SUITESPARSE_BLAS_STRSV SUITESPARSE_BLAS ( strsv , STRSV ) +#define SUITESPARSE_BLAS_SGEMV SUITESPARSE_BLAS ( sgemv , SGEMV ) +#define SUITESPARSE_BLAS_STRSM SUITESPARSE_BLAS ( strsm , STRSM ) +#define SUITESPARSE_BLAS_SGEMM SUITESPARSE_BLAS ( sgemm , SGEMM ) +#define SUITESPARSE_BLAS_SSYRK SUITESPARSE_BLAS ( ssyrk , SSYRK ) +#define SUITESPARSE_BLAS_SGER SUITESPARSE_BLAS ( sger , SGER ) +#define SUITESPARSE_BLAS_SSCAL SUITESPARSE_BLAS ( sscal , SSCAL ) +#define SUITESPARSE_BLAS_SNRM2 SUITESPARSE_BLAS ( snrm2 , SNRM2 ) + +#define SUITESPARSE_LAPACK_SPOTRF SUITESPARSE_BLAS ( spotrf , SPOTRF ) +#define SUITESPARSE_LAPACK_SLARF SUITESPARSE_BLAS ( slarf , SLARF ) +#define SUITESPARSE_LAPACK_SLARFG SUITESPARSE_BLAS ( slarfg , SLARFG ) +#define SUITESPARSE_LAPACK_SLARFT SUITESPARSE_BLAS ( slarft , SLARFT ) +#define SUITESPARSE_LAPACK_SLARFB SUITESPARSE_BLAS ( slarfb , SLARFB ) + +// single complex +#define SUITESPARSE_BLAS_CTRSV SUITESPARSE_BLAS ( ctrsv , CTRSV ) +#define SUITESPARSE_BLAS_CGEMV SUITESPARSE_BLAS ( cgemv , CGEMV ) +#define SUITESPARSE_BLAS_CTRSM SUITESPARSE_BLAS ( ctrsm , CTRSM ) +#define SUITESPARSE_BLAS_CGEMM SUITESPARSE_BLAS ( cgemm , CGEMM ) +#define SUITESPARSE_BLAS_CHERK SUITESPARSE_BLAS ( cherk , CHERK ) +#define SUITESPARSE_BLAS_CGERU SUITESPARSE_BLAS ( cgeru , CGERU ) +#define SUITESPARSE_BLAS_CSCAL SUITESPARSE_BLAS ( cscal , CSCAL ) +#define SUITESPARSE_BLAS_SCNRM2 SUITESPARSE_BLAS ( scnrm2 , SCNRM2 ) + +#define SUITESPARSE_LAPACK_CPOTRF SUITESPARSE_BLAS ( cpotrf , CPOTRF ) +#define SUITESPARSE_LAPACK_CLARF SUITESPARSE_BLAS ( clarf , CLARF ) +#define SUITESPARSE_LAPACK_CLARFG SUITESPARSE_BLAS ( clarfg , CLARFG ) +#define SUITESPARSE_LAPACK_CLARFT SUITESPARSE_BLAS ( clarft , CLARFT ) +#define SUITESPARSE_LAPACK_CLARFB SUITESPARSE_BLAS ( clarfb , CLARFB ) + //------------------------------------------------------------------------------ // prototypes of BLAS and SUITESPARSE_LAPACK functions //------------------------------------------------------------------------------ @@ -627,7 +677,11 @@ int SuiteSparse_version // returns SUITESPARSE_VERSION #if defined ( SUITESPARSE_BLAS_DEFINITIONS ) -void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ +// gemv: Y = alpha*A*x + beta*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMV ( // input: const char *trans, @@ -659,7 +713,39 @@ void SUITESPARSE_BLAS_DGEMV // Y = alpha*A*x + beta*Y } \ } -void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y +void SUITESPARSE_BLAS_SGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *beta, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGEMV ( // input: const char *trans, @@ -691,7 +777,43 @@ void SUITESPARSE_BLAS_ZGEMV // Y = alpha*A*X + beta*Y } \ } -void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b +void SUITESPARSE_BLAS_CGEMV +( + // input: + const char *trans, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *beta, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGEMV (trans, &M_blas_int, &N_blas_int, alpha, A, \ + &LDA_blas_int, X, &INCX_blas_int, beta, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsv: solve Lx=b, Ux=b, L'x=b, or U'x=b +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSV ( // input: const char *uplo, @@ -718,7 +840,34 @@ void SUITESPARSE_BLAS_DTRSV // solve Lx=b, Ux=b, L'x=b, or U'x=b } \ } -void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b +void SUITESPARSE_BLAS_STRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_strsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSV ( // input: const char *uplo, @@ -745,7 +894,38 @@ void SUITESPARSE_BLAS_ZTRSV // solve (L, L', L^H, U, U', or U^H)x=b } \ } -void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B +void SUITESPARSE_BLAS_CTRSV +( + // input: + const char *uplo, + const char *trans, + const char *diag, + const SUITESPARSE_BLAS_INT *n, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_ctrsv(uplo,trans,diag,n,A,lda,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSV (uplo, trans, diag, &N_blas_int, A, \ + &LDA_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// trsm: solve LX=B, UX=B, L'X=B, or U'X=B +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DTRSM ( // input: const char *side, @@ -776,7 +956,38 @@ void SUITESPARSE_BLAS_DTRSM // solve LX=B, UX=B, L'X=B, or U'X=B } \ } -void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B +void SUITESPARSE_BLAS_STRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + float *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_strsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_STRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZTRSM ( // input: const char *side, @@ -807,7 +1018,42 @@ void SUITESPARSE_BLAS_ZTRSM // solve (L, L', L^H, U, U', or U^H)X=B } \ } -void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_CTRSM +( + // input: + const char *side, + const char *uplo, + const char *transa, + const char *diag, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + // input/output: + void *B, + // input: + const SUITESPARSE_BLAS_INT *ldb +) ; + +#define SUITESPARSE_BLAS_ctrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb,ok)\ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CTRSM (side, uplo, transa, diag, &M_blas_int, \ + &N_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// gemm: C = alpha*A*B + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGEMM ( // input: const char *transa, @@ -844,7 +1090,7 @@ void SUITESPARSE_BLAS_DGEMM // C = alpha*A*B + beta*C } \ } -void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C +void SUITESPARSE_BLAS_SGEMM ( // input: const char *transa, @@ -852,19 +1098,19 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const void *alpha, - const void *A, + const float *alpha, + const float *A, const SUITESPARSE_BLAS_INT *lda, - const void *B, + const float *B, const SUITESPARSE_BLAS_INT *ldb, - const void *beta, + const float *beta, // input/output: - void *C, + float *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ +#define SUITESPARSE_BLAS_sgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ @@ -875,52 +1121,62 @@ void SUITESPARSE_BLAS_ZGEMM // C = alpha*A*B + beta*C SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + SUITESPARSE_BLAS_SGEMM (transa, transb, &M_blas_int, &N_blas_int, \ &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_DSYRK // C = alpha*A*A' + beta*C, or A'A +void SUITESPARSE_BLAS_ZGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, - const double *alpha, - const double *A, + const void *alpha, + const void *A, const SUITESPARSE_BLAS_INT *lda, - const double *beta, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, + const void *beta, // input/output: - double *C, + void *C, // input: const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_ZGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A +void SUITESPARSE_BLAS_CGEMM ( // input: - const char *uplo, - const char *trans, + const char *transa, + const char *transb, + const SUITESPARSE_BLAS_INT *m, const SUITESPARSE_BLAS_INT *n, const SUITESPARSE_BLAS_INT *k, const void *alpha, const void *A, const SUITESPARSE_BLAS_INT *lda, + const void *B, + const SUITESPARSE_BLAS_INT *ldb, const void *beta, // input/output: void *C, @@ -928,47 +1184,206 @@ void SUITESPARSE_BLAS_ZHERK // C = alpha*A*A^H + beta*C, or A^H*A const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +#define SUITESPARSE_BLAS_cgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta, \ + C,ldc,ok) \ { \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDB_blas_int, ldb, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ - A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + SUITESPARSE_BLAS_CGEMM (transa, transb, &M_blas_int, &N_blas_int, \ + &K_blas_int, alpha, A, &LDA_blas_int, B, &LDB_blas_int, beta, C, \ + &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_DPOTRF // Cholesky factorization +//------------------------------------------------------------------------------ +// syrk/herk: C = alpha*A*A' + beta*C ; or C = alpha*A'*A + beta*C +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSYRK ( // input: const char *uplo, + const char *trans, const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const double *alpha, + const double *A, + const SUITESPARSE_BLAS_INT *lda, + const double *beta, // input/output: - double *A, + double *C, // input: - const SUITESPARSE_BLAS_INT *lda, - // output: - SUITESPARSE_BLAS_INT *info + const SUITESPARSE_BLAS_INT *ldc ) ; -#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +#define SUITESPARSE_BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ { \ SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ - info = 1 ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ if (ok) \ { \ - SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ - SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ - &LAPACK_Info) ; \ - info = (Int) LAPACK_Info ; \ + SUITESPARSE_BLAS_DSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ } \ } -void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization +void SUITESPARSE_BLAS_SSYRK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *alpha, + const float *A, + const SUITESPARSE_BLAS_INT *lda, + const float *beta, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_ssyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSYRK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_ZHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_CHERK +( + // input: + const char *uplo, + const char *trans, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *alpha, + const void *A, + const SUITESPARSE_BLAS_INT *lda, + const void *beta, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc +) ; + +#define SUITESPARSE_BLAS_cherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CHERK (uplo, trans, &N_blas_int, &K_blas_int, alpha, \ + A, &LDA_blas_int, beta, C, &LDC_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// potrf: Cholesky factorization +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + double *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_dpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_DPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_SPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_spotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_SPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = (Int) LAPACK_Info ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZPOTRF ( // input: const char *uplo, @@ -995,7 +1410,38 @@ void SUITESPARSE_LAPACK_ZPOTRF // Cholesky factorization } \ } -void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y +void SUITESPARSE_LAPACK_CPOTRF +( + // input: + const char *uplo, + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda, + // output: + SUITESPARSE_BLAS_INT *info +) ; + +#define SUITESPARSE_LAPACK_cpotrf(uplo,n,A,lda,info,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + info = 1 ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_INT LAPACK_Info = -999 ; \ + SUITESPARSE_LAPACK_CPOTRF (uplo, &N_blas_int, A, &LDA_blas_int, \ + &LAPACK_Info) ; \ + info = LAPACK_Info ; \ + } \ +} + +//------------------------------------------------------------------------------ +// scal: Y = alpha*Y +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1016,7 +1462,28 @@ void SUITESPARSE_BLAS_DSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y +void SUITESPARSE_BLAS_SSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + // input/output: + float *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_sscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZSCAL ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1037,7 +1504,32 @@ void SUITESPARSE_BLAS_ZSCAL // Y = alpha*Y } \ } -void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A +void SUITESPARSE_BLAS_CSCAL +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + // input/output: + void *Y, + // input: + const SUITESPARSE_BLAS_INT *incy +) ; + +#define SUITESPARSE_BLAS_cscal(n,alpha,Y,incy,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CSCAL (&N_blas_int, alpha, Y, &INCY_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// ger/geru: A = alpha*x*y' + A +//------------------------------------------------------------------------------ + +void SUITESPARSE_BLAS_DGER ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1067,7 +1559,37 @@ void SUITESPARSE_BLAS_DGER // A = alpha*x*y' + A } \ } -void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A +void SUITESPARSE_BLAS_SGER +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *alpha, + const float *X, + const SUITESPARSE_BLAS_INT *incx, + const float *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + float *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_sger(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_SGER (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +void SUITESPARSE_BLAS_ZGERU ( // input: const SUITESPARSE_BLAS_INT *m, @@ -1097,7 +1619,41 @@ void SUITESPARSE_BLAS_ZGERU // A = alpha*x*y' + A } \ } -void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor +void SUITESPARSE_BLAS_CGERU +( + // input: + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *alpha, + const void *X, + const SUITESPARSE_BLAS_INT *incx, + const void *Y, + const SUITESPARSE_BLAS_INT *incy, + // input/output: + void *A, + // input: + const SUITESPARSE_BLAS_INT *lda +) ; + +#define SUITESPARSE_BLAS_cgeru(m,n,alpha,X,incx,Y,incy,A,lda,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCY_blas_int, incy, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDA_blas_int, lda, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_BLAS_CGERU (&M_blas_int, &N_blas_int, alpha, X, \ + &INCX_blas_int, Y, &INCY_blas_int, A, &LDA_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larft: T = block Householder factor +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFT ( // input: const char *direct, @@ -1126,7 +1682,36 @@ void SUITESPARSE_LAPACK_DLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor +void SUITESPARSE_LAPACK_SLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *Tau, + // output: + float *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_slarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFT ( // input: const char *direct, @@ -1155,7 +1740,40 @@ void SUITESPARSE_LAPACK_ZLARFT // T = block Householder factor } \ } -void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_CLARFT +( + // input: + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *Tau, + // output: + void *T, + // input: + const SUITESPARSE_BLAS_INT *ldt +) ; + +#define SUITESPARSE_LAPACK_clarft(direct,storev,n,k,V,ldv,Tau,T,ldt,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFT (direct, storev, &N_blas_int, &K_blas_int, \ + V, &LDV_blas_int, Tau, T, &LDT_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfb: apply block Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFB ( // input: const char *side, @@ -1197,7 +1815,49 @@ void SUITESPARSE_LAPACK_DLARFB // apply block Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector +void SUITESPARSE_LAPACK_SLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const float *V, + const SUITESPARSE_BLAS_INT *ldv, + const float *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_slarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFB ( // input: const char *side, @@ -1239,7 +1899,53 @@ void SUITESPARSE_LAPACK_ZLARFB // apply block Householder reflector } \ } -double SUITESPARSE_BLAS_DNRM2 // vector 2-norm +void SUITESPARSE_LAPACK_CLARFB +( + // input: + const char *side, + const char *trans, + const char *direct, + const char *storev, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const SUITESPARSE_BLAS_INT *k, + const void *V, + const SUITESPARSE_BLAS_INT *ldv, + const void *T, + const SUITESPARSE_BLAS_INT *ldt, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work, + // input: + const SUITESPARSE_BLAS_INT *ldwork +) ; + +#define SUITESPARSE_LAPACK_clarfb(side,trans,direct,storev,m,n,k,V,ldv,T,ldt, \ + C,ldc,Work,ldwork,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (K_blas_int, k, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDV_blas_int, ldv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDT_blas_int, ldt, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDWORK_blas_int, ldwork, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFB (side, trans, direct, storev, &M_blas_int, \ + &N_blas_int, &K_blas_int, V, &LDV_blas_int, T, &LDT_blas_int, C, \ + &LDC_blas_int, Work, &LDWORK_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// nrm2: vector 2-norm +//------------------------------------------------------------------------------ + +double SUITESPARSE_BLAS_DNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1258,7 +1964,26 @@ double SUITESPARSE_BLAS_DNRM2 // vector 2-norm } \ } -double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm +float SUITESPARSE_BLAS_SNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const float *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_snrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +double SUITESPARSE_BLAS_DZNRM2 ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1277,7 +2002,30 @@ double SUITESPARSE_BLAS_DZNRM2 // vector 2-norm } \ } -void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector +float SUITESPARSE_BLAS_SCNRM2 +( + // input: + const SUITESPARSE_BLAS_INT *n, + const void *X, + const SUITESPARSE_BLAS_INT *incx +) ; + +#define SUITESPARSE_BLAS_scnrm2(result,n,X,incx,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + result = 0 ; \ + if (ok) \ + { \ + result = SUITESPARSE_BLAS_SCNRM2 (&N_blas_int, X, &INCX_blas_int) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larfg: generate Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1301,7 +2049,31 @@ void SUITESPARSE_LAPACK_DLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector +void SUITESPARSE_LAPACK_SLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + float *alpha, + float *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + float *tau +) ; + +#define SUITESPARSE_LAPACK_slarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARFG ( // input: const SUITESPARSE_BLAS_INT *n, @@ -1325,7 +2097,35 @@ void SUITESPARSE_LAPACK_ZLARFG // generate Householder reflector } \ } -void SUITESPARSE_LAPACK_DLARF // apply Householder reflector +void SUITESPARSE_LAPACK_CLARFG +( + // input: + const SUITESPARSE_BLAS_INT *n, + // input/output: + void *alpha, + void *X, + // input: + const SUITESPARSE_BLAS_INT *incx, + // output: + void *tau +) ; + +#define SUITESPARSE_LAPACK_clarfg(n,alpha,X,incx,tau,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCX_blas_int, incx, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARFG (&N_blas_int, alpha, X, &INCX_blas_int, \ + tau) ; \ + } \ +} + +//------------------------------------------------------------------------------ +// larf: apply Householder reflector +//------------------------------------------------------------------------------ + +void SUITESPARSE_LAPACK_DLARF ( // input: const char *side, @@ -1355,7 +2155,37 @@ void SUITESPARSE_LAPACK_DLARF // apply Householder reflector } \ } -void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector +void SUITESPARSE_LAPACK_SLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const float *V, + const SUITESPARSE_BLAS_INT *incv, + const float *tau, + // input/output: + float *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + float *Work +) ; + +#define SUITESPARSE_LAPACK_slarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_SLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + +void SUITESPARSE_LAPACK_ZLARF ( // input: const char *side, @@ -1385,6 +2215,36 @@ void SUITESPARSE_LAPACK_ZLARF // apply Householder reflector } \ } +void SUITESPARSE_LAPACK_CLARF +( + // input: + const char *side, + const SUITESPARSE_BLAS_INT *m, + const SUITESPARSE_BLAS_INT *n, + const void *V, + const SUITESPARSE_BLAS_INT *incv, + const void *tau, + // input/output: + void *C, + // input: + const SUITESPARSE_BLAS_INT *ldc, + // workspace: + void *Work +) ; + +#define SUITESPARSE_LAPACK_clarf(side,m,n,V,incv,tau,C,ldc,Work,ok) \ +{ \ + SUITESPARSE_TO_BLAS_INT (M_blas_int, m, ok) ; \ + SUITESPARSE_TO_BLAS_INT (N_blas_int, n, ok) ; \ + SUITESPARSE_TO_BLAS_INT (INCV_blas_int, incv, ok) ; \ + SUITESPARSE_TO_BLAS_INT (LDC_blas_int, ldc, ok) ; \ + if (ok) \ + { \ + SUITESPARSE_LAPACK_CLARF (side, &M_blas_int, &N_blas_int, V, \ + &INCV_blas_int, tau, C, &LDC_blas_int, Work) ; \ + } \ +} + #endif //------------------------------------------------------------------------------ diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/FindSuiteSparse_config.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/FindSuiteSparse_config.cmake deleted file mode 100644 index 2b75390cc9..0000000000 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/FindSuiteSparse_config.cmake +++ /dev/null @@ -1,141 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/SuiteSparse_config/cmake_modules/FindSuiteSparse_config.cmake -#------------------------------------------------------------------------------- - -# The following copyright and license applies to just this file only, not to -# the library itself: -# FindSuiteSparse_config.cmake, Copyright (c) 2022-2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# Finds the SuiteSparse_config include file and compiled library and sets: - -# SUITESPARSE_CONFIG_INCLUDE_DIR - where to find SuiteSparse_config.h -# SUITESPARSE_CONFIG_LIBRARY - dynamic SuiteSparse_config library -# SUITESPARSE_CONFIG_STATIC - static SuiteSparse_config library -# SUITESPARSE_CONFIG_LIBRARIES - libraries when using SuiteSparse_config -# SUITESPARSE_CONFIG_FOUND - true if SuiteSparse_config found - -# set ``SUITESPARSE_CONFIG_ROOT`` or ``SuiteSparse_config_ROOT`` to a -# SuiteSparse_config installation root to tell this module where to look. - -# All the Find*.cmake files in SuiteSparse are installed by 'make install' into -# /usr/local/lib/cmake/SuiteSparse (where '/usr/local' is the -# ${CMAKE_INSTALL_PREFIX}). To access this file, place the following commands -# in your CMakeLists.txt file. See also SuiteSparse/Example/CMakeLists.txt: -# -# set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} -# ${CMAKE_INSTALL_PREFIX}/lib/cmake/SuiteSparse ) - -#------------------------------------------------------------------------------- - -# include files for SuiteSparse_config -find_path ( SUITESPARSE_CONFIG_INCLUDE_DIR - NAMES SuiteSparse_config.h - HINTS ${SUITESPARSE_CONFIG_ROOT} - HINTS ENV SUITESPARSE_CONFIG_ROOT - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/SuiteSparse_config - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config - PATH_SUFFIXES include Include -) - -# dynamic SuiteSparse_config (or static if no dynamic library was built) -find_library ( SUITESPARSE_CONFIG_LIBRARY - NAMES suitesparseconfig suitesparseconfig_static - HINTS ${SUITESPARSE_CONFIG_ROOT} - HINTS ENV SUITESPARSE_CONFIG_ROOT - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/SuiteSparse_config - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( MSVC ) - set ( STATIC_NAME suitesparseconfig_static ) -else ( ) - set ( STATIC_NAME suitesparseconfig ) - set ( save ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - message ( STATUS "original library suffixes: ${CMAKE_FIND_LIBRARY_SUFFIXES}" ) - set ( CMAKE_FIND_LIBRARY_SUFFIXES - ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES} ) - message ( STATUS "revised for static search: ${CMAKE_FIND_LIBRARY_SUFFIXES}" ) -endif ( ) - -# static libraries for SuiteSparse_config -find_library ( SUITESPARSE_CONFIG_STATIC - NAMES ${STATIC_NAME} - HINTS ${SUITESPARSE_CONFIG_ROOT} - HINTS ENV SUITESPARSE_CONFIG_ROOT - HINTS ${CMAKE_SOURCE_DIR}/.. - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse/SuiteSparse_config - HINTS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config - PATH_SUFFIXES lib build build/Release build/Debug -) - -if ( NOT MSVC ) - # restore the CMAKE_FIND_LIBRARY_SUFFIXES variable - set ( CMAKE_FIND_LIBRARY_SUFFIXES ${save} ) -endif ( ) - -# get version of the library from the dynamic library filename, if present -get_filename_component ( SUITESPARSE_CONFIG_LIBRARY ${SUITESPARSE_CONFIG_LIBRARY} REALPATH ) -get_filename_component ( SUITESPARSE_CONFIG_FILENAME ${SUITESPARSE_CONFIG_LIBRARY} NAME ) -string ( - REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" - SUITESPARSE_CONFIG_VERSION - ${SUITESPARSE_CONFIG_FILENAME} -) - -# set ( SUITESPARSE_CONFIG_VERSION "" ) -if ( EXISTS "${SUITESPARSE_CONFIG_INCLUDE_DIR}" AND NOT SUITESPARSE_CONFIG_VERSION ) - # if the version does not appear in the filename, read the include file - file ( STRINGS ${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h SUITESPARSE_CONFIG_MAJOR_STR - REGEX "define SUITESPARSE_MAIN_VERSION" ) - file ( STRINGS ${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h SUITESPARSE_CONFIG_MINOR_STR - REGEX "define SUITESPARSE_SUB_VERSION" ) - file ( STRINGS ${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h SUITESPARSE_CONFIG_PATCH_STR - REGEX "define SUITESPARSE_SUBSUB_VERSION" ) - message ( STATUS "major: ${SUITESPARSE_CONFIG_MAJOR_STR}" ) - message ( STATUS "minor: ${SUITESPARSE_CONFIG_MINOR_STR}" ) - message ( STATUS "patch: ${SUITESPARSE_CONFIG_PATCH_STR}" ) - string ( REGEX MATCH "[0-9]+" SUITESPARSE_CONFIG_MAJOR ${SUITESPARSE_CONFIG_MAJOR_STR} ) - string ( REGEX MATCH "[0-9]+" SUITESPARSE_CONFIG_MINOR ${SUITESPARSE_CONFIG_MINOR_STR} ) - string ( REGEX MATCH "[0-9]+" SUITESPARSE_CONFIG_PATCH ${SUITESPARSE_CONFIG_PATCH_STR} ) - set (SUITESPARSE_CONFIG_VERSION "${SUITESPARSE_CONFIG_MAJOR}.${SUITESPARSE_CONFIG_MINOR}.${SUITESPARSE_CONFIG_PATCH}") -endif ( ) - -# libaries when using SuiteSparse_config -set (SUITESPARSE_CONFIG_LIBRARIES ${SUITESPARSE_CONFIG_LIBRARY}) - -include ( FindPackageHandleStandardArgs ) - -find_package_handle_standard_args ( SuiteSparse_config - REQUIRED_VARS SUITESPARSE_CONFIG_LIBRARY SUITESPARSE_CONFIG_INCLUDE_DIR - VERSION_VAR SUITESPARSE_CONFIG_VERSION - REASON_FAILURE_MESSAGE result -) - -message (STATUS "result: ${result}") - -mark_as_advanced ( - SUITESPARSE_CONFIG_INCLUDE_DIR - SUITESPARSE_CONFIG_LIBRARY - SUITESPARSE_CONFIG_STATIC - SUITESPARSE_CONFIG_LIBRARIES -) - -if ( SUITESPARSE_CONFIG_FOUND ) - message ( STATUS "SuiteSparse_config version: ${SUITESPARSE_CONFIG_VERSION}" ) - message ( STATUS "SuiteSparse_config include: ${SUITESPARSE_CONFIG_INCLUDE_DIR}" ) - message ( STATUS "SuiteSparse_config library: ${SUITESPARSE_CONFIG_LIBRARY}" ) - message ( STATUS "SuiteSparse_config static: ${SUITESPARSE_CONFIG_STATIC}" ) -else ( ) - message ( STATUS "SuiteSparse_config not found" ) - set ( SUITESPARSE_CONFIG_INCLUDE_DIR "" ) - set ( SUITESPARSE_CONFIG_LIBRARIES "" ) - set ( SUITESPARSE_CONFIG_LIBRARY "" ) - set ( SUITESPARSE_CONFIG_STATIC "" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS.cmake index 9e4b779acb..2225f53731 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS.cmake +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS.cmake @@ -24,13 +24,27 @@ endif ( ) set ( BLA_VENDOR "ANY" CACHE STRING "if ANY (default): searches for any BLAS. Otherwise: search for a specific BLAS" ) -# To allow the use of a BLAS with 64-bit integers, set this to true -option ( ALLOW_64BIT_BLAS - "OFF (default): use only 32-bit BLAS. ON: look for 32 or 64-bit BLAS" off ) +# To allow the use of a BLAS with 64-bit integers, set this to ON +option ( SUITESPARSE_USE_64BIT_BLAS + "OFF (default): use only 32-bit BLAS. ON: look for 32 or 64-bit BLAS" OFF ) # dynamic/static linking with BLAS option ( BLA_STATIC - "OFF (default): dynamic linking of BLAS. ON: static linking of BLAS" off ) + "OFF (default): dynamic linking of BLAS. ON: static linking of BLAS" OFF ) + +if ( DEFINED BLAS_LIBRARIES OR DEFINED BLAS_INCLUDE_DIRS ) + # AMICI -- silence cmake "Manually-specified variables were not used by the project" + set(amici_ignore "${BLAS_LIBRARIES} ${BLAS_INCLUDE_DIRS}") + + # User supplied variables for libraries and/or include directories. + # Use them as-is. + if ( SUITESPARSE_USE_64BIT_BLAS ) + include ( SuiteSparseBLAS64 ) + else ( ) + include ( SuiteSparseBLAS32 ) + endif ( ) + return ( ) +endif ( ) #------------------------------------------------------------------------------- # look for a specific BLAS library @@ -39,32 +53,34 @@ option ( BLA_STATIC # To request specific BLAS, use either (for example): # # CMAKE_OPTIONS="-DBLA_VENDOR=Apple" make -# cd build ; cmake -DBLA_VENDOR=Apple .. ; make +# cd build && cmake -DBLA_VENDOR=Apple .. ; make # -# Use the ALLOW_64BIT_BLAS to select 64-bit or 32-bit BLAS. This setting is -# strictly enforced. If set to true, then only a 64-bit BLAS is allowed. -# If this is not found, no 32-bit BLAS is considered, and the build will fail. +# Use SUITESPARSE_USE_64BIT_BLAS to select 64-bit or 32-bit BLAS. If +# BLA_VENDOR is also defined, this setting is strictly enforced. If set to +# ON, then only a 64-bit BLAS is allowed. If this is not found, no 32-bit +# BLAS is considered, and the build will fail. # -# If the BLA_VENDOR string implies a 64-bit BLAS, then ALLOW_64BIT_BLAS is set -# to true, ignoring the setting from the user (Intel10_64ilp* and Arm_64ilp*). +# If the BLA_VENDOR string implies a 64-bit BLAS, then +# SUITESPARSE_USE_64BIT_BLAS is set to ON, ignoring the setting of this value +# from the user (Intel10_64ilp* and Arm_64ilp*). # -# The default for ALLOW_64BIT_BLAS is false. +# The default for SUITESPARSE_USE_64BIT_BLAS is OFF. if ( NOT (BLA_VENDOR STREQUAL "ANY" ) ) # only look for the BLAS from a single vendor if ( ( BLA_VENDOR MATCHES "64ilp" ) OR ( BLA_VENDOR MATCHES "ilp64" ) ) # Intel10_64ilp* or Arm_ilp64* - set ( ALLOW_64BIT_BLAS true ) + set ( SUITESPARSE_USE_64BIT_BLAS ON ) # OK; overidden by BLA_VENDOR endif ( ) - if ( ALLOW_64BIT_BLAS ) + if ( SUITESPARSE_USE_64BIT_BLAS ) # only look for 64-bit BLAS set ( BLA_SIZEOF_INTEGER 8 ) message ( STATUS "Looking for 64-BLAS: " ${BLA_VENDOR} ) else ( ) # only look for 32-bit BLAS - message ( STATUS "Looking for 32-BLAS: " ${BLA_VENDOR} ) set ( BLA_SIZEOF_INTEGER 4 ) + message ( STATUS "Looking for 32-BLAS: " ${BLA_VENDOR} ) endif ( ) find_package ( BLAS REQUIRED ) if ( BLA_SIZEOF_INTEGER EQUAL 8 ) @@ -76,6 +92,7 @@ if ( NOT (BLA_VENDOR STREQUAL "ANY" ) ) include ( SuiteSparseBLAS32 ) endif ( ) message ( STATUS "Specific BLAS: ${BLA_VENDOR} found: ${BLAS_FOUND}" ) + message ( STATUS "BLAS integer size: ${BLA_SIZEOF_INTEGER}" ) return ( ) endif ( ) @@ -83,10 +100,19 @@ endif ( ) # Look for any 64-bit BLAS, if allowed #------------------------------------------------------------------------------- -# If ALLOW_64BIT_BLAS is true, then a 64-bit BLAS is preferred. -# If not found, a 32-bit BLAS is sought (below) +# If SUITESPARSE_USE_64BIT_BLAS is ON and SUITESPARSE_USE_STRICT is OFF, then a +# 64-bit BLAS is preferred. If not found, a 32-bit BLAS is sought. +# The setting of SUITESPARSE_USE_64BIT_BLAS not strict by default. + +# If SUITESPARSE_USE_64BIT_BLAS is ON and SUITESPARSE_USE_STRICT is ON, then a +# only a 64-bit BLAS is considered. An error occurs if a 64-bit BLAS is not +# found. -if ( ALLOW_64BIT_BLAS ) +# If SUITESPARSE_USE_64BIT_BLAS is OFF, only a 32-bit BLAS is considered. An +# error occurs if a 32-bit BLAS is not found (the SUITESPARSE_USE_STRICT +# setting is ignored). + +if ( SUITESPARSE_USE_64BIT_BLAS ) # Look for Intel MKL BLAS with 64-bit integers message ( STATUS "Looking for Intel 64-bit BLAS" ) @@ -139,6 +165,11 @@ if ( ALLOW_64BIT_BLAS ) return ( ) endif ( ) + # report an error if strict + if ( SUITESPARSE_USE_STRICT ) + message ( FATAL_ERROR "64-bit BLAS required, but not found" ) + endif ( ) + endif ( ) #------------------------------------------------------------------------------- diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS64.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS64.cmake index 744aaef910..72efcd5ce0 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS64.cmake +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseBLAS64.cmake @@ -25,19 +25,19 @@ set ( SuiteSparse_BLAS_integer "int64_t" ) # If the suffix does not contain "_", use (Sun Perf., for example): -# cd build ; cmake -DBLAS64_SUFFIX="64" .. +# cd build && cmake -DBLAS64_SUFFIX="64" .. # If the suffix contains "_" (OpenBLAS in spack for example), use the # following: -# cd build ; cmake -DBLAS64_SUFFIX="_64" .. +# cd build && cmake -DBLAS64_SUFFIX="_64" .. # This setting could be used by the spack packaging of SuiteSparse when linked # with the spack-installed OpenBLAS with 64-bit integers. See # https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/suite-sparse/package.py if ( DEFINED BLAS64_SUFFIX ) - # append BLAS64_SUFFIX to each BLAS and LAPACK name + # append BLAS64_SUFFIX to each BLAS and LAPACK function name string ( FIND ${BLAS64_SUFFIX} "_" HAS_UNDERSCORE ) message ( STATUS "BLAS64_suffix: ${BLAS64_SUFFIX}" ) if ( HAS_UNDERSCORE EQUAL -1 ) diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseLAPACK.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseLAPACK.cmake index 27ff73cadd..82366e0aa5 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseLAPACK.cmake +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseLAPACK.cmake @@ -20,18 +20,19 @@ cmake_minimum_required ( VERSION 3.22 ) -if ( BLA_VENDOR STREQUAL "FLAME" ) - # FLAME has the BLAS but not LAPACK +if ( DEFINED LAPACK_LIBRARIES OR DEFINED LAPACK_INCLUDE_DIRS ) + # User supplied variables for libraries and/or include directories. + # Use them as-is. + return ( ) +endif ( ) - set ( BLA_VENDOR "Generic" ) - message ( STATUS "Looking for generic LAPACK to use with BLIS/FLAME BLAS" ) +if ( BLA_VENDOR STREQUAL "FLAME" ) - # look for the generic dynamic LAPACK library (usually liblagraph.so) find_library ( LAPACK_LIBRARY - NAMES lapack + NAMES flame PATH_SUFFIXES lib build ) - # look for the static LAPACK library (usually liblagraph.a) + # look for the static LAPACK library (usually liblapack.a) if ( MSVC ) set ( STATIC_SUFFIX .lib ) else ( ) diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake index 8c18fa7581..b6b195407c 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparsePolicy.cmake @@ -14,24 +14,25 @@ # To use the "Debug" policy, precede this with # set ( CMAKE_BUILD_TYPE Debug ) # -# ENABLE_CUDA: if set to true, CUDA is enabled for the project. -# Default: true for CHOLMOD and SPQR, false for GraphBLAS -# (for which CUDA is in progress and not ready for -# production use). +# SUITESPARSE_USE_CUDA: if OFF, CUDA is disabled. if ON, CUDA is enabled, +# if available. Default: ON. # -# LOCAL_INSTALL: if true, "cmake --install" will install +# SUITESPARSE_LOCAL_INSTALL: if true, "cmake --install" will install # into SuiteSparse/lib and SuiteSparse/include. # if false, "cmake --install" will install into the # default prefix (or the one configured with -# CMAKE_INSTALL_PREFIX). -# Default: false +# CMAKE_INSTALL_PREFIX). Requires cmake 3.19. +# This is ignored when using the root CMakeLists.txt. +# Set CMAKE_INSTALL_PREFIX instead. +# Default: OFF # -# NSTATIC: if true, static libraries are not built. -# Default: false, except for GraphBLAS, which +# BUILD_SHARED_LIBS: if true, shared libraries are built. +# Default: ON. +# +# BUILD_STATIC_LIBS: if true, static libraries are built. +# Default: ON, except for GraphBLAS, which # takes a long time to compile so the default for -# GraphBLAS is true. For Mongoose, the NSTATIC setting -# is treated as if it always false, since the mongoose -# program is built with the static library. +# GraphBLAS is false. # # SUITESPARSE_CUDA_ARCHITECTURES: a string, such as "all" or # "35;50;75;80" that lists the CUDA architectures to use @@ -47,12 +48,12 @@ # Both settings must appear, or neither. # Default: neither are defined. # -# BLA_STATIC: if true, use static linkage for BLAS and LAPACK. -# Default: false +# BLA_STATIC: if ON, use static linkage for BLAS and LAPACK. +# Default: not set (that is, the same as OFF) # -# ALLOW_64BIT_BLAS if true, SuiteSparse will search for both 32-bit and -# 64-bit BLAS. If false, only 32-bit BLAS will be -# searched for. Ignored if BLA_VENDOR and +# SUITESPARSE_USE_64BIT_BLAS if true, SuiteSparse will search for both +# 32-bit and 64-bit BLAS. If false, only 32-bit BLAS +# will be searched for. Ignored if BLA_VENDOR and # BLA_SIZEOF_INTEGER are defined. # # SUITESPARSE_C_TO_FORTRAN: a string that defines how C calls Fortran. @@ -63,33 +64,64 @@ # This setting is only used if no Fortran compiler is # found. # -# NFORTRAN: if true, no Fortan files are compiled, and the Fortran -# language is not enabled in any cmake scripts. The -# built-in cmake script FortranCInterface is skipped. -# This will require SUITESPARSE_C_TO_FORTRAN to be defined -# explicitly, if the defaults are not appropriate for your -# system. -# Default: false - -cmake_minimum_required ( VERSION 3.19 ) - -message ( STATUS "Source: ${CMAKE_SOURCE_DIR} ") -message ( STATUS "Build: ${CMAKE_BINARY_DIR} ") - -cmake_policy ( SET CMP0042 NEW ) # enable MACOSX_RPATH by default -cmake_policy ( SET CMP0048 NEW ) # VERSION variable policy -cmake_policy ( SET CMP0054 NEW ) # if ( expression ) handling policy -cmake_policy ( SET CMP0104 NEW ) # initialize CUDA architectures +# SUITESPARSE_USE_FORTRAN: if OFF, no Fortan files are compiled, and the +# Fortran language is not enabled in any cmake scripts. +# The built-in cmake script FortranCInterface is skipped. +# This will require SUITESPARSE_C_TO_FORTRAN to be +# defined explicitly, if the defaults are not appropriate +# for your system. +# Default: ON +# +# SUITESPARSE_PKGFILEDIR: Directory where CMake Config and pkg-config files +# will be installed. By default, CMake Config files will +# be installed in the subfolder `cmake` of the directory +# where the (static) libraries will be installed (e.g., +# `lib`). The `.pc` files for pkg-config will be +# installed in the subfolder `pkgconfig` of the directory +# where the (static) libraries will be installed. +# Default: CMAKE_INSTALL_PREFIX, or SuiteSparse/lib if +# SUITESPARSE_LOCAL_INSTALL is enabled. +# +# SUITESPARSE_INCLUDEDIR_POSTFIX : Postfix for installation target of +# header from SuiteSparse. Default: suitesparse, so the +# default include directory is: +# CMAKE_INSTALL_PREFIX/include/suitesparse +# +# SUITESPARSE_USE_STRICT: SuiteSparse has many user-definable settings of the +# form SUITESPARSE_USE_* or (package)_USE_* for some +# particular package. In general, these settings are not +# strict. For example, if SUITESPARSE_USE_OPENMP is +# ON then OpenMP is preferred, but SuiteSparse can be +# used without OpenMP so no error is generated if OpenMP +# is not found. However, if SUITESPARSE_USE_STRICT is +# ON then all *_USE_* settings are treated strictly +# and an error occurs if any are set to ON but the +# corresponding package or setting is not available. The +# *_USE_SYSTEM_* settings are always treated as strict. +# Default: OFF. + +message ( STATUS "Source: ${CMAKE_SOURCE_DIR} ") +message ( STATUS "Build: ${CMAKE_BINARY_DIR} ") + +if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.18.0" ) + cmake_policy ( SET CMP0104 NEW ) # initialize CUDA architectures +endif ( ) -# AMICI -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# SuiteSparse packages have many intentional extra semicolons, for code +# readability (such as "/* do nothing */ ;" in SuiteSparse_config.c). Disable +# the clang warning for these statements: +if ( CMAKE_C_COMPILER_ID STREQUAL "Clang" ) + set ( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-extra-semi-stmt" ) +endif ( ) +if ( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) + set ( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-extra-semi-stmt" ) +endif ( ) if ( WIN32 ) set ( CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS true ) add_compile_definitions ( _CRT_SECURE_NO_WARNINGS ) endif ( ) -set ( CMAKE_MACOSX_RPATH TRUE ) enable_language ( C ) include ( GNUInstallDirs ) @@ -97,15 +129,40 @@ include ( GNUInstallDirs ) set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake_modules ) -# NSTATIC option -if ( NSTATIC_DEFAULT_ON ) - option ( NSTATIC "ON (default): do not build static libraries. OFF: build static libraries" on ) +# Use OpenMP +option ( SUITESPARSE_USE_OPENMP "ON (default): Use OpenMP in libraries by default if available. OFF: Do not use OpenMP by default." ON ) + +# strict usage +option ( SUITESPARSE_USE_STRICT "ON: treat all _USE__ settings as strict if they are ON. OFF (default): consider *_USE_* as preferences, not strict" OFF ) + +# build the demos +option ( SUITESPARSE_DEMOS "ON: Build the demo programs. OFF (default): do not build the demo programs." OFF ) + +# BUILD_SHARED_LIBS and BUILD_STATIC_LIBS options +option ( BUILD_SHARED_LIBS "OFF: do not build shared libraries. ON (default): build shared libraries" ON ) + +if ( BUILD_STATIC_LIBS_DEFAULT_OFF ) + option ( BUILD_STATIC_LIBS "OFF (default): do not build static libraries. ON: build static libraries" OFF ) else ( ) - option ( NSTATIC "ON: do not build static libraries. OFF (default): build static libraries" off ) + # For backwards compatibility, use NSTATIC if it is set. + if ( NSTATIC ) + option ( BUILD_STATIC_LIBS "OFF: do not build static libraries. ON (default): build static libraries" OFF ) + else ( ) + option ( BUILD_STATIC_LIBS "OFF: do not build static libraries. ON (default): build static libraries" ON ) + endif ( ) +endif ( ) + +if ( NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS ) + message ( FATAL_ERROR "At least one of BUILD_SHARED_LIBS or BUILD_STATIC_LIBS must be set to ON." ) endif ( ) # installation options -option ( LOCAL_INSTALL "Install in SuiteSparse/lib" off ) +if ( NOT SUITESPARSE_ROOT_CMAKELISTS AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0" ) + # the SUITESPARSE_LOCAL_INSTALL option requires cmake 3.19.0 or later + option ( SUITESPARSE_LOCAL_INSTALL "Install in SuiteSparse/lib" OFF ) +else ( ) + set ( SUITESPARSE_LOCAL_INSTALL OFF ) +endif ( ) if ( SUITESPARSE_SECOND_LEVEL ) # some packages in SuiteSparse are in SuiteSparse/Package/Package @@ -117,94 +174,127 @@ else ( ) ${CMAKE_SOURCE_DIR}/../lib/cmake ) endif ( ) -# add the ./build folder to the runpath so other SuiteSparse packages can -# find this one without "make install" -set ( CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} ${CMAKE_BINARY_DIR} ) - -# determine if this Package is inside the SuiteSparse folder -set ( INSIDE_SUITESPARSE false ) -if ( LOCAL_INSTALL ) - # if you do not want to install local copies of SuiteSparse - # packages in SuiteSparse/lib and SuiteSparse/, set - # LOCAL_INSTALL to false in your CMake options. - if ( SUITESPARSE_SECOND_LEVEL ) - # the package is normally located at the 2nd level inside SuiteSparse - # (SuiteSparse/GraphBLAS/GraphBLAS/ for example) - if ( EXISTS ${CMAKE_SOURCE_DIR}/../../SuiteSparse_config ) - set ( INSIDE_SUITESPARSE true ) +# allow libraries to "see" each other if they are installed in a non-default LIBRARY_PATH +list ( FIND CMAKE_INSTALL_RPATH "$ORIGIN" _idx ) +if ( _idx LESS 0 ) + # "$ORIGIN" not yet included in CMAKE_INSTALL_RPATH + list ( PREPEND CMAKE_INSTALL_RPATH "$ORIGIN" ) +endif ( ) + +set ( INSIDE_SUITESPARSE OFF ) +if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) + # determine if this Package is inside the SuiteSparse folder + if ( SUITESPARSE_LOCAL_INSTALL ) + # if you do not want to install local copies of SuiteSparse + # packages in SuiteSparse/lib and SuiteSparse/, set + # SUITESPARSE_LOCAL_INSTALL to false in your CMake options. + if ( SUITESPARSE_SECOND_LEVEL ) + # the package is normally located at the 2nd level inside SuiteSparse + # (SuiteSparse/GraphBLAS/GraphBLAS/ for example) + if ( EXISTS ${CMAKE_SOURCE_DIR}/../../SuiteSparse_config ) + set ( INSIDE_SUITESPARSE true ) + endif ( ) + else ( ) + # typical case, the package is at the 1st level inside SuiteSparse + # (SuiteSparse/AMD for example) + if ( EXISTS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config ) + set ( INSIDE_SUITESPARSE true ) + endif ( ) endif ( ) - else ( ) - # typical case, the package is at the 1st level inside SuiteSparse - # (SuiteSparse/AMD for example) - if ( EXISTS ${CMAKE_SOURCE_DIR}/../SuiteSparse_config ) - set ( INSIDE_SUITESPARSE true ) + + if ( NOT INSIDE_SUITESPARSE ) + message ( FATAL_ERROR "Unsupported layout for local installation. Correct the directory layout or unset SUITESPARSE_LOCAL_INSTALL." ) endif ( ) - endif ( ) - if ( NOT INSIDE_SUITESPARSE ) - message ( FATAL_ERROR "Unsupported layout for local installation. Correct the directory layout or unset LOCAL_INSTALL." ) endif ( ) - endif ( ) -if ( INSIDE_SUITESPARSE ) - # ../lib and ../include exist: the package is inside SuiteSparse. - # find ( REAL_PATH ...) requires cmake 3.19. - if ( SUITESPARSE_SECOND_LEVEL ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../.. SUITESPARSE_LOCAL_PREFIX ) - else ( ) - file ( REAL_PATH ${CMAKE_SOURCE_DIR}/.. SUITESPARSE_LOCAL_PREFIX ) - endif ( ) -endif ( ) +set ( SUITESPARSE_INCLUDEDIR_POSTFIX "suitesparse" CACHE STRING + "Postfix for installation target of header from SuiteSparse (default: \"suitesparse\")" ) -if ( LOCAL_INSTALL ) +if ( SUITESPARSE_LOCAL_INSTALL ) + if ( INSIDE_SUITESPARSE ) + # ../lib and ../include exist: the package is inside SuiteSparse. + # find ( REAL_PATH ...) requires cmake 3.19. + if ( SUITESPARSE_SECOND_LEVEL ) + file ( REAL_PATH ${CMAKE_SOURCE_DIR}/../.. + SUITESPARSE_LOCAL_PREFIX ) + else ( ) + file ( REAL_PATH ${CMAKE_SOURCE_DIR}/.. + SUITESPARSE_LOCAL_PREFIX ) + endif ( ) + endif ( ) set ( SUITESPARSE_LIBDIR ${SUITESPARSE_LOCAL_PREFIX}/lib ) - set ( SUITESPARSE_INCLUDEDIR ${SUITESPARSE_LOCAL_PREFIX}/include ) + set ( SUITESPARSE_INCLUDEDIR ${SUITESPARSE_LOCAL_PREFIX}/include/${SUITESPARSE_INCLUDEDIR_POSTFIX} ) set ( SUITESPARSE_BINDIR ${SUITESPARSE_LOCAL_PREFIX}/bin ) else ( ) set ( SUITESPARSE_LIBDIR ${CMAKE_INSTALL_LIBDIR} ) - set ( SUITESPARSE_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR} ) + set ( SUITESPARSE_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}/${SUITESPARSE_INCLUDEDIR_POSTFIX} ) set ( SUITESPARSE_BINDIR ${CMAKE_INSTALL_BINDIR} ) endif ( ) if ( INSIDE_SUITESPARSE ) # append ../lib to the install and build runpaths - set ( CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} ${SUITESPARSE_LIBDIR} ) - set ( CMAKE_BUILD_RPATH ${CMAKE_BUILD_RPATH} ${SUITESPARSE_LIBDIR} ) + list ( APPEND CMAKE_INSTALL_RPATH ${SUITESPARSE_LIBDIR} ) + list ( APPEND CMAKE_BUILD_RPATH ${SUITESPARSE_LIBDIR} ) endif ( ) -message ( STATUS "Install lib: ${SUITESPARSE_LIBDIR}" ) -message ( STATUS "Install include: ${SUITESPARSE_INCLUDEDIR}" ) -message ( STATUS "Install bin: ${SUITESPARSE_BINDIR}" ) -message ( STATUS "Install rpath: ${CMAKE_INSTALL_RPATH}" ) -message ( STATUS "Build rpath: ${CMAKE_BUILD_RPATH}" ) +set ( SUITESPARSE_PKGFILEDIR ${SUITESPARSE_LIBDIR} CACHE STRING + "Directory where CMake Config and pkg-config files will be installed" ) + +message ( STATUS "Install lib: ${SUITESPARSE_LIBDIR}" ) +message ( STATUS "Install include: ${SUITESPARSE_INCLUDEDIR}" ) +message ( STATUS "Install bin: ${SUITESPARSE_BINDIR}" ) +message ( STATUS "Install pkg-file: ${SUITESPARSE_PKGFILEDIR}" ) +message ( STATUS "Install rpath: ${CMAKE_INSTALL_RPATH}" ) +message ( STATUS "Build rpath: ${CMAKE_BUILD_RPATH}" ) if ( NOT CMAKE_BUILD_TYPE ) set ( CMAKE_BUILD_TYPE Release ) endif ( ) -message ( STATUS "Build type: ${CMAKE_BUILD_TYPE} ") +message ( STATUS "Build type: ${CMAKE_BUILD_TYPE} ") set ( CMAKE_INCLUDE_CURRENT_DIR ON ) +#------------------------------------------------------------------------------- +# Workaround for math.h on old macOS +#------------------------------------------------------------------------------- + +if ( APPLE AND CMAKE_SYSTEM_VERSION VERSION_LESS 11 ) + # Older versions of math.h on the Mac define Real and Imag, which + # conflict with the internal use of those symbols in CHOLMOD, KLU, SPQR, + # UMFPACK, and ParU. + # This can be disabled with -D__NOEXTENSIONS__ + message ( STATUS "MacOS: disable extensions in math.h" ) + add_compile_definitions ( "__NOEXTENSIONS__" ) +endif ( ) + #------------------------------------------------------------------------------- # check if Fortran is available and enabled #------------------------------------------------------------------------------- include ( CheckLanguage ) -option ( NFORTRAN "ON: do not try to use Fortran. OFF (default): try Fortran" off ) -if ( NFORTRAN ) - message ( STATUS "Fortran: not enabled" ) -else ( ) +option ( SUITESPARSE_USE_FORTRAN "ON (default): use Fortran. OFF: do not use Fortran" ON ) +if ( SUITESPARSE_USE_FORTRAN ) check_language ( Fortran ) if ( CMAKE_Fortran_COMPILER ) enable_language ( Fortran ) - message ( STATUS "Fortran: ${CMAKE_Fortran_COMPILER}" ) + message ( STATUS "Fortran: ${CMAKE_Fortran_COMPILER}" ) + set ( SUITESPARSE_HAS_FORTRAN ON ) else ( ) # Fortran not available: - set ( NFORTRAN true ) - message ( STATUS "Fortran: not available" ) + set ( SUITESPARSE_HAS_FORTRAN OFF ) + message ( STATUS "Fortran: not available" ) endif ( ) +else ( ) + message ( STATUS "Fortran: not enabled" ) + set ( SUITESPARSE_HAS_FORTRAN OFF ) +endif ( ) + +# check for strict usage +if ( SUITESPARSE_USE_STRICT AND SUITESPARSE_USE_FORTRAN AND NOT SUITESPARSE_HAS_FORTRAN ) + message ( FATAL_ERROR "Fortran required for SuiteSparse but not found" ) endif ( ) # default C-to-Fortran name mangling if Fortran compiler not found @@ -222,48 +312,54 @@ endif ( ) # find CUDA #------------------------------------------------------------------------------- -if ( ENABLE_CUDA ) +option ( SUITESPARSE_USE_CUDA "ON (default): enable CUDA acceleration for SuiteSparse, OFF: do not use CUDA" ON ) + +if ( SUITESPARSE_USE_CUDA ) # try finding CUDA check_language ( CUDA ) - message ( STATUS "Looking for CUDA" ) + # message ( STATUS "Looking for CUDA" ) if ( CMAKE_CUDA_COMPILER ) # with CUDA: - message ( STATUS "Find CUDA tool kit:" ) + # message ( STATUS "Find CUDA tool kit:" ) # FindCUDAToolKit needs to have C or CXX enabled first (see above) - include ( FindCUDAToolkit ) - message ( STATUS "CUDA toolkit found: " ${CUDAToolkit_FOUND} ) - message ( STATUS "CUDA toolkit version: " ${CUDAToolkit_VERSION} ) - message ( STATUS "CUDA toolkit include: " ${CUDAToolkit_INCLUDE_DIRS} ) - message ( STATUS "CUDA toolkit lib dir: " ${CUDAToolkit_LIBRARY_DIR} ) + find_package ( CUDAToolkit ) + message ( STATUS "CUDA toolkit : " ${CUDAToolkit_FOUND} ) + message ( STATUS "CUDA toolkit ver: " ${CUDAToolkit_VERSION} ) + message ( STATUS "CUDA toolkit inc: " ${CUDAToolkit_INCLUDE_DIRS} ) + message ( STATUS "CUDA toolkit lib: " ${CUDAToolkit_LIBRARY_DIR} ) if ( CUDAToolkit_VERSION VERSION_LESS "11.2" ) # CUDA is present but too old - message ( STATUS "CUDA: not enabled (CUDA 11.2 or later required)" ) - set ( SUITESPARSE_CUDA off ) + message ( STATUS "CUDA: not enabled (CUDA 11.2 or later required)" ) + set ( SUITESPARSE_HAS_CUDA OFF ) else ( ) # CUDA 11.2 or later present enable_language ( CUDA ) - set ( SUITESPARSE_CUDA on ) + set ( SUITESPARSE_HAS_CUDA ON ) endif ( ) else ( ) # without CUDA: - message ( STATUS "CUDA: not found" ) - set ( SUITESPARSE_CUDA off ) + message ( STATUS "CUDA: not found" ) + set ( SUITESPARSE_HAS_CUDA OFF ) endif ( ) else ( ) # CUDA is disabled - set ( SUITESPARSE_CUDA off ) + set ( SUITESPARSE_HAS_CUDA OFF ) endif ( ) -if ( SUITESPARSE_CUDA ) - message ( STATUS "CUDA: enabled" ) - add_compile_definitions ( SUITESPARSE_CUDA ) +if ( SUITESPARSE_HAS_CUDA ) + message ( STATUS "CUDA: enabled" ) set ( SUITESPARSE_CUDA_ARCHITECTURES "52;75;80" CACHE STRING "CUDA architectures" ) set ( CMAKE_CUDA_ARCHITECTURES ${SUITESPARSE_CUDA_ARCHITECTURES} ) else ( ) - message ( STATUS "CUDA: not enabled" ) + message ( STATUS "CUDA: not enabled" ) +endif ( ) + +# check for strict usage +if ( SUITESPARSE_USE_STRICT AND SUITESPARSE_USE_CUDA AND NOT SUITESPARSE_HAS_CUDA ) + message ( FATAL_ERROR "CUDA required for SuiteSparse but not found" ) endif ( ) diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseReport.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseReport.cmake index 9271c4a920..0b47f34c13 100644 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseReport.cmake +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparseReport.cmake @@ -10,21 +10,15 @@ #------------------------------------------------------------------------------- message ( STATUS "------------------------------------------------------------------------" ) -message ( STATUS "SuiteSparse CMAKE report for: ${CMAKE_PROJECT_NAME}" ) +message ( STATUS "SuiteSparse CMAKE report for: ${PROJECT_NAME}" ) message ( STATUS "------------------------------------------------------------------------" ) -message ( STATUS "inside common SuiteSparse root: ${INSIDE_SUITESPARSE}" ) -message ( STATUS "install in SuiteSparse/lib and SuiteSparse/include: ${LOCAL_INSTALL}" ) -message ( STATUS "build type: ${CMAKE_BUILD_TYPE}" ) -if ( NSTATIC ) - message ( STATUS "NSTATIC: true (do not build static library)" ) -else ( ) - message ( STATUS "NSTATIC: false (build static library)" ) -endif ( ) -if ( OPENMP_FOUND ) - message ( STATUS "use OpenMP: yes ") -else ( ) - message ( STATUS "use OpenMP: no ") +if ( NOT SUITESPARSE_ROOT_CMAKELISTS ) + message ( STATUS "inside common SuiteSparse root: ${INSIDE_SUITESPARSE}" ) + message ( STATUS "install in SuiteSparse/lib and SuiteSparse/include: ${SUITESPARSE_LOCAL_INSTALL}" ) endif ( ) +message ( STATUS "build type: ${CMAKE_BUILD_TYPE}" ) +message ( STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}" ) +message ( STATUS "BUILD_STATIC_LIBS: ${BUILD_STATIC_LIBS}" ) message ( STATUS "C compiler: ${CMAKE_C_COMPILER} ") message ( STATUS "C flags: ${CMAKE_C_FLAGS}" ) message ( STATUS "C++ compiler: ${CMAKE_CXX_COMPILER}" ) @@ -36,10 +30,10 @@ else ( ) message ( STATUS "C Flags release: ${CMAKE_C_FLAGS_RELEASE} ") message ( STATUS "C++ Flags release: ${CMAKE_CXX_FLAGS_RELEASE} ") endif ( ) -if ( NFORTRAN ) - message ( STATUS "Fortran compiler: none" ) -else ( ) +if ( SUITESPARSE_HAS_FORTRAN ) message ( STATUS "Fortran compiler: ${CMAKE_Fortran_COMPILER} " ) +else ( ) + message ( STATUS "Fortran compiler: none" ) endif ( ) get_property ( CDEFN DIRECTORY PROPERTY COMPILE_DEFINITIONS ) message ( STATUS "compile definitions: ${CDEFN}") @@ -49,7 +43,4 @@ endif ( ) if ( DEFINED CMAKE_CUDA_ARCHITECTURES ) message ( STATUS "CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}" ) endif ( ) -if ( NPARTITION ) - message ( STATUS "NPARTITION: do not use METIS" ) -endif ( ) message ( STATUS "------------------------------------------------------------------------" ) diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse__thread.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse__thread.cmake new file mode 100644 index 0000000000..1c52185b7a --- /dev/null +++ b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse__thread.cmake @@ -0,0 +1,72 @@ +#------------------------------------------------------------------------------- +# GraphBLAS/cmake_modules/SuiteSparse__thread.cmake +#------------------------------------------------------------------------------- + +# Copyright (c) 2017-2023, Timothy A. Davis. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +#------------------------------------------------------------------------------- + +# determine if the __thread keyword is available, which is an extension by +# gcc but supported by many compilers, to indicate thread-local-storage. + +include ( CheckCSourceCompiles ) + +set ( thread_src +" #include + __thread int x = 1 ; + int main (void) + { + x = 0 ; + return (x) ; + } +" ) + +set ( declspec_thread_src +" #include + __declspec ( thread ) int x = 1 ; + int main (void) + { + x = 0 ; + return (x) ; + } +" ) + +set ( thread_local_src +" #include + #include + _Thread_local int x = 1 ; + int main (void) + { + x = 0 ; + return (x) ; + } +" ) + +check_c_source_compiles ( "${declspec_thread_src}" HAVE_KEYWORD__DECLSPEC_THREAD ) + +check_c_source_compiles ( "${thread_src}" HAVE_KEYWORD__THREAD ) + +check_c_source_compiles ( "${thread_local_src}" HAVE_KEYWORD__THREAD_LOCAL ) + +if ( HAVE_KEYWORD__DECLSPEC_THREAD ) + add_compile_definitions ( HAVE_KEYWORD__DECLSPEC_THREAD ) + message ( STATUS "__declspec(thread) keyword: available" ) +else ( ) + message ( STATUS "__declspec(thread) keyword: not available" ) +endif ( ) + +if ( HAVE_KEYWORD__THREAD ) + add_compile_definitions ( HAVE_KEYWORD__THREAD ) + message ( STATUS "__thread keyword: available" ) +else ( ) + message ( STATUS "__thread keyword: not available" ) +endif ( ) + +if ( HAVE_KEYWORD__THREAD_LOCAL ) + add_compile_definitions ( HAVE_KEYWORD__THREAD_LOCAL ) + message ( STATUS "_Thread_local keyword: available" ) +else ( ) + message ( STATUS "_Thread_local_thread keyword: not available" ) +endif ( ) + diff --git a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse_ssize_t.cmake b/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse_ssize_t.cmake deleted file mode 100644 index 2b74bae83b..0000000000 --- a/ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse_ssize_t.cmake +++ /dev/null @@ -1,32 +0,0 @@ -#------------------------------------------------------------------------------- -# SuiteSparse/cmake_modules/SuiteSparse_ssize_t.cmake -#------------------------------------------------------------------------------- - -# Copyright (c) 2023, Timothy A. Davis. All Rights Reserved. -# SPDX-License-Identifier: BSD-3-clause - -#------------------------------------------------------------------------------- - -# determine if the compiler defines ssize_t - -include ( CheckCSourceCompiles ) - -set ( ssize_t_source -" #include - int main (void) - { - ssize_t x = 0 ; - return (0) ; - } -" ) - -check_c_source_compiles ( "${ssize_t_source}" TEST_FOR_SSIZE_T ) - -if ( TEST_FOR_SSIZE_T ) - set ( HAVE_SSIZE_T true ) - message ( STATUS "#include and ssize_t: OK" ) -else ( ) - set ( HAVE_SSIZE_T false ) - message ( STATUS "#include and ssize_t: not found" ) -endif ( ) - diff --git a/ThirdParty/SuiteSparse/build/.gitignore b/ThirdParty/SuiteSparse/build/.gitignore new file mode 100644 index 0000000000..52e15321b7 --- /dev/null +++ b/ThirdParty/SuiteSparse/build/.gitignore @@ -0,0 +1,4 @@ +# Ignore all files except this file. +* +*/ +!.gitignore diff --git a/ThirdParty/SuiteSparse/lib/.gitignore b/ThirdParty/SuiteSparse/lib/.gitignore new file mode 100644 index 0000000000..5e7d2734cf --- /dev/null +++ b/ThirdParty/SuiteSparse/lib/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/ThirdParty/sundials/CMakeLists.txt b/ThirdParty/sundials/CMakeLists.txt index f535def9d0..e23332cf31 100644 --- a/ThirdParty/sundials/CMakeLists.txt +++ b/ThirdParty/sundials/CMakeLists.txt @@ -27,9 +27,9 @@ project(SUNDIALS C) # Specify the location of additional CMAKE modules set(CMAKE_MODULE_PATH - ${PROJECT_SOURCE_DIR}/cmake - ${PROJECT_SOURCE_DIR}/cmake/macros - ${PROJECT_SOURCE_DIR}/cmake/tpl + "${PROJECT_SOURCE_DIR}/cmake" + "${PROJECT_SOURCE_DIR}/cmake/macros" + "${PROJECT_SOURCE_DIR}/cmake/tpl" ) # MACRO definitions diff --git a/ThirdParty/sundials/cmake/tpl/FindKLU.cmake b/ThirdParty/sundials/cmake/tpl/FindKLU.cmake index 9e25883c4f..98465aa180 100644 --- a/ThirdParty/sundials/cmake/tpl/FindKLU.cmake +++ b/ThirdParty/sundials/cmake/tpl/FindKLU.cmake @@ -101,7 +101,7 @@ if (NOT SUITESPARSECONFIG_LIBRARY) mark_as_advanced(SUITESPARSECONFIG_LIBRARY) endif () -set(KLU_LIBRARIES ${KLU_LIBRARY} ${AMD_LIBRARY} ${COLAMD_LIBRARY} ${BTF_LIBRARY} ${SUITESPARSECONFIG_LIBRARY}) +set(KLU_LIBRARIES "${KLU_LIBRARY}" "${AMD_LIBRARY}" "${COLAMD_LIBRARY}" "${BTF_LIBRARY}" "${SUITESPARSECONFIG_LIBRARY}") # set package variables including KLU_FOUND include(FindPackageHandleStandardArgs) diff --git a/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake b/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake index 8a9e111c6c..fd7947cac4 100644 --- a/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake +++ b/ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake @@ -49,7 +49,8 @@ find_package(KLU REQUIRED) message(STATUS "KLU_LIBRARIES: ${KLU_LIBRARIES}") message(STATUS "KLU_INCLUDE_DIR: ${KLU_INCLUDE_DIR}") - +list(JOIN KLU_LIBRARIES "\" \"" KLU_LIBRARIES_TMP) +set(KLU_LIBRARIES_TMP \"${KLU_LIBRARIES_TMP}\") # ----------------------------------------------------------------------------- # Section 4: Test the TPL # ----------------------------------------------------------------------------- @@ -58,11 +59,11 @@ if(KLU_FOUND AND (NOT KLU_WORKS)) # Do any checks which don't require compilation first. # Create the KLU_TEST directory - set(KLU_TEST_DIR ${PROJECT_BINARY_DIR}/KLU_TEST) + set(KLU_TEST_DIR "${PROJECT_BINARY_DIR}/KLU_TEST") file(MAKE_DIRECTORY ${KLU_TEST_DIR}) # Create a CMakeLists.txt file - file(WRITE ${KLU_TEST_DIR}/CMakeLists.txt + file(WRITE "${KLU_TEST_DIR}/CMakeLists.txt" "CMAKE_MINIMUM_REQUIRED(VERSION 3.1.3)\n" "PROJECT(ltest C)\n" "SET(CMAKE_VERBOSE_MAKEFILE ON)\n" @@ -72,12 +73,12 @@ if(KLU_FOUND AND (NOT KLU_WORKS)) "SET(CMAKE_C_FLAGS_DEBUG \"${CMAKE_C_FLAGS_DEBUG}\")\n" "SET(CMAKE_C_FLAGS_RELWITHDEBUGINFO \"${CMAKE_C_FLAGS_RELWITHDEBUGINFO}\")\n" "SET(CMAKE_C_FLAGS_MINSIZE \"${CMAKE_C_FLAGS_MINSIZE}\")\n" - "INCLUDE_DIRECTORIES(${KLU_INCLUDE_DIR})\n" + "INCLUDE_DIRECTORIES(\"${KLU_INCLUDE_DIR}\")\n" "ADD_EXECUTABLE(ltest ltest.c)\n" - "TARGET_LINK_LIBRARIES(ltest ${KLU_LIBRARIES})\n") + "TARGET_LINK_LIBRARIES(ltest ${KLU_LIBRARIES_TMP})\n") # Create a C source file which calls a KLU function - file(WRITE ${KLU_TEST_DIR}/ltest.c + file(WRITE "${KLU_TEST_DIR}/ltest.c" "\#include \"klu.h\"\n" "int main(){\n" "klu_common Common;\n" @@ -87,10 +88,10 @@ if(KLU_FOUND AND (NOT KLU_WORKS)) # To ensure we do not use stuff from the previous attempts, # we must remove the CMakeFiles directory. - file(REMOVE_RECURSE ${KLU_TEST_DIR}/CMakeFiles) + file(REMOVE_RECURSE "${KLU_TEST_DIR}/CMakeFiles") # Attempt to build and link the "ltest" executable - try_compile(COMPILE_OK ${KLU_TEST_DIR} ${KLU_TEST_DIR} ltest + try_compile(COMPILE_OK "${KLU_TEST_DIR}" "${KLU_TEST_DIR}" ltest OUTPUT_VARIABLE COMPILE_OUTPUT) # Process test result diff --git a/cmake/AmiciConfig.cmake b/cmake/AmiciConfig.cmake index cb7d57d51a..d1e86c151e 100644 --- a/cmake/AmiciConfig.cmake +++ b/cmake/AmiciConfig.cmake @@ -24,11 +24,13 @@ endif() if(NOT DEFINED KLU_ROOT) set(KLU_ROOT @CMAKE_SOURCE_DIR@/ThirdParty/SuiteSparse/) endif() -find_package(SuiteSparse_config REQUIRED) -find_package(AMD REQUIRED) -find_package(BTF REQUIRED) -find_package(COLAMD REQUIRED) -find_package(KLU REQUIRED) +find_dependency(SuiteSparse_config REQUIRED) +find_dependency(AMD REQUIRED) +find_dependency(BTF REQUIRED) +find_dependency(COLAMD REQUIRED) +find_dependency(KLU REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/AmiciFindBLAS.cmake") add_library(SUNDIALS::KLU INTERFACE IMPORTED) target_link_libraries( @@ -41,15 +43,15 @@ target_link_libraries( set_target_properties(SUNDIALS::KLU PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${KLU_INCLUDE_DIR}") -find_package(SUNDIALS REQUIRED PATHS +find_dependency(SUNDIALS REQUIRED PATHS "@CMAKE_SOURCE_DIR@/ThirdParty/sundials/build/@CMAKE_INSTALL_LIBDIR@/cmake/sundials/") if(@Boost_CHRONO_FOUND@) - find_package(Boost COMPONENTS chrono REQUIRED) + find_dependency(Boost COMPONENTS chrono REQUIRED) endif() if(@HDF5_FOUND@) - find_package( + find_dependency( HDF5 COMPONENTS C HL CXX REQUIRED) diff --git a/cmake/AmiciFindBLAS.cmake b/cmake/AmiciFindBLAS.cmake new file mode 100644 index 0000000000..6b2f9cf5f9 --- /dev/null +++ b/cmake/AmiciFindBLAS.cmake @@ -0,0 +1,110 @@ +# Find a BLAS +# +# AMICI requires BLAS, currently Intel MKL, CBLAS or MATLAB BLAS can be used. +# The latter is not supported via CMake yet. +# +# This module defines the BLAS::BLAS IMPORTED target. + +set(BLAS + "CBLAS" + CACHE STRING "BLAS library to use") +set_property(CACHE BLAS PROPERTY STRINGS "CBLAS" "MKL" "ACCELERATE") + +if(${BLAS} STREQUAL "MKL" OR DEFINED ENV{MKLROOT}) + if(DEFINED ENV{MKLROOT}) + # This is set by Environment Modules + message(STATUS "Using MKL_INCDIR and MKL_LIB from environment module") + set(BLAS + "MKL" + CACHE STRING "BLAS library to use" FORCE) + set(BLAS_INCLUDE_DIRS + "$ENV{MKL_INCDIR}" + CACHE STRING "" FORCE) + set(BLAS_LIBRARIES + "$ENV{MKL_LIB}" + CACHE STRING "" FORCE) + else() + set(BLAS_INCLUDE_DIRS + "" + CACHE STRING "") + set(BLAS_LIBRARIES + -lmkl + CACHE STRING "") + endif() +elseif( + NOT DEFINED ENV{BLAS_LIBS} + AND NOT DEFINED ENV{BLAS_CFLAGS} + AND NOT BLAS_FOUND) + # if nothing is specified via environment variables, let's try FindBLAS + if($(CMAKE_VERSION) VERSION_GREATER_EQUAL 3.22) + set(BLA_SIZEOF_INTEGER 8) + endif() + + if(APPLE AND (NOT DEFINED BLA_VENDOR OR BLA_VENDOR STREQUAL "All")) + set(BLA_VENDOR Apple) + find_package(BLAS) + if(BLAS_FOUND) + message(STATUS "Found Apple Accelerate BLAS") + set_property( + TARGET BLAS::BLAS + APPEND + PROPERTY INTERFACE_COMPILE_DEFINITIONS ACCELERATE_NEW_LAPACK) + set_property( + TARGET BLAS::BLAS + APPEND + PROPERTY INTERFACE_COMPILE_DEFINITIONS ACCELERATE_LAPACK_ILP64) + else() + set(BLA_VENDOR "All") + endif() + + endif() + if(NOT BLAS_FOUND) + find_package(BLAS) + if(BLAS_FOUND) + message(STATUS "Found BLAS via FindBLAS") + endif() + endif() + if(NOT BLAS_FOUND) + # Nothing specified by the user and FindBLAS didn't find anything; let's try + # if cblas is available on the system paths. + set(BLAS_INCLUDE_DIRS + "" + CACHE STRING "") + set(BLAS_LIBRARIES + -lcblas + CACHE STRING "") + endif() +endif() + +# Create an imported target +if(NOT TARGET BLAS::BLAS) + add_library(BLAS INTERFACE) + set_target_properties(BLAS PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${BLAS_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}") + add_library(BLAS::BLAS ALIAS BLAS) + install(TARGETS BLAS EXPORT BLAS) + export(EXPORT BLAS NAMESPACE BLAS::) + install( + EXPORT BLAS + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Amici" + NAMESPACE BLAS::) + + + # legacy python package environment variables: + if(DEFINED ENV{BLAS_CFLAGS}) + target_compile_options(BLAS INTERFACE "$ENV{BLAS_CFLAGS}") + endif() + if(DEFINED ENV{BLAS_LIBS}) + # Note that, on Windows, at least for ninja, this will only work with dashes + # instead of slashes in any linker options + target_link_libraries(BLAS INTERFACE "$ENV{BLAS_LIBS}") + endif() + + if(NOT "${BLAS_INCLUDE_DIRS}" STREQUAL "") + target_include_directories(BLAS INTERFACE ${BLAS_INCLUDE_DIRS}) + endif() + target_compile_definitions(BLAS INTERFACE "AMICI_BLAS_${BLAS}") +else() + target_compile_definitions(BLAS::BLAS INTERFACE "AMICI_BLAS_${BLAS}") +endif() diff --git a/documentation/ExampleJax.ipynb b/documentation/ExampleJax.ipynb deleted file mode 100644 index 53e03788da..0000000000 --- a/documentation/ExampleJax.ipynb +++ /dev/null @@ -1,1113 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d4d2bc5c", - "metadata": {}, - "source": [ - "The purpose of this guide is to showcase how AMICI can be combined with differentiable programming in JAX. We will do so by reimplementing the parameter transformations available in AMICI in JAX and comparing it to the native implementation." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "b0a66e18", - "metadata": {}, - "outputs": [], - "source": [ - "import jax\n", - "import jax.numpy as jnp" - ] - }, - { - "cell_type": "markdown", - "id": "aa587260", - "metadata": {}, - "source": [ - "# Preparation" - ] - }, - { - "cell_type": "markdown", - "id": "fb2fe897", - "metadata": {}, - "source": [ - "To get started we will import a model using the [petab](https://petab.readthedocs.io). To this end, we will use the [benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab), which features a variety of different models. For more details about petab import, see the respective notebook petab [notebook](https://amici.readthedocs.io/en/latest/petab.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "04804185", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cloning into 'tmp/benchmark-models'...\n", - "remote: Enumerating objects: 336, done.\u001B[K\n", - "remote: Counting objects: 100% (336/336), done.\u001B[K\n", - "remote: Compressing objects: 100% (285/285), done.\u001B[K\n", - "remote: Total 336 (delta 88), reused 216 (delta 39), pack-reused 0\u001B[K\n", - "Receiving objects: 100% (336/336), 2.11 MiB | 7.48 MiB/s, done.\n", - "Resolving deltas: 100% (88/88), done.\n" - ] - } - ], - "source": [ - "!git clone --depth 1 https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab.git tmp/benchmark-models || (cd tmp/benchmark-models && git pull)\n", - "from pathlib import Path\n", - "\n", - "folder_base = Path(\".\") / \"tmp\" / \"benchmark-models\" / \"Benchmark-Models\"" - ] - }, - { - "cell_type": "markdown", - "id": "8552f123", - "metadata": {}, - "source": [ - "From the benchmark collection, we now import the Boehm model." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "9166e3bf", - "metadata": {}, - "outputs": [], - "source": [ - "import petab\n", - "\n", - "model_name = \"Boehm_JProteomeRes2014\"\n", - "yaml_file = folder_base / model_name / (model_name + \".yaml\")\n", - "petab_problem = petab.Problem.from_yaml(yaml_file)" - ] - }, - { - "cell_type": "markdown", - "id": "d4038fc4", - "metadata": {}, - "source": [ - "The petab problem includes information about parameter scaling in it's the parameter table. For the boehm model, all estimated parameters (`petab.ESTIMATE` column equal to `1`) have a `petab.LOG10` as parameter scaling." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "b04ca561", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
parameterNameparameterScalelowerBoundupperBoundnominalValueestimate
parameterId
Epo_degradation_BaF3EPO_{degradation,BaF3}log100.000011000000.0269831
k_exp_heterok_{exp,hetero}log100.000011000000.0000101
k_exp_homok_{exp,homo}log100.000011000000.0061701
k_imp_heterok_{imp,hetero}log100.000011000000.0163681
k_imp_homok_{imp,homo}log100.0000110000097749.3794021
k_phosk_{phos}log100.0000110000015766.5070201
ratioratiolin-5.0000050.6930000
sd_pSTAT5A_rel\\sigma_{pSTAT5A,rel}log100.000011000003.8526121
sd_pSTAT5B_rel\\sigma_{pSTAT5B,rel}log100.000011000006.5914781
sd_rSTAT5A_rel\\sigma_{rSTAT5A,rel}log100.000011000003.1527131
specC17specC17lin-5.0000050.1070000
\n", - "
" - ], - "text/plain": [ - " parameterName parameterScale lowerBound \\\n", - "parameterId \n", - "Epo_degradation_BaF3 EPO_{degradation,BaF3} log10 0.00001 \n", - "k_exp_hetero k_{exp,hetero} log10 0.00001 \n", - "k_exp_homo k_{exp,homo} log10 0.00001 \n", - "k_imp_hetero k_{imp,hetero} log10 0.00001 \n", - "k_imp_homo k_{imp,homo} log10 0.00001 \n", - "k_phos k_{phos} log10 0.00001 \n", - "ratio ratio lin -5.00000 \n", - "sd_pSTAT5A_rel \\sigma_{pSTAT5A,rel} log10 0.00001 \n", - "sd_pSTAT5B_rel \\sigma_{pSTAT5B,rel} log10 0.00001 \n", - "sd_rSTAT5A_rel \\sigma_{rSTAT5A,rel} log10 0.00001 \n", - "specC17 specC17 lin -5.00000 \n", - "\n", - " upperBound nominalValue estimate \n", - "parameterId \n", - "Epo_degradation_BaF3 100000 0.026983 1 \n", - "k_exp_hetero 100000 0.000010 1 \n", - "k_exp_homo 100000 0.006170 1 \n", - "k_imp_hetero 100000 0.016368 1 \n", - "k_imp_homo 100000 97749.379402 1 \n", - "k_phos 100000 15766.507020 1 \n", - "ratio 5 0.693000 0 \n", - "sd_pSTAT5A_rel 100000 3.852612 1 \n", - "sd_pSTAT5B_rel 100000 6.591478 1 \n", - "sd_rSTAT5A_rel 100000 3.152713 1 \n", - "specC17 5 0.107000 0 " - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "petab_problem.parameter_df" - ] - }, - { - "cell_type": "markdown", - "id": "8914a18d", - "metadata": {}, - "source": [ - "We now import the petab problem using [`amici.petab_import`](https://amici.readthedocs.io/en/latest/generated/amici.petab_import.html#amici.petab_import.import_petab_problem)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "6ada3fb8", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:18.049 - amici.petab_import - INFO - Importing model ...\n", - "2023-02-16 12:37:18.050 - amici.petab_import - INFO - Validating PEtab problem ...\n", - "2023-02-16 12:37:18.343 - amici.petab_import - INFO - Model name is 'Boehm_JProteomeRes2014'.\n", - "Writing model code to '/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014'.\n", - "2023-02-16 12:37:18.344 - amici.petab_import - INFO - Species: 8\n", - "2023-02-16 12:37:18.344 - amici.petab_import - INFO - Global parameters: 9\n", - "2023-02-16 12:37:18.344 - amici.petab_import - INFO - Reactions: 9\n", - "2023-02-16 12:37:18.353 - amici.petab_import - INFO - Observables: 3\n", - "2023-02-16 12:37:18.353 - amici.petab_import - INFO - Sigmas: 3\n", - "2023-02-16 12:37:18.357 - amici.petab_import - DEBUG - Adding output parameters to model: ['noiseParameter1_pSTAT5A_rel', 'noiseParameter1_pSTAT5B_rel', 'noiseParameter1_rSTAT5A_rel']\n", - "2023-02-16 12:37:18.357 - amici.petab_import - DEBUG - Adding initial assignments for []\n", - "2023-02-16 12:37:18.363 - amici.petab_import - DEBUG - Condition table: (1, 1)\n", - "2023-02-16 12:37:18.364 - amici.petab_import - DEBUG - Fixed parameters are ['ratio', 'specC17']\n", - "2023-02-16 12:37:18.364 - amici.petab_import - INFO - Overall fixed parameters: 2\n", - "2023-02-16 12:37:18.364 - amici.petab_import - INFO - Variable parameters: 10\n", - "2023-02-16 12:37:18.398 - amici.sbml_import - DEBUG - Finished gathering local SBML symbols ++ (1.08E-02s)\n", - "2023-02-16 12:37:18.403 - amici.sbml_import - DEBUG - Finished processing SBML parameters ++ (2.27E-03s)\n", - "2023-02-16 12:37:18.405 - amici.sbml_import - DEBUG - Finished processing SBML compartments ++ (1.18E-04s)\n", - "2023-02-16 12:37:18.411 - amici.sbml_import - DEBUG - Finished processing SBML species initials +++ (2.19E-03s)\n", - "2023-02-16 12:37:18.413 - amici.sbml_import - DEBUG - Finished processing SBML rate rules +++ (1.46E-05s)\n", - "2023-02-16 12:37:18.413 - amici.sbml_import - DEBUG - Finished processing SBML species ++ (5.96E-03s)\n", - "2023-02-16 12:37:18.417 - amici.sbml_import - DEBUG - Finished processing SBML reactions ++ (1.01E-03s)\n", - "2023-02-16 12:37:18.420 - amici.sbml_import - DEBUG - Finished processing SBML rules ++ (1.15E-03s)\n", - "2023-02-16 12:37:18.422 - amici.sbml_import - DEBUG - Finished processing SBML initial assignments++ (4.30E-05s)\n", - "2023-02-16 12:37:18.424 - amici.sbml_import - DEBUG - Finished processing SBML species references ++ (1.96E-04s)\n", - "2023-02-16 12:37:18.426 - amici.sbml_import - DEBUG - Finished processing SBML events ++ (3.40E-05s)\n", - "2023-02-16 12:37:18.426 - amici.sbml_import - DEBUG - Finished importing SBML + (4.08E-02s)\n", - "2023-02-16 12:37:18.457 - amici.sbml_import - DEBUG - Finished processing SBML observables + (2.87E-02s)\n", - "2023-02-16 12:37:18.460 - amici.sbml_import - DEBUG - Finished processing SBML event observables + (1.12E-06s)\n", - "2023-02-16 12:37:18.476 - amici.ode_export - DEBUG - Finished running smart_multiply ++ (1.06E-03s)\n", - "2023-02-16 12:37:18.499 - amici.ode_export - DEBUG - Finished importing SbmlImporter + (2.54E-02s)\n", - "2023-02-16 12:37:18.520 - amici.ode_export - DEBUG - Finished simplifying Jy ++++ (1.33E-02s)\n", - "2023-02-16 12:37:18.521 - amici.ode_export - DEBUG - Finished computing Jy +++ (1.53E-02s)\n", - "2023-02-16 12:37:18.549 - amici.ode_export - DEBUG - Finished simplifying y ++++ (2.28E-02s)\n", - "2023-02-16 12:37:18.549 - amici.ode_export - DEBUG - Finished computing y +++ (2.48E-02s)\n", - "2023-02-16 12:37:18.554 - amici.ode_export - DEBUG - Finished simplifying sigmay ++++ (7.19E-05s)\n", - "2023-02-16 12:37:18.554 - amici.ode_export - DEBUG - Finished computing sigmay +++ (2.17E-03s)\n", - "2023-02-16 12:37:18.570 - amici.ode_export - DEBUG - Finished writing Jy.cpp ++ (6.58E-02s)\n", - "2023-02-16 12:37:18.592 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (1.63E-02s)\n", - "2023-02-16 12:37:18.601 - amici.ode_export - DEBUG - Finished simplifying dJydsigma ++++ (5.78E-03s)\n", - "2023-02-16 12:37:18.601 - amici.ode_export - DEBUG - Finished computing dJydsigma +++ (2.73E-02s)\n", - "2023-02-16 12:37:18.604 - amici.ode_export - DEBUG - Finished writing dJydsigma.cpp ++ (3.18E-02s)\n", - "2023-02-16 12:37:18.619 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (9.30E-03s)\n", - "2023-02-16 12:37:18.630 - amici.ode_export - DEBUG - Finished simplifying dJydy ++++ (7.63E-03s)\n", - "2023-02-16 12:37:18.630 - amici.ode_export - DEBUG - Finished computing dJydy +++ (2.19E-02s)\n", - "2023-02-16 12:37:18.635 - amici.ode_export - DEBUG - Finished writing dJydy.cpp ++ (2.79E-02s)\n", - "2023-02-16 12:37:18.640 - amici.ode_export - DEBUG - Finished simplifying Jz ++++ (3.06E-05s)\n", - "2023-02-16 12:37:18.641 - amici.ode_export - DEBUG - Finished computing Jz +++ (1.71E-03s)\n", - "2023-02-16 12:37:18.643 - amici.ode_export - DEBUG - Finished computing z +++ (6.17E-05s)\n", - "2023-02-16 12:37:18.647 - amici.ode_export - DEBUG - Finished simplifying sigmaz ++++ (2.92E-05s)\n", - "2023-02-16 12:37:18.647 - amici.ode_export - DEBUG - Finished computing sigmaz +++ (2.01E-03s)\n", - "2023-02-16 12:37:18.647 - amici.ode_export - DEBUG - Finished writing Jz.cpp ++ (9.91E-03s)\n", - "2023-02-16 12:37:18.653 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.68E-05s)\n", - "2023-02-16 12:37:18.655 - amici.ode_export - DEBUG - Finished simplifying dJzdsigma ++++ (3.75E-05s)\n", - "2023-02-16 12:37:18.656 - amici.ode_export - DEBUG - Finished computing dJzdsigma +++ (4.13E-03s)\n", - "2023-02-16 12:37:18.656 - amici.ode_export - DEBUG - Finished writing dJzdsigma.cpp ++ (6.25E-03s)\n", - "2023-02-16 12:37:18.661 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.62E-05s)\n", - "2023-02-16 12:37:18.663 - amici.ode_export - DEBUG - Finished simplifying dJzdz ++++ (3.29E-05s)\n", - "2023-02-16 12:37:18.664 - amici.ode_export - DEBUG - Finished computing dJzdz +++ (3.72E-03s)\n", - "2023-02-16 12:37:18.664 - amici.ode_export - DEBUG - Finished writing dJzdz.cpp ++ (5.33E-03s)\n", - "2023-02-16 12:37:18.669 - amici.ode_export - DEBUG - Finished simplifying Jrz ++++ (3.16E-05s)\n", - "2023-02-16 12:37:18.670 - amici.ode_export - DEBUG - Finished computing Jrz +++ (1.69E-03s)\n", - "2023-02-16 12:37:18.672 - amici.ode_export - DEBUG - Finished computing rz +++ (5.45E-05s)\n", - "2023-02-16 12:37:18.672 - amici.ode_export - DEBUG - Finished writing Jrz.cpp ++ (5.46E-03s)\n", - "2023-02-16 12:37:18.677 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.60E-05s)\n", - "2023-02-16 12:37:18.679 - amici.ode_export - DEBUG - Finished simplifying dJrzdsigma ++++ (3.63E-05s)\n", - "2023-02-16 12:37:18.679 - amici.ode_export - DEBUG - Finished computing dJrzdsigma +++ (3.57E-03s)\n", - "2023-02-16 12:37:18.679 - amici.ode_export - DEBUG - Finished writing dJrzdsigma.cpp ++ (5.15E-03s)\n", - "2023-02-16 12:37:18.684 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.39E-05s)\n", - "2023-02-16 12:37:18.686 - amici.ode_export - DEBUG - Finished simplifying dJrzdz ++++ (3.45E-05s)\n", - "2023-02-16 12:37:18.687 - amici.ode_export - DEBUG - Finished computing dJrzdz +++ (3.68E-03s)\n", - "2023-02-16 12:37:18.687 - amici.ode_export - DEBUG - Finished writing dJrzdz.cpp ++ (5.31E-03s)\n", - "2023-02-16 12:37:18.692 - amici.ode_export - DEBUG - Finished simplifying root ++++ (3.28E-05s)\n", - "2023-02-16 12:37:18.693 - amici.ode_export - DEBUG - Finished computing root +++ (1.74E-03s)\n", - "2023-02-16 12:37:18.693 - amici.ode_export - DEBUG - Finished writing root.cpp ++ (3.46E-03s)\n", - "2023-02-16 12:37:18.707 - amici.ode_export - DEBUG - Finished simplifying w +++++ (7.04E-03s)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:18.707 - amici.ode_export - DEBUG - Finished computing w ++++ (8.93E-03s)\n", - "2023-02-16 12:37:18.719 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (9.60E-03s)\n", - "2023-02-16 12:37:18.726 - amici.ode_export - DEBUG - Finished simplifying dwdp ++++ (4.59E-03s)\n", - "2023-02-16 12:37:18.726 - amici.ode_export - DEBUG - Finished computing dwdp +++ (2.93E-02s)\n", - "2023-02-16 12:37:18.730 - amici.ode_export - DEBUG - Finished writing dwdp.cpp ++ (3.43E-02s)\n", - "2023-02-16 12:37:18.743 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (8.10E-03s)\n", - "2023-02-16 12:37:18.749 - amici.ode_export - DEBUG - Finished simplifying dwdx ++++ (3.24E-03s)\n", - "2023-02-16 12:37:18.749 - amici.ode_export - DEBUG - Finished computing dwdx +++ (1.54E-02s)\n", - "2023-02-16 12:37:18.753 - amici.ode_export - DEBUG - Finished writing dwdx.cpp ++ (2.02E-02s)\n", - "2023-02-16 12:37:18.762 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (3.16E-03s)\n", - "2023-02-16 12:37:18.767 - amici.ode_export - DEBUG - Finished simplifying dwdw ++++ (2.23E-03s)\n", - "2023-02-16 12:37:18.767 - amici.ode_export - DEBUG - Finished computing dwdw +++ (9.56E-03s)\n", - "2023-02-16 12:37:18.769 - amici.ode_export - DEBUG - Finished writing dwdw.cpp ++ (1.30E-02s)\n", - "2023-02-16 12:37:18.780 - amici.ode_export - DEBUG - Finished simplifying xdot +++++ (3.54E-03s)\n", - "2023-02-16 12:37:18.780 - amici.ode_export - DEBUG - Finished computing xdot ++++ (5.53E-03s)\n", - "2023-02-16 12:37:18.790 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (6.83E-03s)\n", - "2023-02-16 12:37:18.792 - amici.ode_export - DEBUG - Finished simplifying dxdotdw ++++ (2.24E-04s)\n", - "2023-02-16 12:37:18.793 - amici.ode_export - DEBUG - Finished computing dxdotdw +++ (1.98E-02s)\n", - "2023-02-16 12:37:18.797 - amici.ode_export - DEBUG - Finished writing dxdotdw.cpp ++ (2.55E-02s)\n", - "2023-02-16 12:37:18.804 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (5.02E-04s)\n", - "2023-02-16 12:37:18.806 - amici.ode_export - DEBUG - Finished simplifying dxdotdx_explicit ++++ (3.57E-05s)\n", - "2023-02-16 12:37:18.806 - amici.ode_export - DEBUG - Finished computing dxdotdx_explicit +++ (4.47E-03s)\n", - "2023-02-16 12:37:18.806 - amici.ode_export - DEBUG - Finished writing dxdotdx_explicit.cpp ++ (6.56E-03s)\n", - "2023-02-16 12:37:18.812 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (5.50E-04s)\n", - "2023-02-16 12:37:18.814 - amici.ode_export - DEBUG - Finished simplifying dxdotdp_explicit ++++ (3.08E-05s)\n", - "2023-02-16 12:37:18.815 - amici.ode_export - DEBUG - Finished computing dxdotdp_explicit +++ (4.37E-03s)\n", - "2023-02-16 12:37:18.815 - amici.ode_export - DEBUG - Finished writing dxdotdp_explicit.cpp ++ (6.87E-03s)\n", - "2023-02-16 12:37:18.854 - amici.ode_export - DEBUG - Finished running smart_jacobian +++++ (3.12E-02s)\n", - "2023-02-16 12:37:18.897 - amici.ode_export - DEBUG - Finished simplifying dydx +++++ (4.02E-02s)\n", - "2023-02-16 12:37:18.898 - amici.ode_export - DEBUG - Finished computing dydx ++++ (7.70E-02s)\n", - "2023-02-16 12:37:18.903 - amici.ode_export - DEBUG - Finished running smart_jacobian +++++ (4.23E-04s)\n", - "2023-02-16 12:37:18.905 - amici.ode_export - DEBUG - Finished simplifying dydw +++++ (2.99E-05s)\n", - "2023-02-16 12:37:18.906 - amici.ode_export - DEBUG - Finished computing dydw ++++ (4.61E-03s)\n", - "2023-02-16 12:37:18.942 - amici.ode_export - DEBUG - Finished simplifying dydx ++++ (3.36E-02s)\n", - "2023-02-16 12:37:18.942 - amici.ode_export - DEBUG - Finished computing dydx +++ (1.23E-01s)\n", - "2023-02-16 12:37:18.958 - amici.ode_export - DEBUG - Finished writing dydx.cpp ++ (1.40E-01s)\n", - "2023-02-16 12:37:18.966 - amici.ode_export - DEBUG - Finished running smart_jacobian +++++ (3.85E-04s)\n", - "2023-02-16 12:37:18.968 - amici.ode_export - DEBUG - Finished simplifying dydp +++++ (3.45E-05s)\n", - "2023-02-16 12:37:18.968 - amici.ode_export - DEBUG - Finished computing dydp ++++ (4.15E-03s)\n", - "2023-02-16 12:37:18.971 - amici.ode_export - DEBUG - Finished simplifying dydp ++++ (3.38E-05s)\n", - "2023-02-16 12:37:18.971 - amici.ode_export - DEBUG - Finished computing dydp +++ (8.39E-03s)\n", - "2023-02-16 12:37:18.971 - amici.ode_export - DEBUG - Finished writing dydp.cpp ++ (1.04E-02s)\n", - "2023-02-16 12:37:18.975 - amici.ode_export - DEBUG - Finished computing dzdx +++ (5.68E-05s)\n", - "2023-02-16 12:37:18.975 - amici.ode_export - DEBUG - Finished writing dzdx.cpp ++ (1.63E-03s)\n", - "2023-02-16 12:37:18.979 - amici.ode_export - DEBUG - Finished computing dzdp +++ (4.66E-05s)\n", - "2023-02-16 12:37:18.979 - amici.ode_export - DEBUG - Finished writing dzdp.cpp ++ (1.61E-03s)\n", - "2023-02-16 12:37:18.982 - amici.ode_export - DEBUG - Finished computing drzdx +++ (4.78E-05s)\n", - "2023-02-16 12:37:18.983 - amici.ode_export - DEBUG - Finished writing drzdx.cpp ++ (1.67E-03s)\n", - "2023-02-16 12:37:18.986 - amici.ode_export - DEBUG - Finished computing drzdp +++ (5.38E-05s)\n", - "2023-02-16 12:37:18.986 - amici.ode_export - DEBUG - Finished writing drzdp.cpp ++ (1.69E-03s)\n", - "2023-02-16 12:37:18.992 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (1.11E-04s)\n", - "2023-02-16 12:37:18.994 - amici.ode_export - DEBUG - Finished simplifying dsigmaydy ++++ (3.44E-05s)\n", - "2023-02-16 12:37:18.994 - amici.ode_export - DEBUG - Finished computing dsigmaydy +++ (3.81E-03s)\n", - "2023-02-16 12:37:18.994 - amici.ode_export - DEBUG - Finished writing dsigmaydy.cpp ++ (5.42E-03s)\n", - "2023-02-16 12:37:19.000 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (4.32E-04s)\n", - "2023-02-16 12:37:19.002 - amici.ode_export - DEBUG - Finished simplifying dsigmaydp ++++ (7.44E-05s)\n", - "2023-02-16 12:37:19.002 - amici.ode_export - DEBUG - Finished computing dsigmaydp +++ (4.23E-03s)\n", - "2023-02-16 12:37:19.003 - amici.ode_export - DEBUG - Finished writing dsigmaydp.cpp ++ (6.96E-03s)\n", - "2023-02-16 12:37:19.006 - amici.ode_export - DEBUG - Finished writing sigmay.cpp ++ (5.00E-04s)\n", - "2023-02-16 12:37:19.011 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.56E-05s)\n", - "2023-02-16 12:37:19.013 - amici.ode_export - DEBUG - Finished simplifying dsigmazdp ++++ (3.78E-05s)\n", - "2023-02-16 12:37:19.013 - amici.ode_export - DEBUG - Finished computing dsigmazdp +++ (3.67E-03s)\n", - "2023-02-16 12:37:19.014 - amici.ode_export - DEBUG - Finished writing dsigmazdp.cpp ++ (5.26E-03s)\n", - "2023-02-16 12:37:19.016 - amici.ode_export - DEBUG - Finished writing sigmaz.cpp ++ (1.64E-05s)\n", - "2023-02-16 12:37:19.019 - amici.ode_export - DEBUG - Finished computing stau +++ (5.81E-05s)\n", - "2023-02-16 12:37:19.019 - amici.ode_export - DEBUG - Finished writing stau.cpp ++ (1.65E-03s)\n", - "2023-02-16 12:37:19.023 - amici.ode_export - DEBUG - Finished computing deltax +++ (5.10E-05s)\n", - "2023-02-16 12:37:19.024 - amici.ode_export - DEBUG - Finished writing deltax.cpp ++ (1.91E-03s)\n", - "2023-02-16 12:37:19.027 - amici.ode_export - DEBUG - Finished computing deltasx +++ (5.45E-05s)\n", - "2023-02-16 12:37:19.028 - amici.ode_export - DEBUG - Finished writing deltasx.cpp ++ (1.86E-03s)\n", - "2023-02-16 12:37:19.032 - amici.ode_export - DEBUG - Finished writing w.cpp ++ (2.53E-03s)\n", - "2023-02-16 12:37:19.038 - amici.ode_export - DEBUG - Finished simplifying x0 ++++ (8.98E-04s)\n", - "2023-02-16 12:37:19.038 - amici.ode_export - DEBUG - Finished computing x0 +++ (2.79E-03s)\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:19.040 - amici.ode_export - DEBUG - Finished writing x0.cpp ++ (5.34E-03s)\n", - "2023-02-16 12:37:19.046 - amici.ode_export - DEBUG - Finished simplifying x0_fixedParameters ++++ (3.45E-04s)\n", - "2023-02-16 12:37:19.046 - amici.ode_export - DEBUG - Finished computing x0_fixedParameters +++ (2.33E-03s)\n", - "2023-02-16 12:37:19.047 - amici.ode_export - DEBUG - Finished writing x0_fixedParameters.cpp ++ (4.79E-03s)\n", - "2023-02-16 12:37:19.053 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (9.02E-04s)\n", - "2023-02-16 12:37:19.055 - amici.ode_export - DEBUG - Finished simplifying sx0 ++++ (3.90E-05s)\n", - "2023-02-16 12:37:19.055 - amici.ode_export - DEBUG - Finished computing sx0 +++ (4.79E-03s)\n", - "2023-02-16 12:37:19.056 - amici.ode_export - DEBUG - Finished writing sx0.cpp ++ (6.54E-03s)\n", - "2023-02-16 12:37:19.061 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (8.95E-05s)\n", - "2023-02-16 12:37:19.063 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (1.41E-04s)\n", - "2023-02-16 12:37:19.066 - amici.ode_export - DEBUG - Finished simplifying sx0_fixedParameters ++++ (2.92E-05s)\n", - "2023-02-16 12:37:19.066 - amici.ode_export - DEBUG - Finished computing sx0_fixedParameters +++ (6.44E-03s)\n", - "2023-02-16 12:37:19.067 - amici.ode_export - DEBUG - Finished writing sx0_fixedParameters.cpp ++ (8.77E-03s)\n", - "2023-02-16 12:37:19.075 - amici.ode_export - DEBUG - Finished writing xdot.cpp ++ (5.99E-03s)\n", - "2023-02-16 12:37:19.080 - amici.ode_export - DEBUG - Finished writing y.cpp ++ (2.52E-03s)\n", - "2023-02-16 12:37:19.085 - amici.ode_export - DEBUG - Finished simplifying x_rdata ++++ (7.20E-05s)\n", - "2023-02-16 12:37:19.086 - amici.ode_export - DEBUG - Finished computing x_rdata +++ (2.21E-03s)\n", - "2023-02-16 12:37:19.087 - amici.ode_export - DEBUG - Finished writing x_rdata.cpp ++ (4.64E-03s)\n", - "2023-02-16 12:37:19.092 - amici.ode_export - DEBUG - Finished simplifying total_cl ++++ (3.50E-05s)\n", - "2023-02-16 12:37:19.093 - amici.ode_export - DEBUG - Finished computing total_cl +++ (1.79E-03s)\n", - "2023-02-16 12:37:19.093 - amici.ode_export - DEBUG - Finished writing total_cl.cpp ++ (3.50E-03s)\n", - "2023-02-16 12:37:19.098 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.68E-05s)\n", - "2023-02-16 12:37:19.100 - amici.ode_export - DEBUG - Finished simplifying dtotal_cldp ++++ (3.98E-05s)\n", - "2023-02-16 12:37:19.100 - amici.ode_export - DEBUG - Finished computing dtotal_cldp +++ (3.62E-03s)\n", - "2023-02-16 12:37:19.100 - amici.ode_export - DEBUG - Finished writing dtotal_cldp.cpp ++ (5.25E-03s)\n", - "2023-02-16 12:37:19.105 - amici.ode_export - DEBUG - Finished simplifying dtotal_cldx_rdata ++++ (2.96E-05s)\n", - "2023-02-16 12:37:19.106 - amici.ode_export - DEBUG - Finished computing dtotal_cldx_rdata +++ (1.73E-03s)\n", - "2023-02-16 12:37:19.106 - amici.ode_export - DEBUG - Finished writing dtotal_cldx_rdata.cpp ++ (3.50E-03s)\n", - "2023-02-16 12:37:19.111 - amici.ode_export - DEBUG - Finished simplifying x_solver ++++ (7.02E-05s)\n", - "2023-02-16 12:37:19.112 - amici.ode_export - DEBUG - Finished computing x_solver +++ (1.82E-03s)\n", - "2023-02-16 12:37:19.113 - amici.ode_export - DEBUG - Finished writing x_solver.cpp ++ (4.36E-03s)\n", - "2023-02-16 12:37:19.118 - amici.ode_export - DEBUG - Finished simplifying dx_rdatadx_solver ++++ (2.82E-04s)\n", - "2023-02-16 12:37:19.118 - amici.ode_export - DEBUG - Finished computing dx_rdatadx_solver +++ (1.94E-03s)\n", - "2023-02-16 12:37:19.119 - amici.ode_export - DEBUG - Finished writing dx_rdatadx_solver.cpp ++ (4.05E-03s)\n", - "2023-02-16 12:37:19.125 - amici.ode_export - DEBUG - Finished simplifying dx_rdatadp ++++ (3.14E-04s)\n", - "2023-02-16 12:37:19.125 - amici.ode_export - DEBUG - Finished computing dx_rdatadp +++ (2.11E-03s)\n", - "2023-02-16 12:37:19.126 - amici.ode_export - DEBUG - Finished writing dx_rdatadp.cpp ++ (4.04E-03s)\n", - "2023-02-16 12:37:19.131 - amici.ode_export - DEBUG - Finished running smart_jacobian ++++ (2.58E-05s)\n", - "2023-02-16 12:37:19.133 - amici.ode_export - DEBUG - Finished simplifying dx_rdatadtcl ++++ (3.95E-05s)\n", - "2023-02-16 12:37:19.133 - amici.ode_export - DEBUG - Finished computing dx_rdatadtcl +++ (3.71E-03s)\n", - "2023-02-16 12:37:19.133 - amici.ode_export - DEBUG - Finished writing dx_rdatadtcl.cpp ++ (5.36E-03s)\n", - "2023-02-16 12:37:19.136 - amici.ode_export - DEBUG - Finished writing z.cpp ++ (1.84E-05s)\n", - "2023-02-16 12:37:19.138 - amici.ode_export - DEBUG - Finished writing rz.cpp ++ (1.69E-05s)\n", - "2023-02-16 12:37:19.147 - amici.ode_export - DEBUG - Finished generating cpp code + (6.45E-01s)\n", - "2023-02-16 12:37:31.424 - amici.ode_export - DEBUG - Finished compiling cpp code + (1.23E+01s)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "running AmiciInstall\n", - "hdf5.h found in /opt/homebrew/Cellar/hdf5/1.12.2_2/include\n", - "libhdf5.a found in /opt/homebrew/Cellar/hdf5/1.12.2_2/lib\n", - "running build_ext\n", - "Changed extra_compile_args for unix to ['-std=c++14']\n", - "Building model extension in /Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014\n", - "building 'Boehm_JProteomeRes2014._Boehm_JProteomeRes2014' extension\n", - "Testing SWIG executable swig4.0... FAILED.\n", - "Testing SWIG executable swig3.0... FAILED.\n", - "Testing SWIG executable swig... SUCCEEDED.\n", - "swigging swig/Boehm_JProteomeRes2014.i to swig/Boehm_JProteomeRes2014_wrap.cpp\n", - "swig -python -c++ -modern -outdir Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/swig -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -o swig/Boehm_JProteomeRes2014_wrap.cpp swig/Boehm_JProteomeRes2014.i\n", - "Deprecated command line option: -modern. Ignored, this option is now always on.\n", - "creating build\n", - "creating build/temp.macosx-13-arm64-cpython-310\n", - "creating build/temp.macosx-13-arm64-cpython-310/swig\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_Jy.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_Jy.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydsigma.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydsigma.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydy.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydy_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dJydy_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dsigmaydp.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dsigmaydp.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdp.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdp_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdp_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdw.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdw_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdw_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdx.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdx_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dwdx_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dxdotdw.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dxdotdw_colptrs.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_colptrs.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dxdotdw_rowvals.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_rowvals.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_dydx.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dydx.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_sigmay.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sigmay.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_sx0_fixedParameters.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sx0_fixedParameters.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_w.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_w.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x0.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x0_fixedParameters.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0_fixedParameters.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x_rdata.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_rdata.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_x_solver.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_solver.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_xdot.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_xdot.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c Boehm_JProteomeRes2014_y.cpp -o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_y.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c swig/Boehm_JProteomeRes2014_wrap.cpp -o build/temp.macosx-13-arm64-cpython-310/swig/Boehm_JProteomeRes2014_wrap.o -std=c++14\n", - "clang -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk -I/Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014 -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/gsl -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/sundials/include -I/Users/fabian/Documents/projects/AMICI/python/sdist/amici/ThirdParty/SuiteSparse/include -I/opt/homebrew/Cellar/hdf5/1.12.2_2/include -I/Users/fabian/Documents/projects/AMICI/build/venv/include -I/opt/homebrew/opt/python@3.10/Frameworks/Python.framework/Versions/3.10/include/python3.10 -c wrapfunctions.cpp -o build/temp.macosx-13-arm64-cpython-310/wrapfunctions.o -std=c++14\n", - "clang++ -bundle -undefined dynamic_lookup -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX13.sdk build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_Jy.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydsigma.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dJydy_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dsigmaydp.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdp_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdw_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dwdx_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_colptrs.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dxdotdw_rowvals.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_dydx.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sigmay.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_sx0_fixedParameters.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_w.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x0_fixedParameters.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_rdata.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_x_solver.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_xdot.o build/temp.macosx-13-arm64-cpython-310/Boehm_JProteomeRes2014_y.o build/temp.macosx-13-arm64-cpython-310/swig/Boehm_JProteomeRes2014_wrap.o build/temp.macosx-13-arm64-cpython-310/wrapfunctions.o -L/opt/homebrew/Cellar/hdf5/1.12.2_2/lib -L/Users/fabian/Documents/projects/AMICI/python/sdist/amici/libs -lamici -lsundials -lsuitesparse -lcblas -lhdf5_hl_cpp -lhdf5_hl -lhdf5_cpp -lhdf5 -o /Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014/Boehm_JProteomeRes2014/_Boehm_JProteomeRes2014.cpython-310-darwin.so\n", - "ld: warning: -undefined dynamic_lookup may not work with chained fixups\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2023-02-16 12:37:31.673 - amici.petab_import - INFO - Finished Importing PEtab model (1.36E+01s)\n", - "2023-02-16 12:37:31.684 - amici.petab_import - INFO - Successfully loaded model Boehm_JProteomeRes2014 from /Users/fabian/Documents/projects/AMICI/documentation/amici_models/Boehm_JProteomeRes2014.\n" - ] - } - ], - "source": [ - "from amici.petab.petab_import import import_petab_problem\n", - "\n", - "amici_model = import_petab_problem(petab_problem, compile_=True)" - ] - }, - { - "cell_type": "markdown", - "id": "7827aaf7", - "metadata": {}, - "source": [ - "# JAX implementation" - ] - }, - { - "cell_type": "markdown", - "id": "e2ef051a", - "metadata": {}, - "source": [ - "For full jax support, we would have to implement a new [primitive](https://jax.readthedocs.io/en/latest/notebooks/How_JAX_primitives_work.html), which would require quite a bit of engineering, and in the end wouldn't add much benefit since AMICI can't run on GPUs. Instead, we will interface AMICI using the experimental jax module [`host_callback`](https://jax.readthedocs.io/en/latest/jax.experimental.host_callback.html). " - ] - }, - { - "cell_type": "markdown", - "id": "6bbf2f06", - "metadata": {}, - "source": [ - "To do so, we define a base function that only takes a single argument (the parameters) and runs simulation using petab via [`simulate_petab`](https://amici.readthedocs.io/en/latest/generated/amici.petab_objective.html#amici.petab_objective.simulate_petab). To enable gradient computation later on, we create a solver object and set the sensitivity order to first order and pass it to `simulate_petab`. Moreover, `simulate_petab` expects a dictionary of parameters, so we create a dictionary using the free parameter ids from the petab problem. As we want to implement parameter transformation in JAX, we disable parameter scaling in petab by passing `scaled_parameters=True`." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "72053647", - "metadata": {}, - "outputs": [], - "source": [ - "from amici.petab.simulations import simulate_petab\n", - "import amici\n", - "\n", - "amici_solver = amici_model.getSolver()\n", - "amici_solver.setSensitivityOrder(amici.SensitivityOrder.first)\n", - "\n", - "\n", - "def amici_hcb_base(parameters: jnp.array):\n", - " return simulate_petab(\n", - " petab_problem,\n", - " amici_model,\n", - " problem_parameters=dict(zip(petab_problem.x_free_ids, parameters)),\n", - " scaled_parameters=True,\n", - " solver=amici_solver,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "6f6201e8", - "metadata": {}, - "source": [ - "Now we can use this base function to create two functions separate functions that compute the log-likelihood (`llh`) and it's gradient (`sllh`) in two individual routines. Note that, as we are using the same base function here, the log-likelihood computation will also run with sensitivities which is not necessary and will add some overhead. This is only out of convenience and should be fixed in an application where efficiency is important." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "2dd50b53", - "metadata": {}, - "outputs": [], - "source": [ - "def amici_hcb_llh(parameters: jnp.array):\n", - " return amici_hcb_base(parameters)[\"llh\"]\n", - "\n", - "\n", - "def amici_hcb_sllh(parameters: jnp.array):\n", - " sllh = amici_hcb_base(parameters)[\"sllh\"]\n", - " return jnp.asarray(\n", - " tuple(sllh[par_id] for par_id in petab_problem.x_free_ids)\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "98e819bd", - "metadata": {}, - "source": [ - "Now we can finally define the JAX function that runs amici simulation using the host callback. We add a `custom_jvp` decorator so that we can define a custom jacobian vector product function in the next step. More details about custom jacobian vector product functions can be found in the [JAX documentation](https://jax.readthedocs.io/en/latest/notebooks/Custom_derivative_rules_for_Python_code.html)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "6e1f4f43", - "metadata": {}, - "outputs": [], - "source": [ - "import jax.experimental.host_callback as hcb\n", - "from jax import custom_jvp\n", - "\n", - "import numpy as np\n", - "\n", - "\n", - "@custom_jvp\n", - "def jax_objective(parameters: jnp.array):\n", - " return hcb.call(\n", - " amici_hcb_llh,\n", - " parameters,\n", - " result_shape=jax.ShapeDtypeStruct((), np.float64),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "c75535a5", - "metadata": {}, - "source": [ - "Now we define the function that implement the jacobian vector product. This effectively just returns the objective function value (computed using the previously defined `jax_objective`) as well as the inner product of the gradient (computed using a host callback to the previously defined `amici_hcb_sllh`) and the tangents vector. Note that this implementation performs two simulation runs, one for the function value and one for the gradient, which is inefficient and could be avoided by caching solutions." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "5a68c812", - "metadata": {}, - "outputs": [], - "source": [ - "@jax_objective.defjvp\n", - "def jax_objective_jvp(primals: jnp.array, tangents: jnp.array):\n", - " (parameters,) = primals\n", - " (x_dot,) = tangents\n", - " llh = jax_objective(parameters)\n", - " sllh = hcb.call(\n", - " amici_hcb_sllh,\n", - " parameters,\n", - " result_shape=jax.ShapeDtypeStruct(\n", - " (petab_problem.parameter_df.estimate.sum(),), np.float64\n", - " ),\n", - " )\n", - " return llh, sllh.dot(x_dot)" - ] - }, - { - "cell_type": "markdown", - "id": "379485ca", - "metadata": {}, - "source": [ - "As last step, we implement the parameter transformation in jax. This effectively just extracts parameter scales from the petab problem, implements rescaling in jax and then passes the scaled parameters to the previously objective function we previously defined. We add the `value_and_grad` decorator such that the generated jax function returns both function value and function gradient in a tuple. Moreover, we add the `jax.jit` decorator such that the function is [just in time compiled](https://jax.readthedocs.io/en/latest/jax-101/02-jitting.html) upon the first function call." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "3ab8fde9", - "metadata": {}, - "outputs": [], - "source": [ - "from jax import value_and_grad\n", - "\n", - "parameter_scales = petab_problem.parameter_df.loc[\n", - " petab_problem.x_free_ids, petab.PARAMETER_SCALE\n", - "].values\n", - "\n", - "\n", - "@jax.jit\n", - "@value_and_grad\n", - "def jax_objective_with_parameter_transform(parameters: jnp.array):\n", - " par_scaled = jnp.asarray(\n", - " tuple(\n", - " value\n", - " if scale == petab.LIN\n", - " else jnp.log(value)\n", - " if scale == petab.LOG\n", - " else jnp.log10(value)\n", - " for value, scale in zip(parameters, parameter_scales)\n", - " )\n", - " )\n", - " return jax_objective(par_scaled)" - ] - }, - { - "cell_type": "markdown", - "id": "bce56636", - "metadata": {}, - "source": [ - "# Testing" - ] - }, - { - "cell_type": "markdown", - "id": "293e29fb", - "metadata": {}, - "source": [ - "We can now run the function to compute the log-likelihood and the gradient. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "fb3085a8", - "metadata": {}, - "outputs": [], - "source": [ - "llh_jax, sllh_jax = jax_objective_with_parameter_transform(\n", - " petab_problem.x_nominal_free\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "6aa4a5f7", - "metadata": {}, - "source": [ - "As a sanity check, we compare the computed value to native parameter transformation in amici. " - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "48451b0e", - "metadata": {}, - "outputs": [], - "source": [ - "r = simulate_petab(petab_problem, amici_model, solver=amici_solver)\n", - "# TODO remove me as soon as sllh in simulate_petab is fixed\n", - "sllh = {\n", - " name: value / (np.log(10) * par_value)\n", - " for (name, value), par_value in zip(\n", - " r[\"sllh\"].items(), petab_problem.x_nominal_free\n", - " )\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "2628db12", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "amici -138.221997\n", - "jax -138.222000\n", - "dtype: float64" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "\n", - "pd.Series(dict(amici=r[\"llh\"], jax=float(llh_jax)))" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "0846523f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
amicijax
Epo_degradation_BaF3-3.546026e-01-3.640394e-01
k_exp_hetero-2.401005e+03-2.401010e+03
k_exp_homo-4.073832e-01-4.106763e-01
k_imp_hetero-1.432855e-01-1.639030e-01
k_imp_homo2.006412e-102.006412e-10
k_phos-2.179950e-07-2.089803e-07
sd_pSTAT5A_rel-1.215545e-03-1.222887e-03
sd_pSTAT5B_rel-1.583889e-03-1.580870e-03
sd_rSTAT5A_rel-2.643776e-03-2.641361e-03
\n", - "
" - ], - "text/plain": [ - " amici jax\n", - "Epo_degradation_BaF3 -3.546026e-01 -3.640394e-01\n", - "k_exp_hetero -2.401005e+03 -2.401010e+03\n", - "k_exp_homo -4.073832e-01 -4.106763e-01\n", - "k_imp_hetero -1.432855e-01 -1.639030e-01\n", - "k_imp_homo 2.006412e-10 2.006412e-10\n", - "k_phos -2.179950e-07 -2.089803e-07\n", - "sd_pSTAT5A_rel -1.215545e-03 -1.222887e-03\n", - "sd_pSTAT5B_rel -1.583889e-03 -1.580870e-03\n", - "sd_rSTAT5A_rel -2.643776e-03 -2.641361e-03" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame(\n", - " index=sllh.keys(), data=dict(amici=sllh.values(), jax=np.asarray(sllh_jax))\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "4b00dcb2", - "metadata": {}, - "source": [ - "We see quite some differences in the gradient calculation. The primary reason is that running JAX in default configuration will use float32 precision for the parameters that are passed to AMICI, which uses float64, and the derivative of the parameter transformation \n", - "As AMICI simulations that run on the CPU are the most expensive operation, there is barely any tradeoff for using float32 vs float64 in JAX. Therefore, we configure JAX to use float64 instead and rerun simulations." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "5f81c693", - "metadata": {}, - "outputs": [], - "source": [ - "jax.config.update(\"jax_enable_x64\", True)\n", - "llh_jax, sllh_jax = jax_objective_with_parameter_transform(\n", - " petab_problem.x_nominal_free\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "ab39311d", - "metadata": {}, - "source": [ - "We can now evaluate the results again and see that differences between pure AMICI and AMICI/JAX implementations are now much smaller." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "25e8b301", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "amici -138.221997\n", - "jax -138.221997\n", - "dtype: float64" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.Series(dict(amici=r[\"llh\"], jax=float(llh_jax)))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "f31a3927", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
amicijax
Epo_degradation_BaF3-3.546026e-01-3.546504e-01
k_exp_hetero-2.401005e+03-2.401005e+03
k_exp_homo-4.073832e-01-4.074248e-01
k_imp_hetero-1.432855e-01-1.433139e-01
k_imp_homo2.006412e-102.006412e-10
k_phos-2.179950e-07-2.179076e-07
sd_pSTAT5A_rel-1.215545e-03-1.215596e-03
sd_pSTAT5B_rel-1.583889e-03-1.583805e-03
sd_rSTAT5A_rel-2.643776e-03-2.643703e-03
\n", - "
" - ], - "text/plain": [ - " amici jax\n", - "Epo_degradation_BaF3 -3.546026e-01 -3.546504e-01\n", - "k_exp_hetero -2.401005e+03 -2.401005e+03\n", - "k_exp_homo -4.073832e-01 -4.074248e-01\n", - "k_imp_hetero -1.432855e-01 -1.433139e-01\n", - "k_imp_homo 2.006412e-10 2.006412e-10\n", - "k_phos -2.179950e-07 -2.179076e-07\n", - "sd_pSTAT5A_rel -1.215545e-03 -1.215596e-03\n", - "sd_pSTAT5B_rel -1.583889e-03 -1.583805e-03\n", - "sd_rSTAT5A_rel -2.643776e-03 -2.643703e-03" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame(\n", - " index=sllh.keys(), data=dict(amici=sllh.values(), jax=np.asarray(sllh_jax))\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/documentation/ExampleJax.ipynb b/documentation/ExampleJax.ipynb new file mode 120000 index 0000000000..af2929d76b --- /dev/null +++ b/documentation/ExampleJax.ipynb @@ -0,0 +1 @@ +../python/examples/example_jax/ExampleJax.ipynb \ No newline at end of file diff --git a/documentation/python_modules.rst b/documentation/python_modules.rst index 237a0a021f..2607447f0d 100644 --- a/documentation/python_modules.rst +++ b/documentation/python_modules.rst @@ -12,6 +12,7 @@ AMICI Python API amici.pysb_import amici.bngl_import amici.petab + amici.petab.conditions amici.petab.import_helpers amici.petab.parameter_mapping amici.petab.petab_import @@ -26,6 +27,7 @@ AMICI Python API amici.import_utils amici.de_export amici.de_model + amici.de_model_components amici.plotting amici.pandas amici.logging diff --git a/include/amici/abstract_model.h b/include/amici/abstract_model.h index d88347078d..f340214e7e 100644 --- a/include/amici/abstract_model.h +++ b/include/amici/abstract_model.h @@ -820,11 +820,15 @@ class AbstractModel { * @param h Heaviside vector * @param tcl total abundances for conservation laws * @param spl spline value vector + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ virtual void fw(realtype* w, realtype const t, realtype const* x, realtype const* p, realtype const* k, realtype const* h, realtype const* tcl, - realtype const* spl); + realtype const* spl, bool include_static = true); /** * @brief Model-specific sparse implementation of dwdp @@ -840,12 +844,16 @@ class AbstractModel { * @param spl spline value vector * @param sspl sensitivities of spline values vector w.r.t. parameters \f$ p * \f$ + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ virtual void fdwdp( realtype* dwdp, realtype const t, realtype const* x, realtype const* p, realtype const* k, realtype const* h, realtype const* w, realtype const* tcl, realtype const* stcl, realtype const* spl, - realtype const* sspl + realtype const* sspl, bool include_static = true ); /** @@ -860,28 +868,6 @@ class AbstractModel { */ virtual void fdwdp_rowvals(SUNMatrixWrapper& dwdp); - /** - * @brief Model-specific sensitivity implementation of dwdp - * @param dwdp Recurring terms in xdot, parameter derivative - * @param t timepoint - * @param x vector with the states - * @param p parameter vector - * @param k constants vector - * @param h Heaviside vector - * @param w vector with helper variables - * @param tcl total abundances for conservation laws - * @param stcl sensitivities of total abundances for conservation laws - * @param spl spline value vector - * @param sspl sensitivities of spline values vector - * @param ip sensitivity parameter index - */ - virtual void fdwdp( - realtype* dwdp, realtype const t, realtype const* x, realtype const* p, - realtype const* k, realtype const* h, realtype const* w, - realtype const* tcl, realtype const* stcl, realtype const* spl, - realtype const* sspl, int ip - ); - /** * @brief Model-specific implementation of dwdx, data part * @param dwdx Recurring terms in xdot, state derivative @@ -893,11 +879,15 @@ class AbstractModel { * @param w vector with helper variables * @param tcl total abundances for conservation laws * @param spl spline value vector + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ virtual void fdwdx( realtype* dwdx, realtype const t, realtype const* x, realtype const* p, realtype const* k, realtype const* h, realtype const* w, - realtype const* tcl, realtype const* spl + realtype const* tcl, realtype const* spl, bool include_static = true ); /** @@ -922,11 +912,15 @@ class AbstractModel { * @param h Heaviside vector * @param w vector with helper variables * @param tcl Total abundances for conservation laws + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ virtual void fdwdw( realtype* dwdw, realtype t, realtype const* x, realtype const* p, realtype const* k, realtype const* h, realtype const* w, - realtype const* tcl + realtype const* tcl, bool include_static = true ); /** diff --git a/include/amici/defines.h b/include/amici/defines.h index f5ed1e62bb..bd97d9a0b2 100644 --- a/include/amici/defines.h +++ b/include/amici/defines.h @@ -68,6 +68,7 @@ constexpr int AMICI_TOO_MUCH_WORK= -1; constexpr int AMICI_TOO_MUCH_ACC= -2; constexpr int AMICI_ERR_FAILURE= -3; constexpr int AMICI_CONV_FAILURE= -4; +constexpr int AMICI_LSETUP_FAIL= -6; constexpr int AMICI_RHSFUNC_FAIL= -8; constexpr int AMICI_FIRST_RHSFUNC_ERR= -9; constexpr int AMICI_ILL_INPUT= -22; @@ -254,6 +255,15 @@ enum class SplineExtrapolation { periodic = 3, }; +/** Constraints on state variables */ +enum class Constraint { + none = 0, + non_negative = 1, + non_positive = -1, + positive = 2, + negative = -2, +}; + // clang-format on } // namespace amici diff --git a/include/amici/forwardproblem.h b/include/amici/forwardproblem.h index 8c500bf73c..67658ebee4 100644 --- a/include/amici/forwardproblem.h +++ b/include/amici/forwardproblem.h @@ -316,7 +316,7 @@ class ForwardProblem { * @brief Creates a carbon copy of the current simulation state variables * @return state */ - SimulationState getSimulationState() const; + SimulationState getSimulationState(); /** array of index vectors (dimension ne) indicating whether the respective * root has been detected for all so far encountered discontinuities, diff --git a/include/amici/model.h b/include/amici/model.h index 23f6ac63c8..29b98aa913 100644 --- a/include/amici/model.h +++ b/include/amici/model.h @@ -239,6 +239,18 @@ class Model : public AbstractModel, public ModelDimensions { bool computeSensitivities, std::vector& roots_found ); + /** + * @brief Re-initialize model properties after changing simulation context. + * @param t Timepoint + * @param x Reference to state variables + * @param sx Reference to state variable sensitivities + * @param computeSensitivities Flag indicating whether sensitivities are to + * be computed + */ + void reinitialize( + realtype t, AmiVector& x, AmiVectorArray& sx, bool computeSensitivities + ); + /** * @brief Initialize model properties. * @param xB Adjoint state variables @@ -1322,10 +1334,12 @@ class Model : public AbstractModel, public ModelDimensions { * * @param array * @param model_quantity The model quantity `array` corresponds to + * @param t Current timepoint * @return */ int checkFinite( - gsl::span array, ModelQuantity model_quantity + gsl::span array, ModelQuantity model_quantity, + realtype t ) const; /** * @brief Check if the given array has only finite elements. @@ -1335,11 +1349,12 @@ class Model : public AbstractModel, public ModelDimensions { * @param array Flattened matrix * @param model_quantity The model quantity `array` corresponds to * @param num_cols Number of columns of the non-flattened matrix + * @param t Current timepoint * @return */ int checkFinite( gsl::span array, ModelQuantity model_quantity, - size_t num_cols + size_t num_cols, realtype t ) const; /** @@ -1828,29 +1843,45 @@ class Model : public AbstractModel, public ModelDimensions { * @brief Compute recurring terms in xdot. * @param t Timepoint * @param x Array with the states + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ - void fw(realtype t, realtype const* x); + void fw(realtype t, realtype const* x, bool include_static = true); /** * @brief Compute parameter derivative for recurring terms in xdot. * @param t Timepoint * @param x Array with the states + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ - void fdwdp(realtype t, realtype const* x); + void fdwdp(realtype t, realtype const* x, bool include_static = true); /** * @brief Compute state derivative for recurring terms in xdot. * @param t Timepoint * @param x Array with the states + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ - void fdwdx(realtype t, realtype const* x); + void fdwdx(realtype t, realtype const* x, bool include_static = true); /** * @brief Compute self derivative for recurring terms in xdot. * @param t Timepoint * @param x Array with the states + * @param include_static Whether to (re-)evaluate only dynamic expressions + * (false) or also static expressions (true). + * Dynamic expressions are those that depend directly or indirectly on time, + * static expressions are those that don't. */ - void fdwdw(realtype t, realtype const* x); + void fdwdw(realtype t, realtype const* x, bool include_static = true); /** * @brief Compute fx_rdata. diff --git a/include/amici/rdata.h b/include/amici/rdata.h index 1de02c99db..b5b4c269b4 100644 --- a/include/amici/rdata.h +++ b/include/amici/rdata.h @@ -104,12 +104,12 @@ class ReturnData : public ModelDimensions { */ std::vector ts; - /** time derivative (shape `nx`) */ + /** time derivative (shape `nx`) evaluated at `t_last`. */ std::vector xdot; /** * Jacobian of differential equation right hand side (shape `nx` x `nx`, - * row-major) + * row-major) evaluated at `t_last`. */ std::vector J; @@ -456,6 +456,9 @@ class ReturnData : public ModelDimensions { /** log messages */ std::vector messages; + /** The final internal time of the solver. */ + realtype t_last{std::numeric_limits::quiet_NaN()}; + protected: /** offset for sigma_residuals */ realtype sigma_offset; @@ -576,7 +579,7 @@ class ReturnData : public ModelDimensions { if (!this->J.empty()) { SUNMatrixWrapper J(nx_solver, nx_solver); - model.fJ(t_, 0.0, x_solver_, dx_solver_, xdot, J.get()); + model.fJ(t_, 0.0, x_solver_, dx_solver_, xdot, J); // CVODES uses colmajor, so we need to transform to rowmajor for (int ix = 0; ix < model.nx_solver; ix++) for (int jx = 0; jx < model.nx_solver; jx++) diff --git a/include/amici/serialization.h b/include/amici/serialization.h index 6cab4f0353..e4b1e3afe5 100644 --- a/include/amici/serialization.h +++ b/include/amici/serialization.h @@ -5,6 +5,7 @@ #include "amici/rdata.h" #include "amici/solver.h" #include "amici/solver_cvodes.h" +#include "amici/vector.h" #include @@ -85,6 +86,10 @@ void serialize(Archive& ar, amici::Solver& s, unsigned int const /*version*/) { ar & s.check_sensi_steadystate_conv_; ar & s.rdata_mode_; ar & s.maxtime_; + ar & s.max_conv_fails_; + ar & s.max_nonlin_iters_; + ar & s.constraints_; + ar & s.max_step_size_; } /** @@ -275,6 +280,25 @@ void serialize( ar & m.ubw; ar & m.lbw; } + +/** + * @brief Serialize AmiVector to a boost archive + * @param ar archive + * @param v AmiVector + */ +template +void serialize( + Archive& ar, amici::AmiVector& v, unsigned int const /*version*/ +) { + if (Archive::is_loading::value) { + std::vector tmp; + ar & tmp; + v = amici::AmiVector(tmp); + } else { + auto tmp = v.getVector(); + ar & tmp; + } +} #endif } // namespace serialization } // namespace boost diff --git a/include/amici/solver.h b/include/amici/solver.h index 92ae4c47fb..661a9fac25 100644 --- a/include/amici/solver.h +++ b/include/amici/solver.h @@ -936,6 +936,64 @@ class Solver { check_sensi_steadystate_conv_ = flag; } + /** + * @brief Set the maximum number of nonlinear solver iterations permitted + * per step. + * @param max_nonlin_iters maximum number of nonlinear solver iterations + */ + void setMaxNonlinIters(int max_nonlin_iters); + + /** + * @brief Get the maximum number of nonlinear solver iterations permitted + * per step. + * @return maximum number of nonlinear solver iterations + */ + int getMaxNonlinIters() const; + + /** + * @brief Set the maximum number of nonlinear solver convergence failures + * permitted per step. + * @param max_conv_fails maximum number of nonlinear solver convergence + */ + void setMaxConvFails(int max_conv_fails); + + /** + * @brief Get the maximum number of nonlinear solver convergence failures + * permitted per step. + * @return maximum number of nonlinear solver convergence + */ + int getMaxConvFails() const; + + /** + * @brief Set constraints on the model state. + * + * See + * https://sundials.readthedocs.io/en/latest/cvode/Usage/index.html#c.CVodeSetConstraints. + * + * @param constraints + */ + void setConstraints(std::vector const& constraints); + + /** + * @brief Get constraints on the model state. + * @return constraints + */ + std::vector getConstraints() const { + return constraints_.getVector(); + } + + /** + * @brief Set the maximum step size + * @param max_step_size maximum step size. `0.0` means no limit. + */ + void setMaxStepSize(realtype max_step_size); + + /** + * @brief Get the maximum step size + * @return maximum step size + */ + realtype getMaxStepSize() const; + /** * @brief Serialize Solver (see boost::serialization::serialize) * @param ar Archive to serialize to @@ -1090,7 +1148,7 @@ class Solver { virtual void rootInit(int ne) const = 0; /** - * @brief Initalize non-linear solver for sensitivities + * @brief Initialize non-linear solver for sensitivities * @param model Model instance */ void initializeNonLinearSolverSens(Model const* model) const; @@ -1608,6 +1666,11 @@ class Solver { */ void applySensitivityTolerances() const; + /** + * @brief Apply the constraints to the solver. + */ + virtual void apply_constraints() const; + /** pointer to solver memory block */ mutable std::unique_ptr solver_memory_; @@ -1712,6 +1775,23 @@ class Solver { SensitivityMethod const sensi_meth, bool preequilibration ) const; + /** + * @brief Apply the maximum number of nonlinear solver iterations permitted + * per step. + */ + virtual void apply_max_nonlin_iters() const = 0; + + /** + * @brief Apply the maximum number of nonlinear solver convergence failures + * permitted per step. + */ + virtual void apply_max_conv_fails() const = 0; + + /** + * @brief Apply the allowed maximum stepsize to the solver. + */ + virtual void apply_max_step_size() const = 0; + /** state (dimension: nx_solver) */ mutable AmiVector x_{0}; @@ -1752,6 +1832,9 @@ class Solver { /** flag indicating whether sensInit1 was called */ mutable bool sens_initialized_{false}; + /** Vector of constraints on the solution */ + mutable AmiVector constraints_; + private: /** * @brief applies total number of steps for next solver call @@ -1844,6 +1927,16 @@ class Solver { */ bool check_sensi_steadystate_conv_{true}; + /** Maximum number of nonlinear solver iterations permitted per step */ + int max_nonlin_iters_{3}; + + /** Maximum number of nonlinear solver convergence failures permitted per + * step */ + int max_conv_fails_{10}; + + /** Maximum allowed step size */ + realtype max_step_size_{0.0}; + /** CPU time, forward solve */ mutable realtype cpu_time_{0.0}; diff --git a/include/amici/solver_cvodes.h b/include/amici/solver_cvodes.h index f98fb34c1a..8d04b22a34 100644 --- a/include/amici/solver_cvodes.h +++ b/include/amici/solver_cvodes.h @@ -249,6 +249,14 @@ class CVodeSolver : public Solver { void setJacTimesVecFnB(int which) const override; void setSparseJacFn_ss() const override; + + void apply_max_nonlin_iters() const override; + + void apply_max_conv_fails() const override; + + void apply_constraints() const override; + + void apply_max_step_size() const override; }; } // namespace amici diff --git a/include/amici/solver_idas.h b/include/amici/solver_idas.h index b985a090af..c8efc69c0c 100644 --- a/include/amici/solver_idas.h +++ b/include/amici/solver_idas.h @@ -229,6 +229,14 @@ class IDASolver : public Solver { void setJacTimesVecFnB(int which) const override; void setSparseJacFn_ss() const override; + + void apply_max_nonlin_iters() const override; + + void apply_max_conv_fails() const override; + + void apply_constraints() const override; + + void apply_max_step_size() const override; }; } // namespace amici diff --git a/include/amici/sundials_matrix_wrapper.h b/include/amici/sundials_matrix_wrapper.h index ee2516f78d..0bb9b9215f 100644 --- a/include/amici/sundials_matrix_wrapper.h +++ b/include/amici/sundials_matrix_wrapper.h @@ -72,6 +72,11 @@ class SUNMatrixWrapper { ~SUNMatrixWrapper(); + /** + * @brief Conversion function. + */ + operator SUNMatrix() { return get(); }; + /** * @brief Copy constructor * @param other diff --git a/include/amici/vector.h b/include/amici/vector.h index b1b496c26e..486ea77682 100644 --- a/include/amici/vector.h +++ b/include/amici/vector.h @@ -10,6 +10,18 @@ #include +namespace amici { +class AmiVector; +} + +// for serialization friend +namespace boost { +namespace serialization { +template +void serialize(Archive& ar, amici::AmiVector& s, unsigned int version); +} +} // namespace boost + namespace amici { /** Since const N_Vector is not what we want */ @@ -54,7 +66,7 @@ class AmiVector { * @brief constructor from gsl::span, * @param rvec vector from which the data will be copied */ - explicit AmiVector(gsl::span rvec) + explicit AmiVector(gsl::span rvec) : AmiVector(std::vector(rvec.begin(), rvec.end())) {} /** @@ -213,6 +225,17 @@ class AmiVector { */ void abs() { N_VAbs(getNVector(), getNVector()); }; + /** + * @brief Serialize AmiVector (see boost::serialization::serialize) + * @param ar Archive to serialize to + * @param s Data to serialize + * @param version Version number + */ + template + friend void boost::serialization::serialize( + Archive& ar, AmiVector& s, unsigned int version + ); + private: /** main data storage */ std::vector vec_; @@ -405,6 +428,16 @@ namespace gsl { inline span make_span(N_Vector nv) { return span(N_VGetArrayPointer(nv), N_VGetLength_Serial(nv)); } + +/** + * @brief Create span from N_Vector + * @param nv + * + */ +inline span make_span(amici::AmiVector const& av) { + return make_span(av.getVector()); +} + } // namespace gsl #endif /* AMICI_VECTOR_H */ diff --git a/matlab/@amifun/getArgs.m b/matlab/@amifun/getArgs.m index afb50802e0..a34c658ee5 100644 --- a/matlab/@amifun/getArgs.m +++ b/matlab/@amifun/getArgs.m @@ -108,11 +108,11 @@ case 'dJrzdsigma' this.argstr = '(double *dJrzdsigma, const int iz, const realtype *p, const realtype *k, const double *rz, const double *sigmaz)'; case 'w' - this.argstr = '(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl)'; + this.argstr = '(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static)'; case 'dwdp' - this.argstr = '(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl)'; + this.argstr = '(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static)'; case 'dwdx' - this.argstr = '(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl)'; + this.argstr = '(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static)'; case 'M' this.argstr = '(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k)'; otherwise diff --git a/matlab/@amimodel/generateC.m b/matlab/@amimodel/generateC.m index 869f386baf..2f09831b24 100644 --- a/matlab/@amimodel/generateC.m +++ b/matlab/@amimodel/generateC.m @@ -209,7 +209,7 @@ function generateC(this) end fprintf(fid,'};\n\n'); fprintf(fid,['} // namespace model_' this.modelname '\n\n']); -fprintf(fid,'} // namespace amici \n\n'); +fprintf(fid,'} // namespace amici\n\n'); fprintf(fid,['#endif /* _amici_' this.modelname '_h */\n']); fclose(fid); @@ -253,6 +253,7 @@ function generateC(this) argstr = strrep(argstr,'realtype',''); argstr = strrep(argstr,'int',''); +argstr = strrep(argstr,'bool',''); argstr = strrep(argstr,'const',''); argstr = strrep(argstr,'double',''); argstr = strrep(argstr,'SUNMatrixContent_Sparse',''); diff --git a/models/model_calvetti/CMakeLists.txt b/models/model_calvetti/CMakeLists.txt index 2d1347b553..30262f7de3 100644 --- a/models/model_calvetti/CMakeLists.txt +++ b/models/model_calvetti/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_calvetti) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -73,18 +96,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_calvetti/dwdx.cpp b/models/model_calvetti/dwdx.cpp index 9066d0e953..f185abd31f 100644 --- a/models/model_calvetti/dwdx.cpp +++ b/models/model_calvetti/dwdx.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_calvetti{ -void dwdx_model_calvetti(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) { +void dwdx_model_calvetti(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) { dwdx[0] = 1.0/(x[0]*x[0]*x[0])*-2.0; dwdx[1] = k[1]*w[15]*dwdx[0]; dwdx[2] = dwdx[1]; diff --git a/models/model_calvetti/main.cpp b/models/model_calvetti/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_calvetti/main.cpp +++ b/models/model_calvetti/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_calvetti/model_calvetti.h b/models/model_calvetti/model_calvetti.h index c8144bdf5e..c189ae8d74 100644 --- a/models/model_calvetti/model_calvetti.h +++ b/models/model_calvetti/model_calvetti.h @@ -1,6 +1,6 @@ #ifndef _amici_model_calvetti_h #define _amici_model_calvetti_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -19,11 +19,11 @@ extern void Jy_model_calvetti(double *nllh, const int iy, const realtype *p, con extern void M_model_calvetti(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k); extern void dJydsigma_model_calvetti(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dJydy_model_calvetti(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); -extern void dwdx_model_calvetti(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl); +extern void dwdx_model_calvetti(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static); extern void dydx_model_calvetti(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void root_model_calvetti(realtype *root, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx); extern void sigmay_model_calvetti(double *sigmay, const realtype t, const realtype *p, const realtype *k, const realtype *y); -extern void w_model_calvetti(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl); +extern void w_model_calvetti(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static); extern void x0_model_calvetti(realtype *x0, const realtype t, const realtype *p, const realtype *k); extern void xdot_model_calvetti(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w); extern void y_model_calvetti(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); @@ -72,7 +72,7 @@ class Model_model_calvetti : public amici::Model_DAE { amici::Model* clone() const override { return new Model_model_calvetti(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { JSparse_model_calvetti(JSparse, t, x, p, k, h, cj, dx, w, dwdx); @@ -136,11 +136,11 @@ class Model_model_calvetti : public amici::Model_DAE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { - dwdx_model_calvetti(dwdx, t, x, p, k, h, w, tcl, spl); + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { + dwdx_model_calvetti(dwdx, t, x, p, k, h, w, tcl, spl, include_static); } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) override { @@ -185,8 +185,8 @@ class Model_model_calvetti : public amici::Model_DAE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { - w_model_calvetti(w, t, x, p, k, h, tcl, spl); + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { + w_model_calvetti(w, t, x, p, k, h, tcl, spl, include_static); } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_calvetti/w.cpp b/models/model_calvetti/w.cpp index fb1aaef8e2..38773562d3 100644 --- a/models/model_calvetti/w.cpp +++ b/models/model_calvetti/w.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_calvetti{ -void w_model_calvetti(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) { +void w_model_calvetti(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) { w[0] = 1.0/k[0]; w[1] = k[2]*k[2]; w[2] = 1.0/(x[1]*x[1]); diff --git a/models/model_dirac/CMakeLists.txt b/models/model_dirac/CMakeLists.txt index 64f02dca9b..d96169b04a 100644 --- a/models/model_dirac/CMakeLists.txt +++ b/models/model_dirac/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_dirac) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -73,18 +96,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_dirac/main.cpp b/models/model_dirac/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_dirac/main.cpp +++ b/models/model_dirac/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_dirac/model_dirac.h b/models/model_dirac/model_dirac.h index cfd943e456..0425320765 100644 --- a/models/model_dirac/model_dirac.h +++ b/models/model_dirac/model_dirac.h @@ -1,6 +1,6 @@ #ifndef _amici_model_dirac_h #define _amici_model_dirac_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -72,7 +72,7 @@ class Model_model_dirac : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_dirac(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_dirac(JSparse, t, x, p, k, h, w, dwdx); @@ -134,10 +134,10 @@ class Model_model_dirac : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -184,7 +184,7 @@ class Model_model_dirac : public amici::Model_ODE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_events/CMakeLists.txt b/models/model_events/CMakeLists.txt index 277573426d..53e3a335b8 100644 --- a/models/model_events/CMakeLists.txt +++ b/models/model_events/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_events) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -87,18 +110,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_events/main.cpp b/models/model_events/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_events/main.cpp +++ b/models/model_events/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_events/model_events.h b/models/model_events/model_events.h index ad6c976419..bc2b1b6157 100644 --- a/models/model_events/model_events.h +++ b/models/model_events/model_events.h @@ -1,6 +1,6 @@ #ifndef _amici_model_events_h #define _amici_model_events_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -86,7 +86,7 @@ class Model_model_events : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_events(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_events(JSparse, t, x, p, k, h, w, dwdx); @@ -154,10 +154,10 @@ class Model_model_events : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -210,7 +210,7 @@ class Model_model_events : public amici::Model_ODE { sz_model_events(sz, ie, t, x, p, k, h, sx, ip); } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_jakstat_adjoint/CMakeLists.txt b/models/model_jakstat_adjoint/CMakeLists.txt index 1670a68ee9..75cc527694 100644 --- a/models/model_jakstat_adjoint/CMakeLists.txt +++ b/models/model_jakstat_adjoint/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_jakstat_adjoint) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -76,18 +99,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_jakstat_adjoint/dwdp.cpp b/models/model_jakstat_adjoint/dwdp.cpp index 3213a319d9..092466e87b 100644 --- a/models/model_jakstat_adjoint/dwdp.cpp +++ b/models/model_jakstat_adjoint/dwdp.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_jakstat_adjoint{ -void dwdp_model_jakstat_adjoint(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) { +void dwdp_model_jakstat_adjoint(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) { dwdp[0] = amici::Dspline_pos(4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); dwdp[1] = amici::Dspline_pos(6,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); dwdp[2] = amici::Dspline_pos(8,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); diff --git a/models/model_jakstat_adjoint/dwdx.cpp b/models/model_jakstat_adjoint/dwdx.cpp index 70a26b8a2c..354b72f246 100644 --- a/models/model_jakstat_adjoint/dwdx.cpp +++ b/models/model_jakstat_adjoint/dwdx.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_jakstat_adjoint{ -void dwdx_model_jakstat_adjoint(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) { +void dwdx_model_jakstat_adjoint(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) { dwdx[0] = x[1]*2.0; } diff --git a/models/model_jakstat_adjoint/main.cpp b/models/model_jakstat_adjoint/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_jakstat_adjoint/main.cpp +++ b/models/model_jakstat_adjoint/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_jakstat_adjoint/model_jakstat_adjoint.h b/models/model_jakstat_adjoint/model_jakstat_adjoint.h index 6d7601947a..aad482c26c 100644 --- a/models/model_jakstat_adjoint/model_jakstat_adjoint.h +++ b/models/model_jakstat_adjoint/model_jakstat_adjoint.h @@ -1,6 +1,6 @@ #ifndef _amici_model_jakstat_adjoint_h #define _amici_model_jakstat_adjoint_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -19,14 +19,14 @@ extern void Jy_model_jakstat_adjoint(double *nllh, const int iy, const realtype extern void dJydsigma_model_jakstat_adjoint(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dJydy_model_jakstat_adjoint(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dsigmaydp_model_jakstat_adjoint(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const realtype *y, const int ip); -extern void dwdp_model_jakstat_adjoint(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl); -extern void dwdx_model_jakstat_adjoint(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl); +extern void dwdp_model_jakstat_adjoint(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static); +extern void dwdx_model_jakstat_adjoint(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static); extern void dxdotdp_model_jakstat_adjoint(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp); extern void dydp_model_jakstat_adjoint(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp); extern void dydx_model_jakstat_adjoint(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void sigmay_model_jakstat_adjoint(double *sigmay, const realtype t, const realtype *p, const realtype *k, const realtype *y); extern void sx0_model_jakstat_adjoint(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip); -extern void w_model_jakstat_adjoint(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl); +extern void w_model_jakstat_adjoint(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static); extern void x0_model_jakstat_adjoint(realtype *x0, const realtype t, const realtype *p, const realtype *k); extern void xdot_model_jakstat_adjoint(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); extern void y_model_jakstat_adjoint(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); @@ -75,7 +75,7 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_jakstat_adjoint(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_jakstat_adjoint(JSparse, t, x, p, k, h, w, dwdx); @@ -136,12 +136,12 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { - dwdp_model_jakstat_adjoint(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl); + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { + dwdp_model_jakstat_adjoint(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl, include_static); } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { - dwdx_model_jakstat_adjoint(dwdx, t, x, p, k, h, w, tcl, spl); + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { + dwdx_model_jakstat_adjoint(dwdx, t, x, p, k, h, w, tcl, spl, include_static); } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -188,8 +188,8 @@ class Model_model_jakstat_adjoint : public amici::Model_ODE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { - w_model_jakstat_adjoint(w, t, x, p, k, h, tcl, spl); + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { + w_model_jakstat_adjoint(w, t, x, p, k, h, tcl, spl, include_static); } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_jakstat_adjoint/w.cpp b/models/model_jakstat_adjoint/w.cpp index 06238238ca..430b96de3a 100644 --- a/models/model_jakstat_adjoint/w.cpp +++ b/models/model_jakstat_adjoint/w.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_jakstat_adjoint{ -void w_model_jakstat_adjoint(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) { +void w_model_jakstat_adjoint(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) { w[0] = amici::spline_pos(t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); w[1] = x[1]*x[1]; } diff --git a/models/model_jakstat_adjoint_o2/CMakeLists.txt b/models/model_jakstat_adjoint_o2/CMakeLists.txt index b4b9cc03ca..4b2b35e223 100644 --- a/models/model_jakstat_adjoint_o2/CMakeLists.txt +++ b/models/model_jakstat_adjoint_o2/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_jakstat_adjoint_o2) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -76,18 +99,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_jakstat_adjoint_o2/dwdp.cpp b/models/model_jakstat_adjoint_o2/dwdp.cpp index b3e591fcba..a936666e39 100644 --- a/models/model_jakstat_adjoint_o2/dwdp.cpp +++ b/models/model_jakstat_adjoint_o2/dwdp.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_jakstat_adjoint_o2{ -void dwdp_model_jakstat_adjoint_o2(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) { +void dwdp_model_jakstat_adjoint_o2(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) { dwdp[0] = amici::Dspline_pos(4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); dwdp[1] = amici::DDspline_pos(4,4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); dwdp[2] = amici::DDspline_pos(6,4,t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); diff --git a/models/model_jakstat_adjoint_o2/dwdx.cpp b/models/model_jakstat_adjoint_o2/dwdx.cpp index 3226a7535b..81ad6343f1 100644 --- a/models/model_jakstat_adjoint_o2/dwdx.cpp +++ b/models/model_jakstat_adjoint_o2/dwdx.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_jakstat_adjoint_o2{ -void dwdx_model_jakstat_adjoint_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) { +void dwdx_model_jakstat_adjoint_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) { dwdx[0] = x[1]*2.0; dwdx[1] = 2.0; } diff --git a/models/model_jakstat_adjoint_o2/main.cpp b/models/model_jakstat_adjoint_o2/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_jakstat_adjoint_o2/main.cpp +++ b/models/model_jakstat_adjoint_o2/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h b/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h index bfac0b3267..e44c31b8d5 100644 --- a/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h +++ b/models/model_jakstat_adjoint_o2/model_jakstat_adjoint_o2.h @@ -1,6 +1,6 @@ #ifndef _amici_model_jakstat_adjoint_o2_h #define _amici_model_jakstat_adjoint_o2_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -19,14 +19,14 @@ extern void Jy_model_jakstat_adjoint_o2(double *nllh, const int iy, const realty extern void dJydsigma_model_jakstat_adjoint_o2(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dJydy_model_jakstat_adjoint_o2(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dsigmaydp_model_jakstat_adjoint_o2(double *dsigmaydp, const realtype t, const realtype *p, const realtype *k, const realtype *y, const int ip); -extern void dwdp_model_jakstat_adjoint_o2(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl); -extern void dwdx_model_jakstat_adjoint_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl); +extern void dwdp_model_jakstat_adjoint_o2(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static); +extern void dwdx_model_jakstat_adjoint_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static); extern void dxdotdp_model_jakstat_adjoint_o2(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp); extern void dydp_model_jakstat_adjoint_o2(double *dydp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp); extern void dydx_model_jakstat_adjoint_o2(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void sigmay_model_jakstat_adjoint_o2(double *sigmay, const realtype t, const realtype *p, const realtype *k, const realtype *y); extern void sx0_model_jakstat_adjoint_o2(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip); -extern void w_model_jakstat_adjoint_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl); +extern void w_model_jakstat_adjoint_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static); extern void x0_model_jakstat_adjoint_o2(realtype *x0, const realtype t, const realtype *p, const realtype *k); extern void xdot_model_jakstat_adjoint_o2(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); extern void y_model_jakstat_adjoint_o2(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); @@ -75,7 +75,7 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_jakstat_adjoint_o2(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_jakstat_adjoint_o2(JSparse, t, x, p, k, h, w, dwdx); @@ -136,12 +136,12 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { - dwdp_model_jakstat_adjoint_o2(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl); + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { + dwdp_model_jakstat_adjoint_o2(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl, include_static); } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { - dwdx_model_jakstat_adjoint_o2(dwdx, t, x, p, k, h, w, tcl, spl); + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { + dwdx_model_jakstat_adjoint_o2(dwdx, t, x, p, k, h, w, tcl, spl, include_static); } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -188,8 +188,8 @@ class Model_model_jakstat_adjoint_o2 : public amici::Model_ODE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { - w_model_jakstat_adjoint_o2(w, t, x, p, k, h, tcl, spl); + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { + w_model_jakstat_adjoint_o2(w, t, x, p, k, h, tcl, spl, include_static); } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_jakstat_adjoint_o2/w.cpp b/models/model_jakstat_adjoint_o2/w.cpp index 766860cfa0..827202e139 100644 --- a/models/model_jakstat_adjoint_o2/w.cpp +++ b/models/model_jakstat_adjoint_o2/w.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_jakstat_adjoint_o2{ -void w_model_jakstat_adjoint_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) { +void w_model_jakstat_adjoint_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) { w[0] = amici::spline_pos(t,5,0.0,p[5],5.0,p[6],1.0E1,p[7],2.0E1,p[8],6.0E1,p[9],0.0,0.0); w[1] = x[1]*x[1]; w[2] = 1.0/k[0]; diff --git a/models/model_nested_events/CMakeLists.txt b/models/model_nested_events/CMakeLists.txt index 1a67d0a2c2..c609531e1d 100644 --- a/models/model_nested_events/CMakeLists.txt +++ b/models/model_nested_events/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_nested_events) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -76,18 +99,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_nested_events/main.cpp b/models/model_nested_events/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_nested_events/main.cpp +++ b/models/model_nested_events/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_nested_events/model_nested_events.h b/models/model_nested_events/model_nested_events.h index 0ed43eedbd..5cad2049a9 100644 --- a/models/model_nested_events/model_nested_events.h +++ b/models/model_nested_events/model_nested_events.h @@ -1,6 +1,6 @@ #ifndef _amici_model_nested_events_h #define _amici_model_nested_events_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -75,7 +75,7 @@ class Model_model_nested_events : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_nested_events(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_nested_events(JSparse, t, x, p, k, h, w, dwdx); @@ -138,10 +138,10 @@ class Model_model_nested_events : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -189,7 +189,7 @@ class Model_model_nested_events : public amici::Model_ODE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_neuron/CMakeLists.txt b/models/model_neuron/CMakeLists.txt index 3234271696..4b580c036a 100644 --- a/models/model_neuron/CMakeLists.txt +++ b/models/model_neuron/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_neuron) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -90,18 +113,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_neuron/main.cpp b/models/model_neuron/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_neuron/main.cpp +++ b/models/model_neuron/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_neuron/model_neuron.h b/models/model_neuron/model_neuron.h index e744f57f65..387a3cadbd 100644 --- a/models/model_neuron/model_neuron.h +++ b/models/model_neuron/model_neuron.h @@ -1,6 +1,6 @@ #ifndef _amici_model_neuron_h #define _amici_model_neuron_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -89,7 +89,7 @@ class Model_model_neuron : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_neuron(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_neuron(JSparse, t, x, p, k, h, w, dwdx); @@ -160,10 +160,10 @@ class Model_model_neuron : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -216,7 +216,7 @@ class Model_model_neuron : public amici::Model_ODE { sz_model_neuron(sz, ie, t, x, p, k, h, sx, ip); } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_neuron_o2/CMakeLists.txt b/models/model_neuron_o2/CMakeLists.txt index 42f5da90af..161fd4e9ce 100644 --- a/models/model_neuron_o2/CMakeLists.txt +++ b/models/model_neuron_o2/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_neuron_o2) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -92,18 +115,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_neuron_o2/dwdx.cpp b/models/model_neuron_o2/dwdx.cpp index a746d7549a..3a2036c023 100644 --- a/models/model_neuron_o2/dwdx.cpp +++ b/models/model_neuron_o2/dwdx.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_neuron_o2{ -void dwdx_model_neuron_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) { +void dwdx_model_neuron_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) { dwdx[0] = 2.0/2.5E1; dwdx[1] = dwdx[0]; } diff --git a/models/model_neuron_o2/main.cpp b/models/model_neuron_o2/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_neuron_o2/main.cpp +++ b/models/model_neuron_o2/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_neuron_o2/model_neuron_o2.h b/models/model_neuron_o2/model_neuron_o2.h index a108e6284b..4ae613ee84 100644 --- a/models/model_neuron_o2/model_neuron_o2.h +++ b/models/model_neuron_o2/model_neuron_o2.h @@ -1,6 +1,6 @@ #ifndef _amici_model_neuron_o2_h #define _amici_model_neuron_o2_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -29,7 +29,7 @@ extern void deltasx_model_neuron_o2(double *deltasx, const realtype t, const rea extern void deltax_model_neuron_o2(double *deltax, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old); extern void deltaxB_model_neuron_o2(double *deltaxB, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ie, const realtype *xdot, const realtype *xdot_old, const realtype *xB); extern void drzdx_model_neuron_o2(double *drzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h); -extern void dwdx_model_neuron_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl); +extern void dwdx_model_neuron_o2(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static); extern void dxdotdp_model_neuron_o2(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp); extern void dydx_model_neuron_o2(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void dzdx_model_neuron_o2(double *dzdx, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h); @@ -41,7 +41,7 @@ extern void srz_model_neuron_o2(double *srz, const int ie, const realtype t, con extern void stau_model_neuron_o2(double *stau, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *sx, const int ip, const int ie); extern void sx0_model_neuron_o2(realtype *sx0, const realtype t,const realtype *x0, const realtype *p, const realtype *k, const int ip); extern void sz_model_neuron_o2(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip); -extern void w_model_neuron_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl); +extern void w_model_neuron_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static); extern void x0_model_neuron_o2(realtype *x0, const realtype t, const realtype *p, const realtype *k); extern void xdot_model_neuron_o2(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); extern void y_model_neuron_o2(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); @@ -91,7 +91,7 @@ class Model_model_neuron_o2 : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_neuron_o2(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_neuron_o2(JSparse, t, x, p, k, h, w, dwdx); @@ -162,11 +162,11 @@ class Model_model_neuron_o2 : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { - dwdx_model_neuron_o2(dwdx, t, x, p, k, h, w, tcl, spl); + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { + dwdx_model_neuron_o2(dwdx, t, x, p, k, h, w, tcl, spl, include_static); } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -219,8 +219,8 @@ class Model_model_neuron_o2 : public amici::Model_ODE { sz_model_neuron_o2(sz, ie, t, x, p, k, h, sx, ip); } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { - w_model_neuron_o2(w, t, x, p, k, h, tcl, spl); + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { + w_model_neuron_o2(w, t, x, p, k, h, tcl, spl, include_static); } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_neuron_o2/w.cpp b/models/model_neuron_o2/w.cpp index cbd2f0a25f..fca88b9e36 100644 --- a/models/model_neuron_o2/w.cpp +++ b/models/model_neuron_o2/w.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_neuron_o2{ -void w_model_neuron_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) { +void w_model_neuron_o2(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) { w[0] = x[0]*(2.0/2.5E1); w[1] = w[0]+5.0; } diff --git a/models/model_robertson/CMakeLists.txt b/models/model_robertson/CMakeLists.txt index 9b27e3daaf..1a4c57353a 100644 --- a/models/model_robertson/CMakeLists.txt +++ b/models/model_robertson/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_robertson) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -74,18 +97,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_robertson/dwdp.cpp b/models/model_robertson/dwdp.cpp index 831c448cad..5911b99078 100644 --- a/models/model_robertson/dwdp.cpp +++ b/models/model_robertson/dwdp.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_robertson{ -void dwdp_model_robertson(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) { +void dwdp_model_robertson(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) { dwdp[0] = x[1]*x[2]; } diff --git a/models/model_robertson/dwdx.cpp b/models/model_robertson/dwdx.cpp index 5c300a54ec..1e75c29246 100644 --- a/models/model_robertson/dwdx.cpp +++ b/models/model_robertson/dwdx.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_robertson{ -void dwdx_model_robertson(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) { +void dwdx_model_robertson(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) { dwdx[0] = p[1]*x[2]; dwdx[1] = p[1]*x[1]; } diff --git a/models/model_robertson/main.cpp b/models/model_robertson/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_robertson/main.cpp +++ b/models/model_robertson/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_robertson/model_robertson.h b/models/model_robertson/model_robertson.h index 816dd2db32..4f25f4d9bd 100644 --- a/models/model_robertson/model_robertson.h +++ b/models/model_robertson/model_robertson.h @@ -1,6 +1,6 @@ #ifndef _amici_model_robertson_h #define _amici_model_robertson_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -19,12 +19,12 @@ extern void Jy_model_robertson(double *nllh, const int iy, const realtype *p, co extern void M_model_robertson(realtype *M, const realtype t, const realtype *x, const realtype *p, const realtype *k); extern void dJydsigma_model_robertson(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dJydy_model_robertson(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); -extern void dwdp_model_robertson(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl); -extern void dwdx_model_robertson(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl); +extern void dwdp_model_robertson(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static); +extern void dwdx_model_robertson(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static); extern void dxdotdp_model_robertson(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp); extern void dydx_model_robertson(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void sigmay_model_robertson(double *sigmay, const realtype t, const realtype *p, const realtype *k, const realtype *y); -extern void w_model_robertson(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl); +extern void w_model_robertson(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static); extern void x0_model_robertson(realtype *x0, const realtype t, const realtype *p, const realtype *k); extern void xdot_model_robertson(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *dx, const realtype *w); extern void y_model_robertson(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); @@ -73,7 +73,7 @@ class Model_model_robertson : public amici::Model_DAE { amici::Model* clone() const override { return new Model_model_robertson(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype cj, const realtype *dx, const realtype *w, const realtype *dwdx) override { JSparse_model_robertson(JSparse, t, x, p, k, h, cj, dx, w, dwdx); @@ -137,12 +137,12 @@ class Model_model_robertson : public amici::Model_DAE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { - dwdp_model_robertson(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl); + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { + dwdp_model_robertson(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl, include_static); } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { - dwdx_model_robertson(dwdx, t, x, p, k, h, w, tcl, spl); + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { + dwdx_model_robertson(dwdx, t, x, p, k, h, w, tcl, spl, include_static); } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *dx, const realtype *w, const realtype *dwdp) override { @@ -187,8 +187,8 @@ class Model_model_robertson : public amici::Model_DAE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { - w_model_robertson(w, t, x, p, k, h, tcl, spl); + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { + w_model_robertson(w, t, x, p, k, h, tcl, spl, include_static); } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_robertson/w.cpp b/models/model_robertson/w.cpp index 6905b49c0e..ae4145ba6b 100644 --- a/models/model_robertson/w.cpp +++ b/models/model_robertson/w.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_robertson{ -void w_model_robertson(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) { +void w_model_robertson(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) { w[0] = p[1]*x[1]*x[2]; } diff --git a/models/model_steadystate/CMakeLists.txt b/models/model_steadystate/CMakeLists.txt index 9b699da5b0..3d0dacaf83 100644 --- a/models/model_steadystate/CMakeLists.txt +++ b/models/model_steadystate/CMakeLists.txt @@ -1,5 +1,11 @@ # Build AMICI model cmake_minimum_required(VERSION 3.15) +cmake_policy(VERSION 3.15...3.27) + +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) project(model_steadystate) @@ -14,7 +20,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() foreach(flag ${MY_CXX_FLAGS}) unset(CUR_FLAG_SUPPORTED CACHE) - check_cxx_compiler_flag(-Werror ${flag} CUR_FLAG_SUPPORTED) + check_cxx_compiler_flag(${flag} CUR_FLAG_SUPPORTED) if(${CUR_FLAG_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${flag}") endif() @@ -33,6 +39,23 @@ find_package(Amici REQUIRED HINTS ${CMAKE_CURRENT_LIST_DIR}/../../build) message(STATUS "Found AMICI ${Amici_DIR}") +# Debug build? +if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") + add_compile_options(-UNDEBUG) + if(MSVC) + add_compile_options(-DEBUG) + else() + add_compile_options(-O0 -g) + endif() + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# coverage options +if($ENV{ENABLE_GCOV_COVERAGE}) + string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") + string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") +endif() + set(MODEL_DIR ${CMAKE_CURRENT_LIST_DIR}) set(SRC_LIST_LIB ${MODEL_DIR}/JSparse.cpp @@ -73,18 +96,6 @@ if(NOT "${AMICI_PYTHON_BUILD_EXT_ONLY}") target_link_libraries(simulate_${PROJECT_NAME} ${PROJECT_NAME}) endif() -# Debug build? -if("$ENV{ENABLE_AMICI_DEBUGGING}" OR "$ENV{ENABLE_GCOV_COVERAGE}") - add_compile_options(-UNDEBUG -O0 -g) - set(CMAKE_BUILD_TYPE "Debug") -endif() - -# coverage options -if($ENV{ENABLE_GCOV_COVERAGE}) - string(APPEND CMAKE_CXX_FLAGS_DEBUG " --coverage") - string(APPEND CMAKE_EXE_LINKER_FLAGS_DEBUG " --coverage") -endif() - # SWIG option(ENABLE_SWIG "Build swig/python library?" ON) if(ENABLE_SWIG) diff --git a/models/model_steadystate/dwdp.cpp b/models/model_steadystate/dwdp.cpp index 154db2a72f..d31310d341 100644 --- a/models/model_steadystate/dwdp.cpp +++ b/models/model_steadystate/dwdp.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_steadystate{ -void dwdp_model_steadystate(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) { +void dwdp_model_steadystate(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) { dwdp[0] = x[2]; } diff --git a/models/model_steadystate/dwdx.cpp b/models/model_steadystate/dwdx.cpp index d447f2140d..dcd5f5e49e 100644 --- a/models/model_steadystate/dwdx.cpp +++ b/models/model_steadystate/dwdx.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_steadystate{ -void dwdx_model_steadystate(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) { +void dwdx_model_steadystate(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) { dwdx[0] = x[0]*2.0; dwdx[1] = p[3]; } diff --git a/models/model_steadystate/main.cpp b/models/model_steadystate/main.cpp index 00a5e6b448..ecdff85a46 100644 --- a/models/model_steadystate/main.cpp +++ b/models/model_steadystate/main.cpp @@ -1,14 +1,13 @@ #include -#include /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector& v) -{ +template +std::ostream& operator<<(std::ostream& os, std::vector const& v) { os << "["; - for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector::const_iterator ii = v.begin(); ii != v.end(); + ++ii) { os << " " << *ii; } os << "]"; @@ -21,9 +20,9 @@ std::ostream& operator << (std::ostream& os, const std::vector& v) */ int main() { - std::cout<<"********************************"<getObservableIds(); - std::cout<<"Simulated observables for timepoints "<ts<<"\n\n"; - for(int i_observable = 0; i_observable < rdata->ny; ++i_observable) { - std::cout<nt; ++i_time) { + std::cout << "Simulated observables for timepoints " << rdata->ts << "\n\n"; + for (int i_observable = 0; i_observable < rdata->ny; ++i_observable) { + std::cout << observable_ids[i_observable] << ":\n\t"; + for (int i_time = 0; i_time < rdata->nt; ++i_time) { // rdata->y is a flat 2D array in row-major ordering - std::cout<y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<setSensitivityOrder(amici::SensitivityOrder::first); @@ -78,18 +76,17 @@ int main() { auto state_ids = model->getStateIds(); auto parameter_ids = model->getParameterIds(); - std::cout<<"State sensitivities for timepoint " - <ts[i_time] - <nx; ++i_state) { - std::cout<<"\td("<plist(i_nplist)]<<") = "; + std::cout << "State sensitivities for timepoint " << rdata->ts[i_time] + << std::endl; // nt x nplist x nx + for (int i_state = 0; i_state < rdata->nx; ++i_state) { + std::cout << "\td(" << state_ids[i_state] << ")/d(" + << parameter_ids[model->plist(i_nplist)] << ") = "; // rdata->sx is a flat 3D array in row-major ordering - std::cout<sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<sx + [i_time * rdata->nplist * rdata->nx + + i_nplist * rdata->nx + i_state]; + std::cout << std::endl; } return 0; diff --git a/models/model_steadystate/model_steadystate.h b/models/model_steadystate/model_steadystate.h index 776b754b08..ca02261ef8 100644 --- a/models/model_steadystate/model_steadystate.h +++ b/models/model_steadystate/model_steadystate.h @@ -1,6 +1,6 @@ #ifndef _amici_model_steadystate_h #define _amici_model_steadystate_h -/* Generated by amiwrap (R2017b) 223c5075608273b17f304556d0e8ccb41233bd21 */ +/* Generated by amiwrap (R2017b) 8b324bca5b796a93094195d22a023e5f8e945ef1 */ #include #include #include "amici/defines.h" @@ -18,12 +18,12 @@ extern void JSparse_model_steadystate(SUNMatrixContent_Sparse JSparse, const rea extern void Jy_model_steadystate(double *nllh, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dJydsigma_model_steadystate(double *dJydsigma, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); extern void dJydy_model_steadystate(double *dJydy, const int iy, const realtype *p, const realtype *k, const double *y, const double *sigmay, const double *my); -extern void dwdp_model_steadystate(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl); -extern void dwdx_model_steadystate(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl); +extern void dwdp_model_steadystate(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static); +extern void dwdx_model_steadystate(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static); extern void dxdotdp_model_steadystate(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp); extern void dydx_model_steadystate(double *dydx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx); extern void sigmay_model_steadystate(double *sigmay, const realtype t, const realtype *p, const realtype *k, const realtype *y); -extern void w_model_steadystate(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl); +extern void w_model_steadystate(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static); extern void x0_model_steadystate(realtype *x0, const realtype t, const realtype *p, const realtype *k); extern void xdot_model_steadystate(realtype *xdot, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); extern void y_model_steadystate(double *y, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w); @@ -72,7 +72,7 @@ class Model_model_steadystate : public amici::Model_ODE { amici::Model* clone() const override { return new Model_model_steadystate(*this); }; - std::string getAmiciCommit() const override { return "223c5075608273b17f304556d0e8ccb41233bd21"; }; + std::string getAmiciCommit() const override { return "8b324bca5b796a93094195d22a023e5f8e945ef1"; }; void fJSparse(SUNMatrixContent_Sparse JSparse, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *dwdx) override { JSparse_model_steadystate(JSparse, t, x, p, k, h, w, dwdx); @@ -132,12 +132,12 @@ class Model_model_steadystate : public amici::Model_ODE { void fdsigmazdp(double *dsigmazdp, const realtype t, const realtype *p, const realtype *k, const int ip) override { } - void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl) override { - dwdp_model_steadystate(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl); + void fdwdp(realtype *dwdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *stcl, const realtype *spl, const realtype *sspl, bool include_static) override { + dwdp_model_steadystate(dwdp, t, x, p, k, h, w, tcl, stcl, spl, sspl, include_static); } - void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl) override { - dwdx_model_steadystate(dwdx, t, x, p, k, h, w, tcl, spl); + void fdwdx(realtype *dwdx, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *w, const realtype *tcl, const realtype *spl, bool include_static) override { + dwdx_model_steadystate(dwdx, t, x, p, k, h, w, tcl, spl, include_static); } void fdxdotdp(realtype *dxdotdp, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const int ip, const realtype *w, const realtype *dwdp) override { @@ -182,8 +182,8 @@ class Model_model_steadystate : public amici::Model_ODE { void fsz(double *sz, const int ie, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *sx, const int ip) override { } - void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) override { - w_model_steadystate(w, t, x, p, k, h, tcl, spl); + void fw(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) override { + w_model_steadystate(w, t, x, p, k, h, tcl, spl, include_static); } void fx0(realtype *x0, const realtype t, const realtype *p, const realtype *k) override { diff --git a/models/model_steadystate/w.cpp b/models/model_steadystate/w.cpp index 948d4529c2..5a0acafc83 100644 --- a/models/model_steadystate/w.cpp +++ b/models/model_steadystate/w.cpp @@ -10,7 +10,7 @@ namespace amici { namespace model_model_steadystate{ -void w_model_steadystate(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl) { +void w_model_steadystate(realtype *w, const realtype t, const realtype *x, const realtype *p, const realtype *k, const realtype *h, const realtype *tcl, const realtype *spl, bool include_static) { w[0] = p[3]*x[2]; w[1] = x[0]*x[0]; } diff --git a/python/examples/example_jax/ExampleJax.ipynb b/python/examples/example_jax/ExampleJax.ipynb index 62391ce9be..931dfb7e28 100644 --- a/python/examples/example_jax/ExampleJax.ipynb +++ b/python/examples/example_jax/ExampleJax.ipynb @@ -5,7 +5,10 @@ "id": "d4d2bc5c", "metadata": {}, "source": [ - "# Overview\n", + "# AMICI & JAX\n", + "\n", + "## Overview\n", + "\n", "The purpose of this guide is to showcase how AMICI can be combined with differentiable programming in [JAX](https://jax.readthedocs.io/en/latest/index.html). We will do so by reimplementing the parameter transformations available in AMICI in JAX and comparing it to the native implementation." ] }, @@ -25,9 +28,9 @@ "id": "fb2fe897", "metadata": {}, "source": [ - "# Preparation\n", + "## Preparation\n", "\n", - "To get started we will import a model using the [petab](https://petab.readthedocs.io). To this end, we will use the [benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab), which features a variety of different models. For more details about petab import, see the respective notebook petab [notebook](https://amici.readthedocs.io/en/latest/petab.html)." + "To get started, we will import a model using the [petab](https://petab.readthedocs.io). To this end, we will use the [benchmark collection](https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab), which features a variety of different models. For more details about petab import, see the respective notebook petab [notebook](https://amici.readthedocs.io/en/latest/petab.html)." ] }, { @@ -274,7 +277,7 @@ "id": "e2ef051a", "metadata": {}, "source": [ - "# JAX implementation\n", + "## JAX implementation\n", "\n", "For full jax support, we would have to implement a new [primitive](https://jax.readthedocs.io/en/latest/notebooks/How_JAX_primitives_work.html), which would require quite a bit of engineering, and in the end wouldn't add much benefit since AMICI can't run on GPUs. Instead, will interface AMICI using the experimental jax module [host_callback](https://jax.readthedocs.io/en/latest/jax.experimental.host_callback.html)." ] @@ -439,7 +442,7 @@ "id": "293e29fb", "metadata": {}, "source": [ - "# Testing\n", + "## Testing\n", "\n", "We can now run the function to compute the log-likelihood and the gradient." ] @@ -473,7 +476,7 @@ "id": "6aa4a5f7", "metadata": {}, "source": [ - "As a sanity check, we compare the computed value to native parameter transformation in amici. " + "As a sanity check, we compare the computed value to native parameter transformation in amici." ] }, { diff --git a/python/sdist/amici/MANIFEST.template.in b/python/sdist/amici/MANIFEST.template.in index eb3b1b450f..fd78129853 100644 --- a/python/sdist/amici/MANIFEST.template.in +++ b/python/sdist/amici/MANIFEST.template.in @@ -1 +1,3 @@ include *.cpp *.h +include CMakeLists.txt +recursive-include swig/ * diff --git a/python/sdist/amici/__init__.py b/python/sdist/amici/__init__.py index 204933565f..cd7bcb0500 100644 --- a/python/sdist/amici/__init__.py +++ b/python/sdist/amici/__init__.py @@ -114,7 +114,7 @@ def _imported_from_setup() -> bool: # These modules don't require the swig interface from typing import Protocol, runtime_checkable - from .de_export import DEExporter, DEModel # noqa: F401 + from .de_export import DEExporter # noqa: F401 from .sbml_import import ( # noqa: F401 SbmlImporter, assignmentRules2observables, diff --git a/python/sdist/amici/_codegen/__init__.py b/python/sdist/amici/_codegen/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/python/sdist/amici/_codegen/cxx_functions.py b/python/sdist/amici/_codegen/cxx_functions.py new file mode 100644 index 0000000000..7831ed97c2 --- /dev/null +++ b/python/sdist/amici/_codegen/cxx_functions.py @@ -0,0 +1,408 @@ +"""Info about C++ functions in the generated model code.""" +from __future__ import annotations + +from dataclasses import dataclass +import re + + +@dataclass +class _FunctionInfo: + """Information on a model-specific generated C++ function + + :ivar ode_arguments: argument list of the ODE function. + input variables should be ``const``. + :ivar dae_arguments: argument list of the DAE function, if different from + ODE function. input variables should be ``const``. + :ivar return_type: the return type of the function + :ivar assume_pow_positivity: + identifies the functions on which ``assume_pow_positivity`` will have + an effect when specified during model generation. generally these are + functions that are used for solving the ODE, where negative values may + negatively affect convergence of the integration algorithm + :ivar sparse: + specifies whether the result of this function will be stored in sparse + format. sparse format means that the function will only return an + array of nonzero values and not a full matrix. + :ivar generate_body: + indicates whether a model-specific implementation is to be generated + :ivar body: + the actual function body. will be filled later + """ + + ode_arguments: str = "" + dae_arguments: str = "" + return_type: str = "void" + assume_pow_positivity: bool = False + sparse: bool = False + generate_body: bool = True + body: str = "" + + def arguments(self, ode: bool = True) -> str: + """Get the arguments for the ODE or DAE function""" + if ode or not self.dae_arguments: + return self.ode_arguments + return self.dae_arguments + + +# Information on a model-specific generated C++ function +# prototype for generated C++ functions, keys are the names of functions +functions = { + "Jy": _FunctionInfo( + "realtype *Jy, const int iy, const realtype *p, " + "const realtype *k, const realtype *y, const realtype *sigmay, " + "const realtype *my" + ), + "dJydsigma": _FunctionInfo( + "realtype *dJydsigma, const int iy, const realtype *p, " + "const realtype *k, const realtype *y, const realtype *sigmay, " + "const realtype *my" + ), + "dJydy": _FunctionInfo( + "realtype *dJydy, const int iy, const realtype *p, " + "const realtype *k, const realtype *y, " + "const realtype *sigmay, const realtype *my", + sparse=True, + ), + "Jz": _FunctionInfo( + "realtype *Jz, const int iz, const realtype *p, const realtype *k, " + "const realtype *z, const realtype *sigmaz, const realtype *mz" + ), + "dJzdsigma": _FunctionInfo( + "realtype *dJzdsigma, const int iz, const realtype *p, " + "const realtype *k, const realtype *z, const realtype *sigmaz, " + "const realtype *mz" + ), + "dJzdz": _FunctionInfo( + "realtype *dJzdz, const int iz, const realtype *p, " + "const realtype *k, const realtype *z, const realtype *sigmaz, " + "const double *mz", + ), + "Jrz": _FunctionInfo( + "realtype *Jrz, const int iz, const realtype *p, " + "const realtype *k, const realtype *rz, const realtype *sigmaz" + ), + "dJrzdsigma": _FunctionInfo( + "realtype *dJrzdsigma, const int iz, const realtype *p, " + "const realtype *k, const realtype *rz, const realtype *sigmaz" + ), + "dJrzdz": _FunctionInfo( + "realtype *dJrzdz, const int iz, const realtype *p, " + "const realtype *k, const realtype *rz, const realtype *sigmaz", + ), + "root": _FunctionInfo( + "realtype *root, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *tcl" + ), + "dwdp": _FunctionInfo( + "realtype *dwdp, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w, const realtype *tcl, const realtype *dtcldp, " + "const realtype *spl, const realtype *sspl, bool include_static", + assume_pow_positivity=True, + sparse=True, + ), + "dwdx": _FunctionInfo( + "realtype *dwdx, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w, const realtype *tcl, const realtype *spl, " + "bool include_static", + assume_pow_positivity=True, + sparse=True, + ), + "create_splines": _FunctionInfo( + "const realtype *p, const realtype *k", + return_type="std::vector", + ), + "spl": _FunctionInfo(generate_body=False), + "sspl": _FunctionInfo(generate_body=False), + "spline_values": _FunctionInfo( + "const realtype *p, const realtype *k", generate_body=False + ), + "spline_slopes": _FunctionInfo( + "const realtype *p, const realtype *k", generate_body=False + ), + "dspline_valuesdp": _FunctionInfo( + "realtype *dspline_valuesdp, const realtype *p, const realtype *k, " + "const int ip" + ), + "dspline_slopesdp": _FunctionInfo( + "realtype *dspline_slopesdp, const realtype *p, const realtype *k, " + "const int ip" + ), + "dwdw": _FunctionInfo( + "realtype *dwdw, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w, const realtype *tcl, bool include_static", + assume_pow_positivity=True, + sparse=True, + ), + "dxdotdw": _FunctionInfo( + "realtype *dxdotdw, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w", + "realtype *dxdotdw, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *dx, const realtype *w", + assume_pow_positivity=True, + sparse=True, + ), + "dxdotdx_explicit": _FunctionInfo( + "realtype *dxdotdx_explicit, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h, const realtype *w", + "realtype *dxdotdx_explicit, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h, const realtype *dx, const realtype *w", + assume_pow_positivity=True, + sparse=True, + ), + "dxdotdp_explicit": _FunctionInfo( + "realtype *dxdotdp_explicit, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h, const realtype *w", + "realtype *dxdotdp_explicit, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h, const realtype *dx, const realtype *w", + assume_pow_positivity=True, + sparse=True, + ), + "dydx": _FunctionInfo( + "realtype *dydx, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w, const realtype *dwdx", + ), + "dydp": _FunctionInfo( + "realtype *dydp, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const int ip, const realtype *w, const realtype *tcl, " + "const realtype *dtcldp, const realtype *spl, const realtype *sspl" + ), + "dzdx": _FunctionInfo( + "realtype *dzdx, const int ie, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h", + ), + "dzdp": _FunctionInfo( + "realtype *dzdp, const int ie, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h, const int ip", + ), + "drzdx": _FunctionInfo( + "realtype *drzdx, const int ie, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h", + ), + "drzdp": _FunctionInfo( + "realtype *drzdp, const int ie, const realtype t, " + "const realtype *x, const realtype *p, const realtype *k, " + "const realtype *h, const int ip", + ), + "dsigmaydy": _FunctionInfo( + "realtype *dsigmaydy, const realtype t, const realtype *p, " + "const realtype *k, const realtype *y" + ), + "dsigmaydp": _FunctionInfo( + "realtype *dsigmaydp, const realtype t, const realtype *p, " + "const realtype *k, const realtype *y, const int ip", + ), + "sigmay": _FunctionInfo( + "realtype *sigmay, const realtype t, const realtype *p, " + "const realtype *k, const realtype *y", + ), + "dsigmazdp": _FunctionInfo( + "realtype *dsigmazdp, const realtype t, const realtype *p," + " const realtype *k, const int ip", + ), + "sigmaz": _FunctionInfo( + "realtype *sigmaz, const realtype t, const realtype *p, " + "const realtype *k", + ), + "sroot": _FunctionInfo( + "realtype *stau, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *sx, const int ip, const int ie, " + "const realtype *tcl", + generate_body=False, + ), + "drootdt": _FunctionInfo(generate_body=False), + "drootdt_total": _FunctionInfo(generate_body=False), + "drootdp": _FunctionInfo(generate_body=False), + "drootdx": _FunctionInfo(generate_body=False), + "stau": _FunctionInfo( + "realtype *stau, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *tcl, const realtype *sx, const int ip, " + "const int ie" + ), + "deltax": _FunctionInfo( + "double *deltax, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const int ie, const realtype *xdot, const realtype *xdot_old" + ), + "ddeltaxdx": _FunctionInfo(generate_body=False), + "ddeltaxdt": _FunctionInfo(generate_body=False), + "ddeltaxdp": _FunctionInfo(generate_body=False), + "deltasx": _FunctionInfo( + "realtype *deltasx, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w, const int ip, const int ie, " + "const realtype *xdot, const realtype *xdot_old, " + "const realtype *sx, const realtype *stau, const realtype *tcl" + ), + "w": _FunctionInfo( + "realtype *w, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, " + "const realtype *h, const realtype *tcl, const realtype *spl, " + "bool include_static", + assume_pow_positivity=True, + ), + "x0": _FunctionInfo( + "realtype *x0, const realtype t, const realtype *p, " + "const realtype *k" + ), + "x0_fixedParameters": _FunctionInfo( + "realtype *x0_fixedParameters, const realtype t, " + "const realtype *p, const realtype *k, " + "gsl::span reinitialization_state_idxs", + ), + "sx0": _FunctionInfo( + "realtype *sx0, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const int ip", + ), + "sx0_fixedParameters": _FunctionInfo( + "realtype *sx0_fixedParameters, const realtype t, " + "const realtype *x0, const realtype *p, const realtype *k, " + "const int ip, gsl::span reinitialization_state_idxs", + ), + "xdot": _FunctionInfo( + "realtype *xdot, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *w", + "realtype *xdot, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h, " + "const realtype *dx, const realtype *w", + assume_pow_positivity=True, + ), + "xdot_old": _FunctionInfo(generate_body=False), + "y": _FunctionInfo( + "realtype *y, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, " + "const realtype *h, const realtype *w", + ), + "x_rdata": _FunctionInfo( + "realtype *x_rdata, const realtype *x, const realtype *tcl, " + "const realtype *p, const realtype *k" + ), + "total_cl": _FunctionInfo( + "realtype *total_cl, const realtype *x_rdata, " + "const realtype *p, const realtype *k" + ), + "dtotal_cldp": _FunctionInfo( + "realtype *dtotal_cldp, const realtype *x_rdata, " + "const realtype *p, const realtype *k, const int ip" + ), + "dtotal_cldx_rdata": _FunctionInfo( + "realtype *dtotal_cldx_rdata, const realtype *x_rdata, " + "const realtype *p, const realtype *k, const realtype *tcl", + sparse=True, + ), + "x_solver": _FunctionInfo("realtype *x_solver, const realtype *x_rdata"), + "dx_rdatadx_solver": _FunctionInfo( + "realtype *dx_rdatadx_solver, const realtype *x, " + "const realtype *tcl, const realtype *p, const realtype *k", + sparse=True, + ), + "dx_rdatadp": _FunctionInfo( + "realtype *dx_rdatadp, const realtype *x, " + "const realtype *tcl, const realtype *p, const realtype *k, " + "const int ip" + ), + "dx_rdatadtcl": _FunctionInfo( + "realtype *dx_rdatadtcl, const realtype *x, " + "const realtype *tcl, const realtype *p, const realtype *k", + sparse=True, + ), + "z": _FunctionInfo( + "realtype *z, const int ie, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h" + ), + "rz": _FunctionInfo( + "realtype *rz, const int ie, const realtype t, const realtype *x, " + "const realtype *p, const realtype *k, const realtype *h" + ), +} + +#: list of sparse functions +sparse_functions = [ + func_name for func_name, func_info in functions.items() if func_info.sparse +] + +#: list of nobody functions +nobody_functions = [ + func_name + for func_name, func_info in functions.items() + if not func_info.generate_body +] + +#: list of sensitivity functions +sensi_functions = [ + func_name + for func_name, func_info in functions.items() + if "const int ip" in func_info.arguments() +] + +#: list of sparse sensitivity functions +sparse_sensi_functions = [ + func_name + for func_name, func_info in functions.items() + if "const int ip" not in func_info.arguments() + and func_name.endswith("dp") + or func_name.endswith("dp_explicit") +] + +#: list of event functions +event_functions = [ + func_name + for func_name, func_info in functions.items() + if "const int ie" in func_info.arguments() + and "const int ip" not in func_info.arguments() +] + +#: list of event sensitivity functions +event_sensi_functions = [ + func_name + for func_name, func_info in functions.items() + if "const int ie" in func_info.arguments() + and "const int ip" in func_info.arguments() +] + +#: list of multiobs functions +multiobs_functions = [ + func_name + for func_name, func_info in functions.items() + if "const int iy" in func_info.arguments() + or "const int iz" in func_info.arguments() +] + + +def var_in_function_signature(name: str, varname: str, ode: bool) -> bool: + """ + Checks if the values for a symbolic variable is passed in the signature + of a function + + :param name: + name of the function + :param varname: + name of the symbolic variable + :param ode: + whether to check the ODE or DAE signature + + :return: + boolean indicating whether the variable occurs in the function + signature + """ + return name in functions and re.search( + rf"const (realtype|double) \*{varname}[0]*(,|$)+", + functions[name].arguments(ode=ode), + ) diff --git a/python/sdist/amici/_codegen/model_class.py b/python/sdist/amici/_codegen/model_class.py new file mode 100644 index 0000000000..e6366c1dfd --- /dev/null +++ b/python/sdist/amici/_codegen/model_class.py @@ -0,0 +1,191 @@ +"""Function for generating the ``amici::Model`` subclass for an amici model.""" +from __future__ import annotations + +from .cxx_functions import functions, multiobs_functions + +from ..de_model_components import Event + + +def get_function_extern_declaration(fun: str, name: str, ode: bool) -> str: + """ + Constructs the extern function declaration for a given function + + :param fun: + function name + :param name: + model name + :param ode: + whether to generate declaration for DAE or ODE + + :return: + C++ function definition string + """ + f = functions[fun] + return f"extern {f.return_type} {fun}_{name}({f.arguments(ode)});" + + +def get_sunindex_extern_declaration( + fun: str, name: str, indextype: str +) -> str: + """ + Constructs the function declaration for an index function of a given + function + + :param fun: + function name + + :param name: + model name + + :param indextype: + index function {'colptrs', 'rowvals'} + + :return: + C++ function declaration string + """ + index_arg = ", int index" if fun in multiobs_functions else "" + return ( + f"extern void {fun}_{indextype}_{name}" + f"(SUNMatrixWrapper &{indextype}{index_arg});" + ) + + +def get_model_override_implementation( + fun: str, name: str, ode: bool, nobody: bool = False +) -> str: + """ + Constructs ``amici::Model::*`` override implementation for a given function + + :param fun: + function name + + :param name: + model name + + :param nobody: + whether the function has a nontrivial implementation + + :return: + C++ function implementation string + """ + func_info = functions[fun] + body = ( + "" + if nobody + else "\n{ind8}{maybe_return}{fun}_{name}({eval_signature});\n{ind4}".format( + ind4=" " * 4, + ind8=" " * 8, + maybe_return="" if func_info.return_type == "void" else "return ", + fun=fun, + name=name, + eval_signature=remove_argument_types(func_info.arguments(ode)), + ) + ) + return "{return_type} f{fun}({signature}) override {{{body}}}\n".format( + return_type=func_info.return_type, + fun=fun, + signature=func_info.arguments(ode), + body=body, + ) + + +def get_sunindex_override_implementation( + fun: str, name: str, indextype: str, nobody: bool = False +) -> str: + """ + Constructs the ``amici::Model`` function implementation for an index + function of a given function + + :param fun: + function name + + :param name: + model name + + :param indextype: + index function {'colptrs', 'rowvals'} + + :param nobody: + whether the corresponding function has a nontrivial implementation + + :return: + C++ function implementation string + """ + index_arg = ", int index" if fun in multiobs_functions else "" + index_arg_eval = ", index" if fun in multiobs_functions else "" + + impl = "void f{fun}_{indextype}({signature}) override {{" + + if nobody: + impl += "}}\n" + else: + impl += ( + "\n{ind8}{fun}_{indextype}_{name}({eval_signature});\n{ind4}}}\n" + ) + + return impl.format( + ind4=" " * 4, + ind8=" " * 8, + fun=fun, + indextype=indextype, + name=name, + signature=f"SUNMatrixWrapper &{indextype}{index_arg}", + eval_signature=f"{indextype}{index_arg_eval}", + ) + + +def remove_argument_types(signature: str) -> str: + """ + Strips argument types from a function signature + + :param signature: + function signature + + :return: + string that can be used to construct function calls with the same + variable names and ordering as in the function signature + """ + # remove * prefix for pointers (pointer must always be removed before + # values otherwise we will inadvertently dereference values, + # same applies for const specifications) + # + # always add whitespace after type definition for cosmetic reasons + known_types = [ + "const realtype *", + "const double *", + "const realtype ", + "double *", + "realtype *", + "const int ", + "int ", + "bool ", + "SUNMatrixContent_Sparse ", + "gsl::span", + ] + + for type_str in known_types: + signature = signature.replace(type_str, "") + + return signature + + +def get_state_independent_event_intializer(events: list[Event]) -> str: + """Get initializer list for state independent events in amici::Model.""" + map_time_to_event_idx = {} + for event_idx, event in enumerate(events): + if not event.triggers_at_fixed_timepoint(): + continue + trigger_time = float(event.get_trigger_time()) + try: + map_time_to_event_idx[trigger_time].append(event_idx) + except KeyError: + map_time_to_event_idx[trigger_time] = [event_idx] + + def vector_initializer(v): + """std::vector initializer list with elements from `v`""" + return f"{{{', '.join(map(str, v))}}}" + + return ", ".join( + f"{{{trigger_time}, {vector_initializer(event_idxs)}}}" + for trigger_time, event_idxs in map_time_to_event_idx.items() + ) diff --git a/python/sdist/amici/_codegen/template.py b/python/sdist/amici/_codegen/template.py new file mode 100644 index 0000000000..34f3391ed6 --- /dev/null +++ b/python/sdist/amici/_codegen/template.py @@ -0,0 +1,42 @@ +"""Functions to apply template substitution to files.""" +from pathlib import Path +from string import Template +from typing import Union + + +class TemplateAmici(Template): + """ + Template format used in AMICI (see :class:`string.Template` for more + details). + + :cvar delimiter: + delimiter that identifies template variables + """ + + delimiter = "TPL_" + + +def apply_template( + source_file: Union[str, Path], + target_file: Union[str, Path], + template_data: dict[str, str], +) -> None: + """ + Load source file, apply template substitution as provided in + templateData and save as targetFile. + + :param source_file: + relative or absolute path to template file + + :param target_file: + relative or absolute path to output file + + :param template_data: + template keywords to substitute (key is template + variable without :attr:`TemplateAmici.delimiter`) + """ + with open(source_file) as filein: + src = TemplateAmici(filein.read()) + result = src.safe_substitute(template_data) + with open(target_file, "w") as fileout: + fileout.write(result) diff --git a/python/sdist/amici/compile.py b/python/sdist/amici/compile.py new file mode 100644 index 0000000000..6c4a336afc --- /dev/null +++ b/python/sdist/amici/compile.py @@ -0,0 +1,80 @@ +""" +Functionality for building the C++ extensions of an amici-created model +package. +""" +import subprocess +import sys +from typing import Optional, Union +from pathlib import Path +import os + + +def build_model_extension( + package_dir: Union[str, Path], + verbose: Optional[Union[bool, int]] = False, + compiler: Optional[str] = None, + extra_msg: Optional[str] = None, +) -> None: + """ + Compile the model extension of an amici-created model package. + + :param package_dir: + Directory of the model package to be compiled. I.e., the directory + containing the `setup.py` file. + + :param verbose: + Make model compilation verbose. + + :param compiler: + Absolute path to the compiler executable to be used to build the Python + extension, e.g. ``/usr/bin/clang``. + + :param extra_msg: + Additional message to be printed in case of a failed build. + """ + # setup.py assumes it is run from within the model directory + package_dir = Path(package_dir) + script_args = [sys.executable, package_dir / "setup.py"] + + if verbose: + script_args.append("--verbose") + else: + script_args.append("--quiet") + + script_args.extend( + [ + "build_ext", + f"--build-lib={package_dir}", + # This is generally not required, but helps to reduce the path + # length of intermediate build files, that may easily become + # problematic on Windows, due to its ridiculous 255-character path + # length limit. + f'--build-temp={package_dir / "build"}', + ] + ) + + env = os.environ.copy() + if compiler is not None: + # CMake will use the compiler specified in the CXX environment variable + env["CXX"] = compiler + + # distutils.core.run_setup looks nicer, but does not let us check the + # result easily + try: + result = subprocess.run( + script_args, + cwd=str(package_dir), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + env=env, + ) + except subprocess.CalledProcessError as e: + print(e.output.decode("utf-8")) + print("Failed building the model extension.") + if extra_msg: + print(f"Note: {extra_msg}") + raise + + if verbose: + print(result.stdout.decode("utf-8")) diff --git a/python/sdist/amici/cxxcodeprinter.py b/python/sdist/amici/cxxcodeprinter.py index 3fe5b8cd17..fb98b0aca0 100644 --- a/python/sdist/amici/cxxcodeprinter.py +++ b/python/sdist/amici/cxxcodeprinter.py @@ -3,6 +3,7 @@ import os import re from typing import Optional +from collections.abc import Sequence from collections.abc import Iterable import sympy as sp @@ -123,6 +124,7 @@ def _get_sym_lines_symbols( equations: sp.Matrix, variable: str, indent_level: int, + indices: Optional[Sequence[int]] = None, ) -> list[str]: """ Generate C++ code for where array elements are directly replaced with @@ -140,9 +142,19 @@ def _get_sym_lines_symbols( :param indent_level: indentation level (number of leading blanks) + :param indices: + Optional custom indices corresponding to entries in `symbols`. + Only used for comments. + :return: C++ code as list of lines """ + assert len(symbols) == len(equations) + if indices is None: + indices = range(len(symbols)) + else: + assert len(indices) == len(symbols) + indent = " " * indent_level def format_regular_line(symbol, math, index): @@ -179,7 +191,9 @@ def format_regular_line(symbol, math, index): for (identifier, definition) in expr_dict.items() } ) - symbol_to_idx = {sym: idx for idx, sym in enumerate(symbols)} + symbol_to_idx = { + sym: idx for idx, sym in zip(indices, symbols) + } def format_line(symbol: sp.Symbol): math = expr_dict[symbol] @@ -203,94 +217,10 @@ def format_line(symbol: sp.Symbol): return [ format_regular_line(sym, math, index) - for index, (sym, math) in enumerate(zip(symbols, equations)) + for index, sym, math in zip(indices, symbols, equations) if math not in [0, 0.0] ] - def csc_matrix( - self, - matrix: sp.Matrix, - rownames: list[sp.Symbol], - colnames: list[sp.Symbol], - identifier: Optional[int] = 0, - pattern_only: Optional[bool] = False, - ) -> tuple[list[int], list[int], sp.Matrix, list[str], sp.Matrix]: - """ - Generates the sparse symbolic identifiers, symbolic identifiers, - sparse matrix, column pointers and row values for a symbolic - variable - - :param matrix: - dense matrix to be sparsified - - :param rownames: - ids of the variable of which the derivative is computed (assuming - matrix is the jacobian) - - :param colnames: - ids of the variable with respect to which the derivative is computed - (assuming matrix is the jacobian) - - :param identifier: - additional identifier that gets appended to symbol names to - ensure their uniqueness in outer loops - - :param pattern_only: - flag for computing sparsity pattern without whole matrix - - :return: - symbol_col_ptrs, symbol_row_vals, sparse_list, symbol_list, - sparse_matrix - """ - idx = 0 - - nrows, ncols = matrix.shape - - if not pattern_only: - sparse_matrix = sp.zeros(nrows, ncols) - symbol_list = [] - sparse_list = [] - symbol_col_ptrs = [] - symbol_row_vals = [] - - for col in range(ncols): - symbol_col_ptrs.append(idx) - for row in range(nrows): - if matrix[row, col] == 0: - continue - - symbol_row_vals.append(row) - idx += 1 - symbol_name = ( - f"d{rownames[row].name}" f"_d{colnames[col].name}" - ) - if identifier: - symbol_name += f"_{identifier}" - symbol_list.append(symbol_name) - if pattern_only: - continue - - sparse_matrix[row, col] = sp.Symbol(symbol_name, real=True) - sparse_list.append(matrix[row, col]) - - if idx == 0: - symbol_col_ptrs = [] # avoid bad memory access for empty matrices - else: - symbol_col_ptrs.append(idx) - - if pattern_only: - sparse_matrix = None - else: - sparse_list = sp.Matrix(sparse_list) - - return ( - symbol_col_ptrs, - symbol_row_vals, - sparse_list, - symbol_list, - sparse_matrix, - ) - @staticmethod def print_bool(expr) -> str: """Print the boolean value of the given expression""" @@ -360,3 +290,84 @@ def get_switch_statement( ), indent0 + "}", ] + + +def csc_matrix( + matrix: sp.Matrix, + rownames: list[sp.Symbol], + colnames: list[sp.Symbol], + identifier: Optional[int] = 0, + pattern_only: Optional[bool] = False, +) -> tuple[list[int], list[int], sp.Matrix, list[str], sp.Matrix]: + """ + Generates the sparse symbolic identifiers, symbolic identifiers, + sparse matrix, column pointers and row values for a symbolic + variable + + :param matrix: + dense matrix to be sparsified + + :param rownames: + ids of the variable of which the derivative is computed (assuming + matrix is the jacobian) + + :param colnames: + ids of the variable with respect to which the derivative is computed + (assuming matrix is the jacobian) + + :param identifier: + additional identifier that gets appended to symbol names to + ensure their uniqueness in outer loops + + :param pattern_only: + flag for computing sparsity pattern without whole matrix + + :return: + symbol_col_ptrs, symbol_row_vals, sparse_list, symbol_list, + sparse_matrix + """ + idx = 0 + nrows, ncols = matrix.shape + + if not pattern_only: + sparse_matrix = sp.zeros(nrows, ncols) + symbol_list = [] + sparse_list = [] + symbol_col_ptrs = [] + symbol_row_vals = [] + + for col in range(ncols): + symbol_col_ptrs.append(idx) + for row in range(nrows): + if matrix[row, col].is_zero: + continue + + symbol_row_vals.append(row) + idx += 1 + symbol_name = f"d{rownames[row].name}" f"_d{colnames[col].name}" + if identifier: + symbol_name += f"_{identifier}" + symbol_list.append(symbol_name) + if pattern_only: + continue + + sparse_matrix[row, col] = sp.Symbol(symbol_name, real=True) + sparse_list.append(matrix[row, col]) + + if idx == 0: + symbol_col_ptrs = [] # avoid bad memory access for empty matrices + else: + symbol_col_ptrs.append(idx) + + if pattern_only: + sparse_matrix = None + else: + sparse_list = sp.Matrix(sparse_list) + + return ( + symbol_col_ptrs, + symbol_row_vals, + sparse_list, + symbol_list, + sparse_matrix, + ) diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index f2badbea76..fea9325ab2 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -1,39 +1,26 @@ """ C++ Export ---------- -This module provides all necessary functionality specify an DE model and -generate executable C++ simulation code. The user generally won't have to -directly call any function from this module as this will be done by +This module provides all necessary functionality to specify a differential +equation model and generate executable C++ simulation code. +The user generally won't have to directly call any function from this module +as this will be done by :py:func:`amici.pysb_import.pysb2amici`, :py:func:`amici.sbml_import.SbmlImporter.sbml2amici` and :py:func:`amici.petab_import.import_model`. """ -import contextlib +from __future__ import annotations import copy -import itertools import logging import os import re import shutil -import subprocess -import sys -from dataclasses import dataclass -from itertools import chain, starmap from pathlib import Path -from string import Template from typing import ( TYPE_CHECKING, - Any, - Callable, Literal, - Optional, - Union, ) -from collections.abc import Sequence -import numpy as np import sympy as sp -from sympy.matrices.dense import MutableDenseMatrix -from sympy.matrices.immutable import ImmutableDenseMatrix from . import ( __commit__, @@ -43,2805 +30,76 @@ amiciSwigPath, splines, ) -from .constants import SymbolId -from .cxxcodeprinter import AmiciCxxCodePrinter, get_switch_statement -from .de_model import * -from .import_utils import ( - ObservableTransformation, - SBMLException, - amici_time_symbol, - generate_flux_symbol, - smart_subs_dict, - strip_pysb, - toposort_symbols, - unique_preserve_order, -) -from .logging import get_logger, log_execution_time, set_log_level - -if TYPE_CHECKING: - from . import sbml_import - - -# Template for model simulation main.cpp file -CXX_MAIN_TEMPLATE_FILE = os.path.join(amiciSrcPath, "main.template.cpp") -# Template for model/swig/CMakeLists.txt -SWIG_CMAKE_TEMPLATE_FILE = os.path.join( - amiciSwigPath, "CMakeLists_model.cmake" -) -# Template for model/CMakeLists.txt -MODEL_CMAKE_TEMPLATE_FILE = os.path.join( - amiciSrcPath, "CMakeLists.template.cmake" -) - -IDENTIFIER_PATTERN = re.compile(r"^[a-zA-Z_]\w*$") -DERIVATIVE_PATTERN = re.compile(r"^d(x_rdata|xdot|\w+?)d(\w+?)(?:_explicit)?$") - - -@dataclass -class _FunctionInfo: - """Information on a model-specific generated C++ function - - :ivar ode_arguments: argument list of the ODE function. input variables should be - ``const``. - :ivar dae_arguments: argument list of the DAE function, if different from ODE - function. input variables should be ``const``. - :ivar return_type: the return type of the function - :ivar assume_pow_positivity: - identifies the functions on which ``assume_pow_positivity`` will have - an effect when specified during model generation. generally these are - functions that are used for solving the ODE, where negative values may - negatively affect convergence of the integration algorithm - :ivar sparse: - specifies whether the result of this function will be stored in sparse - format. sparse format means that the function will only return an - array of nonzero values and not a full matrix. - :ivar generate_body: - indicates whether a model-specific implementation is to be generated - :ivar body: - the actual function body. will be filled later - """ - - ode_arguments: str = "" - dae_arguments: str = "" - return_type: str = "void" - assume_pow_positivity: bool = False - sparse: bool = False - generate_body: bool = True - body: str = "" - - def arguments(self, ode: bool = True) -> str: - """Get the arguments for the ODE or DAE function""" - if ode or not self.dae_arguments: - return self.ode_arguments - return self.dae_arguments - - -# Information on a model-specific generated C++ function -# prototype for generated C++ functions, keys are the names of functions -functions = { - "Jy": _FunctionInfo( - "realtype *Jy, const int iy, const realtype *p, " - "const realtype *k, const realtype *y, const realtype *sigmay, " - "const realtype *my" - ), - "dJydsigma": _FunctionInfo( - "realtype *dJydsigma, const int iy, const realtype *p, " - "const realtype *k, const realtype *y, const realtype *sigmay, " - "const realtype *my" - ), - "dJydy": _FunctionInfo( - "realtype *dJydy, const int iy, const realtype *p, " - "const realtype *k, const realtype *y, " - "const realtype *sigmay, const realtype *my", - sparse=True, - ), - "Jz": _FunctionInfo( - "realtype *Jz, const int iz, const realtype *p, const realtype *k, " - "const realtype *z, const realtype *sigmaz, const realtype *mz" - ), - "dJzdsigma": _FunctionInfo( - "realtype *dJzdsigma, const int iz, const realtype *p, " - "const realtype *k, const realtype *z, const realtype *sigmaz, " - "const realtype *mz" - ), - "dJzdz": _FunctionInfo( - "realtype *dJzdz, const int iz, const realtype *p, " - "const realtype *k, const realtype *z, const realtype *sigmaz, " - "const double *mz", - ), - "Jrz": _FunctionInfo( - "realtype *Jrz, const int iz, const realtype *p, " - "const realtype *k, const realtype *rz, const realtype *sigmaz" - ), - "dJrzdsigma": _FunctionInfo( - "realtype *dJrzdsigma, const int iz, const realtype *p, " - "const realtype *k, const realtype *rz, const realtype *sigmaz" - ), - "dJrzdz": _FunctionInfo( - "realtype *dJrzdz, const int iz, const realtype *p, " - "const realtype *k, const realtype *rz, const realtype *sigmaz", - ), - "root": _FunctionInfo( - "realtype *root, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *tcl" - ), - "dwdp": _FunctionInfo( - "realtype *dwdp, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w, const realtype *tcl, const realtype *dtcldp, " - "const realtype *spl, const realtype *sspl", - assume_pow_positivity=True, - sparse=True, - ), - "dwdx": _FunctionInfo( - "realtype *dwdx, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w, const realtype *tcl, const realtype *spl", - assume_pow_positivity=True, - sparse=True, - ), - "create_splines": _FunctionInfo( - "const realtype *p, const realtype *k", - return_type="std::vector", - ), - "spl": _FunctionInfo(generate_body=False), - "sspl": _FunctionInfo(generate_body=False), - "spline_values": _FunctionInfo( - "const realtype *p, const realtype *k", generate_body=False - ), - "spline_slopes": _FunctionInfo( - "const realtype *p, const realtype *k", generate_body=False - ), - "dspline_valuesdp": _FunctionInfo( - "realtype *dspline_valuesdp, const realtype *p, const realtype *k, const int ip" - ), - "dspline_slopesdp": _FunctionInfo( - "realtype *dspline_slopesdp, const realtype *p, const realtype *k, const int ip" - ), - "dwdw": _FunctionInfo( - "realtype *dwdw, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w, const realtype *tcl", - assume_pow_positivity=True, - sparse=True, - ), - "dxdotdw": _FunctionInfo( - "realtype *dxdotdw, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w", - "realtype *dxdotdw, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *dx, const realtype *w", - assume_pow_positivity=True, - sparse=True, - ), - "dxdotdx_explicit": _FunctionInfo( - "realtype *dxdotdx_explicit, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h, const realtype *w", - "realtype *dxdotdx_explicit, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h, const realtype *dx, const realtype *w", - assume_pow_positivity=True, - sparse=True, - ), - "dxdotdp_explicit": _FunctionInfo( - "realtype *dxdotdp_explicit, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h, const realtype *w", - "realtype *dxdotdp_explicit, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h, const realtype *dx, const realtype *w", - assume_pow_positivity=True, - sparse=True, - ), - "dydx": _FunctionInfo( - "realtype *dydx, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w, const realtype *dwdx", - ), - "dydp": _FunctionInfo( - "realtype *dydp, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const int ip, const realtype *w, const realtype *tcl, " - "const realtype *dtcldp, const realtype *spl, const realtype *sspl" - ), - "dzdx": _FunctionInfo( - "realtype *dzdx, const int ie, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h", - ), - "dzdp": _FunctionInfo( - "realtype *dzdp, const int ie, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h, const int ip", - ), - "drzdx": _FunctionInfo( - "realtype *drzdx, const int ie, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h", - ), - "drzdp": _FunctionInfo( - "realtype *drzdp, const int ie, const realtype t, " - "const realtype *x, const realtype *p, const realtype *k, " - "const realtype *h, const int ip", - ), - "dsigmaydy": _FunctionInfo( - "realtype *dsigmaydy, const realtype t, const realtype *p, " - "const realtype *k, const realtype *y" - ), - "dsigmaydp": _FunctionInfo( - "realtype *dsigmaydp, const realtype t, const realtype *p, " - "const realtype *k, const realtype *y, const int ip", - ), - "sigmay": _FunctionInfo( - "realtype *sigmay, const realtype t, const realtype *p, " - "const realtype *k, const realtype *y", - ), - "dsigmazdp": _FunctionInfo( - "realtype *dsigmazdp, const realtype t, const realtype *p," - " const realtype *k, const int ip", - ), - "sigmaz": _FunctionInfo( - "realtype *sigmaz, const realtype t, const realtype *p, " - "const realtype *k", - ), - "sroot": _FunctionInfo( - "realtype *stau, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *sx, const int ip, const int ie, " - "const realtype *tcl", - generate_body=False, - ), - "drootdt": _FunctionInfo(generate_body=False), - "drootdt_total": _FunctionInfo(generate_body=False), - "drootdp": _FunctionInfo(generate_body=False), - "drootdx": _FunctionInfo(generate_body=False), - "stau": _FunctionInfo( - "realtype *stau, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *tcl, const realtype *sx, const int ip, " - "const int ie" - ), - "deltax": _FunctionInfo( - "double *deltax, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const int ie, const realtype *xdot, const realtype *xdot_old" - ), - "ddeltaxdx": _FunctionInfo(generate_body=False), - "ddeltaxdt": _FunctionInfo(generate_body=False), - "ddeltaxdp": _FunctionInfo(generate_body=False), - "deltasx": _FunctionInfo( - "realtype *deltasx, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w, const int ip, const int ie, " - "const realtype *xdot, const realtype *xdot_old, " - "const realtype *sx, const realtype *stau, const realtype *tcl" - ), - "w": _FunctionInfo( - "realtype *w, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, " - "const realtype *h, const realtype *tcl, const realtype *spl", - assume_pow_positivity=True, - ), - "x0": _FunctionInfo( - "realtype *x0, const realtype t, const realtype *p, " - "const realtype *k" - ), - "x0_fixedParameters": _FunctionInfo( - "realtype *x0_fixedParameters, const realtype t, " - "const realtype *p, const realtype *k, " - "gsl::span reinitialization_state_idxs", - ), - "sx0": _FunctionInfo( - "realtype *sx0, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const int ip", - ), - "sx0_fixedParameters": _FunctionInfo( - "realtype *sx0_fixedParameters, const realtype t, " - "const realtype *x0, const realtype *p, const realtype *k, " - "const int ip, gsl::span reinitialization_state_idxs", - ), - "xdot": _FunctionInfo( - "realtype *xdot, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *w", - "realtype *xdot, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h, " - "const realtype *dx, const realtype *w", - assume_pow_positivity=True, - ), - "xdot_old": _FunctionInfo(generate_body=False), - "y": _FunctionInfo( - "realtype *y, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, " - "const realtype *h, const realtype *w", - ), - "x_rdata": _FunctionInfo( - "realtype *x_rdata, const realtype *x, const realtype *tcl, " - "const realtype *p, const realtype *k" - ), - "total_cl": _FunctionInfo( - "realtype *total_cl, const realtype *x_rdata, " - "const realtype *p, const realtype *k" - ), - "dtotal_cldp": _FunctionInfo( - "realtype *dtotal_cldp, const realtype *x_rdata, " - "const realtype *p, const realtype *k, const int ip" - ), - "dtotal_cldx_rdata": _FunctionInfo( - "realtype *dtotal_cldx_rdata, const realtype *x_rdata, " - "const realtype *p, const realtype *k, const realtype *tcl", - sparse=True, - ), - "x_solver": _FunctionInfo("realtype *x_solver, const realtype *x_rdata"), - "dx_rdatadx_solver": _FunctionInfo( - "realtype *dx_rdatadx_solver, const realtype *x, " - "const realtype *tcl, const realtype *p, const realtype *k", - sparse=True, - ), - "dx_rdatadp": _FunctionInfo( - "realtype *dx_rdatadp, const realtype *x, " - "const realtype *tcl, const realtype *p, const realtype *k, " - "const int ip" - ), - "dx_rdatadtcl": _FunctionInfo( - "realtype *dx_rdatadtcl, const realtype *x, " - "const realtype *tcl, const realtype *p, const realtype *k", - sparse=True, - ), - "z": _FunctionInfo( - "realtype *z, const int ie, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h" - ), - "rz": _FunctionInfo( - "realtype *rz, const int ie, const realtype t, const realtype *x, " - "const realtype *p, const realtype *k, const realtype *h" - ), -} - -# list of sparse functions -sparse_functions = [ - func_name for func_name, func_info in functions.items() if func_info.sparse -] -# list of nobody functions -nobody_functions = [ - func_name - for func_name, func_info in functions.items() - if not func_info.generate_body -] -# list of sensitivity functions -sensi_functions = [ - func_name - for func_name, func_info in functions.items() - if "const int ip" in func_info.arguments() -] -# list of sensitivity functions -sparse_sensi_functions = [ - func_name - for func_name, func_info in functions.items() - if "const int ip" not in func_info.arguments() - and func_name.endswith("dp") - or func_name.endswith("dp_explicit") -] -# list of event functions -event_functions = [ - func_name - for func_name, func_info in functions.items() - if "const int ie" in func_info.arguments() - and "const int ip" not in func_info.arguments() -] -event_sensi_functions = [ - func_name - for func_name, func_info in functions.items() - if "const int ie" in func_info.arguments() - and "const int ip" in func_info.arguments() -] -# list of multiobs functions -multiobs_functions = [ - func_name - for func_name, func_info in functions.items() - if "const int iy" in func_info.arguments() - or "const int iz" in func_info.arguments() -] -# list of equations that have ids which may not be unique -non_unique_id_symbols = ["x_rdata", "y"] - -# custom c++ function replacements -CUSTOM_FUNCTIONS = [ - { - "sympy": "polygamma", - "c++": "boost::math::polygamma", - "include": "#include ", - "build_hint": "Using polygamma requires libboost-math header files.", - }, - {"sympy": "Heaviside", "c++": "amici::heaviside"}, - {"sympy": "DiracDelta", "c++": "amici::dirac"}, -] - -# python log manager -logger = get_logger(__name__, logging.ERROR) - - -def var_in_function_signature(name: str, varname: str, ode: bool) -> bool: - """ - Checks if the values for a symbolic variable is passed in the signature - of a function - - :param name: - name of the function - :param varname: - name of the symbolic variable - :param ode: - whether to check the ODE or DAE signature - - :return: - boolean indicating whether the variable occurs in the function - signature - """ - return name in functions and re.search( - rf"const (realtype|double) \*{varname}[0]*(,|$)+", - functions[name].arguments(ode=ode), - ) - - -# defines the type of some attributes in DEModel -symbol_to_type = { - SymbolId.SPECIES: DifferentialState, - SymbolId.ALGEBRAIC_STATE: AlgebraicState, - SymbolId.ALGEBRAIC_EQUATION: AlgebraicEquation, - SymbolId.PARAMETER: Parameter, - SymbolId.FIXED_PARAMETER: Constant, - SymbolId.OBSERVABLE: Observable, - SymbolId.EVENT_OBSERVABLE: EventObservable, - SymbolId.SIGMAY: SigmaY, - SymbolId.SIGMAZ: SigmaZ, - SymbolId.LLHY: LogLikelihoodY, - SymbolId.LLHZ: LogLikelihoodZ, - SymbolId.LLHRZ: LogLikelihoodRZ, - SymbolId.EXPRESSION: Expression, - SymbolId.EVENT: Event, -} - - -@log_execution_time("running smart_jacobian", logger) -def smart_jacobian( - eq: sp.MutableDenseMatrix, sym_var: sp.MutableDenseMatrix -) -> sp.MutableSparseMatrix: - """ - Wrapper around symbolic jacobian with some additional checks that reduce - computation time for large matrices - - :param eq: - equation - :param sym_var: - differentiation variable - :return: - jacobian of eq wrt sym_var - """ - nrow = eq.shape[0] - ncol = sym_var.shape[0] - if ( - not min(eq.shape) - or not min(sym_var.shape) - or smart_is_zero_matrix(eq) - or smart_is_zero_matrix(sym_var) - ): - return sp.MutableSparseMatrix(nrow, ncol, dict()) - - # preprocess sparsity pattern - elements = ( - (i, j, a, b) - for i, a in enumerate(eq) - for j, b in enumerate(sym_var) - if a.has(b) - ) - - if (n_procs := int(os.environ.get("AMICI_IMPORT_NPROCS", 1))) == 1: - # serial - return sp.MutableSparseMatrix( - nrow, ncol, dict(starmap(_jacobian_element, elements)) - ) - - # parallel - from multiprocessing import get_context - - # "spawn" should avoid potential deadlocks occurring with fork - # see e.g. https://stackoverflow.com/a/66113051 - ctx = get_context("spawn") - with ctx.Pool(n_procs) as p: - mapped = p.starmap(_jacobian_element, elements) - return sp.MutableSparseMatrix(nrow, ncol, dict(mapped)) - - -@log_execution_time("running smart_multiply", logger) -def smart_multiply( - x: Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix], - y: sp.MutableDenseMatrix, -) -> Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix]: - """ - Wrapper around symbolic multiplication with some additional checks that - reduce computation time for large matrices - - :param x: - educt 1 - :param y: - educt 2 - :return: - product - """ - if ( - not x.shape[0] - or not y.shape[1] - or smart_is_zero_matrix(x) - or smart_is_zero_matrix(y) - ): - return sp.zeros(x.shape[0], y.shape[1]) - return x.multiply(y) - - -def smart_is_zero_matrix( - x: Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix], -) -> bool: - """A faster implementation of sympy's is_zero_matrix - - Avoids repeated indexer type checks and double iteration to distinguish - False/None. Found to be about 100x faster for large matrices. - - :param x: Matrix to check - """ - - if isinstance(x, sp.MutableDenseMatrix): - return all(xx.is_zero is True for xx in x.flat()) - - if isinstance(x, list): - return all(smart_is_zero_matrix(xx) for xx in x) - - return x.nnz() == 0 - - -def _default_simplify(x): - """Default simplification applied in DEModel""" - # We need this as a free function instead of a lambda to have it picklable - # for parallel simplification - return sp.powsimp(x, deep=True) - - -class DEModel: - """ - Defines a Differential Equation as set of ModelQuantities. - This class provides general purpose interfaces to compute arbitrary - symbolic derivatives that are necessary for model simulation or - sensitivity computation. - - :ivar _differential_states: - list of differential state variables - - :ivar _algebraic_states: - list of algebraic state variables - - :ivar _observables: - list of observables - - :ivar _event_observables: - list of event observables - - :ivar _sigma_ys: - list of sigmas for observables - - :ivar _sigma_zs: - list of sigmas for event observables - - :ivar _parameters: - list of parameters - - :ivar _log_likelihood_ys: - list of loglikelihoods for observables - - :ivar _log_likelihood_zs: - list of loglikelihoods for event observables - - :ivar _log_likelihood_rzs: - list of loglikelihoods for event observable regularizations - - :ivar _expressions: - list of expressions instances - - :ivar _conservation_laws: - list of conservation laws - - :ivar _symboldim_funs: - define functions that compute model dimensions, these - are functions as the underlying symbolic expressions have not been - populated at compile time - - :ivar _eqs: - carries symbolic formulas of the symbolic variables of the model - - :ivar _sparseeqs: - carries linear list of all symbolic formulas for sparsified - variables - - :ivar _vals: - carries numeric values of symbolic identifiers of the symbolic - variables of the model - - :ivar _names: - carries the names of symbolic identifiers of the symbolic variables - of the model - - :ivar _syms: - carries symbolic identifiers of the symbolic variables of the - model - - :ivar _sparsesyms: - carries linear list of all symbolic identifiers for sparsified - variables - - :ivar _colptrs: - carries column pointers for sparsified variables. See - SUNMatrixContent_Sparse definition in ``sunmatrix/sunmatrix_sparse.h`` - - :ivar _rowvals: - carries row values for sparsified variables. See - SUNMatrixContent_Sparse definition in ``sunmatrix/sunmatrix_sparse.h`` - - :ivar _equation_prototype: - defines the attribute from which an equation should be generated via - list comprehension (see :meth:`OEModel._generate_equation`) - - :ivar _variable_prototype: - defines the attribute from which a variable should be generated via - list comprehension (see :meth:`DEModel._generate_symbol`) - - :ivar _value_prototype: - defines the attribute from which a value should be generated via - list comprehension (see :meth:`DEModel._generate_value`) - - :ivar _total_derivative_prototypes: - defines how a total derivative equation is computed for an equation, - key defines the name and values should be arguments for - :meth:`DEModel.totalDerivative` - - :ivar _lock_total_derivative: - add chainvariables to this set when computing total derivative from - a partial derivative call to enforce a partial derivative in the - next recursion. prevents infinite recursion - - :ivar _simplify: - If not None, this function will be used to simplify symbolic - derivative expressions. Receives sympy expressions as only argument. - To apply multiple simplifications, wrap them in a lambda expression. - - :ivar _x0_fixedParameters_idx: - Index list of subset of states for which x0_fixedParameters was - computed - - :ivar _w_recursion_depth: - recursion depth in w, quantified as nilpotency of dwdw - - :ivar _has_quadratic_nllh: - whether all observables have a gaussian noise model, i.e. whether - res and FIM make sense. - - :ivar _code_printer: - Code printer to generate C++ code - - :ivar _z2event: - list of event indices for each event observable - """ - - def __init__( - self, - verbose: Optional[Union[bool, int]] = False, - simplify: Optional[Callable] = _default_simplify, - cache_simplify: bool = False, - ): - """ - Create a new DEModel instance. - - :param verbose: - verbosity level for logging, True/False default to - ``logging.DEBUG``/``logging.ERROR`` - - :param simplify: - see :meth:`DEModel._simplify` - - :param cache_simplify: - Whether to cache calls to the simplify method. Can e.g. decrease - import times for models with events. - """ - self._differential_states: list[DifferentialState] = [] - self._algebraic_states: list[AlgebraicState] = [] - self._algebraic_equations: list[AlgebraicEquation] = [] - self._observables: list[Observable] = [] - self._event_observables: list[EventObservable] = [] - self._sigma_ys: list[SigmaY] = [] - self._sigma_zs: list[SigmaZ] = [] - self._parameters: list[Parameter] = [] - self._constants: list[Constant] = [] - self._log_likelihood_ys: list[LogLikelihoodY] = [] - self._log_likelihood_zs: list[LogLikelihoodZ] = [] - self._log_likelihood_rzs: list[LogLikelihoodRZ] = [] - self._expressions: list[Expression] = [] - self._conservation_laws: list[ConservationLaw] = [] - self._events: list[Event] = [] - self._splines = [] - self._symboldim_funs: dict[str, Callable[[], int]] = { - "sx": self.num_states_solver, - "v": self.num_states_solver, - "vB": self.num_states_solver, - "xB": self.num_states_solver, - "sigmay": self.num_obs, - "sigmaz": self.num_eventobs, - } - self._eqs: dict[ - str, - Union[ - sp.Matrix, - sp.SparseMatrix, - list[Union[sp.Matrix, sp.SparseMatrix]], - ], - ] = dict() - self._sparseeqs: dict[str, Union[sp.Matrix, list[sp.Matrix]]] = dict() - self._vals: dict[str, list[sp.Expr]] = dict() - self._names: dict[str, list[str]] = dict() - self._syms: dict[str, Union[sp.Matrix, list[sp.Matrix]]] = dict() - self._sparsesyms: dict[str, Union[list[str], list[list[str]]]] = dict() - self._colptrs: dict[str, Union[list[int], list[list[int]]]] = dict() - self._rowvals: dict[str, Union[list[int], list[list[int]]]] = dict() - - self._equation_prototype: dict[str, Callable] = { - "total_cl": self.conservation_laws, - "x0": self.states, - "y": self.observables, - "Jy": self.log_likelihood_ys, - "Jz": self.log_likelihood_zs, - "Jrz": self.log_likelihood_rzs, - "w": self.expressions, - "root": self.events, - "sigmay": self.sigma_ys, - "sigmaz": self.sigma_zs, - } - self._variable_prototype: dict[str, Callable] = { - "tcl": self.conservation_laws, - "x_rdata": self.states, - "y": self.observables, - "z": self.event_observables, - "p": self.parameters, - "k": self.constants, - "w": self.expressions, - "sigmay": self.sigma_ys, - "sigmaz": self.sigma_zs, - "h": self.events, - } - self._value_prototype: dict[str, Callable] = { - "p": self.parameters, - "k": self.constants, - } - self._total_derivative_prototypes: dict[ - str, dict[str, Union[str, list[str]]] - ] = { - "sroot": { - "eq": "root", - "chainvars": ["x"], - "var": "p", - "dxdz_name": "sx", - }, - } - - self._lock_total_derivative: list[str] = list() - self._simplify: Callable = simplify - if cache_simplify and simplify is not None: - - def cached_simplify( - expr: sp.Expr, - _simplified: dict[str, sp.Expr] = {}, - _simplify: Callable = simplify, - ) -> sp.Expr: - """Speed up expression simplification with caching. - - NB: This can decrease model import times for models that have - many repeated expressions during C++ file generation. - For example, this can be useful for models with events. - However, for other models, this may increase model import - times. - - :param expr: - The SymPy expression. - :param _simplified: - The cache. - :param _simplify: - The simplification method. - - :return: - The simplified expression. - """ - expr_str = repr(expr) - if expr_str not in _simplified: - _simplified[expr_str] = _simplify(expr) - return _simplified[expr_str] - - self._simplify = cached_simplify - self._x0_fixedParameters_idx: Union[None, Sequence[int]] - self._w_recursion_depth: int = 0 - self._has_quadratic_nllh: bool = True - set_log_level(logger, verbose) - - self._code_printer = AmiciCxxCodePrinter() - for fun in CUSTOM_FUNCTIONS: - self._code_printer.known_functions[fun["sympy"]] = fun["c++"] - - def differential_states(self) -> list[DifferentialState]: - """Get all differential states.""" - return self._differential_states - - def algebraic_states(self) -> list[AlgebraicState]: - """Get all algebraic states.""" - return self._algebraic_states - - def observables(self) -> list[Observable]: - """Get all observables.""" - return self._observables - - def parameters(self) -> list[Parameter]: - """Get all parameters.""" - return self._parameters - - def constants(self) -> list[Constant]: - """Get all constants.""" - return self._constants - - def expressions(self) -> list[Expression]: - """Get all expressions.""" - return self._expressions - - def events(self) -> list[Event]: - """Get all events.""" - return self._events - - def event_observables(self) -> list[EventObservable]: - """Get all event observables.""" - return self._event_observables - - def sigma_ys(self) -> list[SigmaY]: - """Get all observable sigmas.""" - return self._sigma_ys - - def sigma_zs(self) -> list[SigmaZ]: - """Get all event observable sigmas.""" - return self._sigma_zs - - def conservation_laws(self) -> list[ConservationLaw]: - """Get all conservation laws.""" - return self._conservation_laws - - def log_likelihood_ys(self) -> list[LogLikelihoodY]: - """Get all observable log likelihoodss.""" - return self._log_likelihood_ys - - def log_likelihood_zs(self) -> list[LogLikelihoodZ]: - """Get all event observable log likelihoods.""" - return self._log_likelihood_zs - - def log_likelihood_rzs(self) -> list[LogLikelihoodRZ]: - """Get all event observable regularization log likelihoods.""" - return self._log_likelihood_rzs - - def is_ode(self) -> bool: - """Check if model is ODE model.""" - return len(self._algebraic_equations) == 0 - - def states(self) -> list[State]: - """Get all states.""" - return self._differential_states + self._algebraic_states - - @log_execution_time("importing SbmlImporter", logger) - def import_from_sbml_importer( - self, - si: "sbml_import.SbmlImporter", - compute_cls: Optional[bool] = True, - ) -> None: - """ - Imports a model specification from a - :class:`amici.sbml_import.SbmlImporter` instance. - - :param si: - imported SBML model - :param compute_cls: - whether to compute conservation laws - """ - - # add splines as expressions to the model - # saved for later substituting into the fluxes - spline_subs = {} - - for ispl, spl in enumerate(si.splines): - spline_expr = spl.ode_model_symbol(si) - spline_subs[spl.sbml_id] = spline_expr - self.add_component( - Expression( - identifier=spl.sbml_id, - name=str(spl.sbml_id), - value=spline_expr, - ) - ) - self._splines = si.splines - - # get symbolic expression from SBML importers - symbols = copy.copy(si.symbols) - - # assemble fluxes and add them as expressions to the model - assert len(si.flux_ids) == len(si.flux_vector) - fluxes = [ - generate_flux_symbol(ir, name=flux_id) - for ir, flux_id in enumerate(si.flux_ids) - ] - - # correct time derivatives for compartment changes - def transform_dxdt_to_concentration(species_id, dxdt): - """ - Produces the appropriate expression for the first derivative of a - species with respect to time, for species that reside in - compartments with a constant volume, or a volume that is defined by - an assignment or rate rule. - - :param species_id: - The identifier of the species (generated in "sbml_import.py"). - - :param dxdt: - The element-wise product of the row in the stoichiometric - matrix that corresponds to the species (row x_index) and the - flux (kinetic laws) vector. Ignored in the case of rate rules. - """ - # The derivation of the below return expressions can be found in - # the documentation. They are found by rearranging - # $\frac{d}{dt} (vx) = Sw$ for $\frac{dx}{dt}$, where $v$ is the - # vector of species compartment volumes, $x$ is the vector of - # species concentrations, $S$ is the stoichiometric matrix, and $w$ - # is the flux vector. The conditional below handles the cases of - # species in (i) compartments with a rate rule, (ii) compartments - # with an assignment rule, and (iii) compartments with a constant - # volume, respectively. - species = si.symbols[SymbolId.SPECIES][species_id] - - comp = species["compartment"] - if comp in si.symbols[SymbolId.SPECIES]: - dv_dt = si.symbols[SymbolId.SPECIES][comp]["dt"] - xdot = (dxdt - dv_dt * species_id) / comp - return xdot - elif comp in si.compartment_assignment_rules: - v = si.compartment_assignment_rules[comp] - - # we need to flatten out assignments in the compartment in - # order to ensure that we catch all species dependencies - v = smart_subs_dict( - v, si.symbols[SymbolId.EXPRESSION], "value" - ) - dv_dt = v.diff(amici_time_symbol) - # we may end up with a time derivative of the compartment - # volume due to parameter rate rules - comp_rate_vars = [ - p - for p in v.free_symbols - if p in si.symbols[SymbolId.SPECIES] - ] - for var in comp_rate_vars: - dv_dt += ( - v.diff(var) * si.symbols[SymbolId.SPECIES][var]["dt"] - ) - dv_dx = v.diff(species_id) - xdot = (dxdt - dv_dt * species_id) / (dv_dx * species_id + v) - return xdot - elif comp in si.symbols[SymbolId.ALGEBRAIC_STATE]: - raise SBMLException( - f"Species {species_id} is in a compartment {comp} that is" - f" defined by an algebraic equation. This is not" - f" supported." - ) - else: - v = si.compartments[comp] - - if v == 1.0: - return dxdt - - return dxdt / v - - # create dynamics without respecting conservation laws first - dxdt = smart_multiply( - si.stoichiometric_matrix, MutableDenseMatrix(fluxes) - ) - for ix, ((species_id, species), formula) in enumerate( - zip(symbols[SymbolId.SPECIES].items(), dxdt) - ): - # rate rules and amount species don't need to be updated - if "dt" in species: - continue - if species["amount"]: - species["dt"] = formula - else: - species["dt"] = transform_dxdt_to_concentration( - species_id, formula - ) - - # create all basic components of the DE model and add them. - for symbol_name in symbols: - # transform dict of lists into a list of dicts - args = ["name", "identifier"] - - if symbol_name == SymbolId.SPECIES: - args += ["dt", "init"] - elif symbol_name == SymbolId.ALGEBRAIC_STATE: - args += ["init"] - else: - args += ["value"] - - if symbol_name == SymbolId.EVENT: - args += ["state_update", "initial_value"] - elif symbol_name == SymbolId.OBSERVABLE: - args += ["transformation"] - elif symbol_name == SymbolId.EVENT_OBSERVABLE: - args += ["event"] - - comp_kwargs = [ - { - "identifier": var_id, - **{k: v for k, v in var.items() if k in args}, - } - for var_id, var in symbols[symbol_name].items() - ] - - for comp_kwarg in comp_kwargs: - self.add_component(symbol_to_type[symbol_name](**comp_kwarg)) - - # add fluxes as expressions, this needs to happen after base - # expressions from symbols have been parsed - for flux_id, flux in zip(fluxes, si.flux_vector): - # replace splines inside fluxes - flux = flux.subs(spline_subs) - self.add_component( - Expression(identifier=flux_id, name=str(flux_id), value=flux) - ) - - # process conservation laws - if compute_cls: - si.process_conservation_laws(self) - - # fill in 'self._sym' based on prototypes and components in ode_model - self.generate_basic_variables() - self._has_quadratic_nllh = all( - llh["dist"] - in ["normal", "lin-normal", "log-normal", "log10-normal"] - for llh in si.symbols[SymbolId.LLHY].values() - ) - - # substitute SBML-rateOf constructs - self._process_sbml_rate_of() - - def _process_sbml_rate_of(self) -> None: - """Substitute any SBML-rateOf constructs in the model equations""" - rate_of_func = sp.core.function.UndefinedFunction("rateOf") - species_sym_to_xdot = dict(zip(self.sym("x"), self.sym("xdot"))) - species_sym_to_idx = {x: i for i, x in enumerate(self.sym("x"))} - - def get_rate(symbol: sp.Symbol): - """Get rate of change of the given symbol""" - if symbol.find(rate_of_func): - raise SBMLException("Nesting rateOf() is not allowed.") - - # Replace all rateOf(some_species) by their respective xdot equation - with contextlib.suppress(KeyError): - return self._eqs["xdot"][species_sym_to_idx[symbol]] - - # For anything other than a state, rateOf(.) is 0 or invalid - return 0 - - # replace rateOf-instances in xdot by xdot symbols - made_substitutions = False - for i_state in range(len(self.eq("xdot"))): - if rate_ofs := self._eqs["xdot"][i_state].find(rate_of_func): - self._eqs["xdot"][i_state] = self._eqs["xdot"][i_state].subs( - { - # either the rateOf argument is a state, or it's 0 - rate_of: species_sym_to_xdot.get(rate_of.args[0], 0) - for rate_of in rate_ofs - } - ) - made_substitutions = True - - if made_substitutions: - # substitute in topological order - subs = toposort_symbols( - dict(zip(self.sym("xdot"), self.eq("xdot"))) - ) - self._eqs["xdot"] = smart_subs_dict(self.eq("xdot"), subs) - - # replace rateOf-instances in x0 by xdot equation - for i_state in range(len(self.eq("x0"))): - if rate_ofs := self._eqs["x0"][i_state].find(rate_of_func): - self._eqs["x0"][i_state] = self._eqs["x0"][i_state].subs( - { - rate_of: get_rate(rate_of.args[0]) - for rate_of in rate_ofs - } - ) - - # replace rateOf-instances in w by xdot equation - # here we may need toposort, as xdot may depend on w - made_substitutions = False - for i_expr in range(len(self.eq("w"))): - if rate_ofs := self._eqs["w"][i_expr].find(rate_of_func): - self._eqs["w"][i_expr] = self._eqs["w"][i_expr].subs( - { - rate_of: get_rate(rate_of.args[0]) - for rate_of in rate_ofs - } - ) - made_substitutions = True - - if made_substitutions: - # Sort expressions in self._expressions, w symbols, and w equations - # in topological order. Ideally, this would already happen before - # adding the expressions to the model, but at that point, we don't - # have access to xdot yet. - # NOTE: elsewhere, conservations law expressions are expected to - # occur before any other w expressions, so we must maintain their - # position - # toposort everything but conservation law expressions, - # then prepend conservation laws - w_sorted = toposort_symbols( - dict( - zip( - self.sym("w")[self.num_cons_law() :, :], - self.eq("w")[self.num_cons_law() :, :], - ) - ) - ) - w_sorted = ( - dict( - zip( - self.sym("w")[: self.num_cons_law(), :], - self.eq("w")[: self.num_cons_law(), :], - ) - ) - | w_sorted - ) - old_syms = tuple(self._syms["w"]) - topo_expr_syms = tuple(w_sorted.keys()) - new_order = [old_syms.index(s) for s in topo_expr_syms] - self._expressions = [self._expressions[i] for i in new_order] - self._syms["w"] = sp.Matrix(topo_expr_syms) - self._eqs["w"] = sp.Matrix(list(w_sorted.values())) - - for component in chain( - self.observables(), - self.events(), - self._algebraic_equations, - ): - if rate_ofs := component.get_val().find(rate_of_func): - if isinstance(component, Event): - # TODO froot(...) can currently not depend on `w`, so this substitution fails for non-zero rates - # see, e.g., sbml test case 01293 - raise SBMLException( - "AMICI does currently not support rateOf(.) inside event trigger functions." - ) - - if isinstance(component, AlgebraicEquation): - # TODO IDACalcIC fails with - # "The linesearch algorithm failed: step too small or too many backtracks." - # see, e.g., sbml test case 01482 - raise SBMLException( - "AMICI does currently not support rateOf(.) inside AlgebraicRules." - ) - - component.set_val( - component.get_val().subs( - { - rate_of: get_rate(rate_of.args[0]) - for rate_of in rate_ofs - } - ) - ) - - for event in self.events(): - if event._state_update is None: - continue - - for i_state in range(len(event._state_update)): - if rate_ofs := event._state_update[i_state].find(rate_of_func): - raise SBMLException( - "AMICI does currently not support rateOf(.) inside event state updates." - ) - # TODO here we need xdot sym, not eqs - # event._state_update[i_state] = event._state_update[i_state].subs( - # {rate_of: get_rate(rate_of.args[0]) for rate_of in rate_ofs} - # ) - - def add_component( - self, component: ModelQuantity, insert_first: Optional[bool] = False - ) -> None: - """ - Adds a new ModelQuantity to the model. - - :param component: - model quantity to be added - - :param insert_first: - whether to add quantity first or last, relevant when components - may refer to other components of the same type. - """ - if type(component) not in { - Observable, - Expression, - Parameter, - Constant, - DifferentialState, - AlgebraicState, - AlgebraicEquation, - LogLikelihoodY, - LogLikelihoodZ, - LogLikelihoodRZ, - SigmaY, - SigmaZ, - ConservationLaw, - Event, - EventObservable, - }: - raise ValueError(f"Invalid component type {type(component)}") - - component_list = getattr( - self, - "_" - + "_".join( - s.lower() - for s in re.split(r"([A-Z][^A-Z]+)", type(component).__name__) - if s - ) - + "s", - ) - if insert_first: - component_list.insert(0, component) - else: - component_list.append(component) - - def add_conservation_law( - self, - state: sp.Symbol, - total_abundance: sp.Symbol, - coefficients: dict[sp.Symbol, sp.Expr], - ) -> None: - r""" - Adds a new conservation law to the model. A conservation law is defined - by the conserved quantity :math:`T = \sum_i(a_i * x_i)`, where - :math:`a_i` are coefficients and :math:`x_i` are different state - variables. - - :param state: - symbolic identifier of the state that should be replaced by - the conservation law (:math:`x_j`) - - :param total_abundance: - symbolic identifier of the total abundance (:math:`T/a_j`) - - :param coefficients: - Dictionary of coefficients {x_i: a_i} - """ - try: - ix = next( - filter( - lambda is_s: is_s[1].get_id() == state, - enumerate(self._differential_states), - ) - )[0] - except StopIteration: - raise ValueError( - f"Specified state {state} was not found in the " - f"model states." - ) - - state_id = self._differential_states[ix].get_id() - - # \sum_{i≠j}(a_i * x_i)/a_j - target_expression = ( - sp.Add( - *( - c_i * x_i - for x_i, c_i in coefficients.items() - if x_i != state - ) - ) - / coefficients[state] - ) - - # x_j = T/a_j - \sum_{i≠j}(a_i * x_i)/a_j - state_expr = total_abundance - target_expression - - # T/a_j = \sum_{i≠j}(a_i * x_i)/a_j + x_j - abundance_expr = target_expression + state_id - - self.add_component( - Expression(state_id, str(state_id), state_expr), insert_first=True - ) - - cl = ConservationLaw( - total_abundance, - f"total_{state_id}", - abundance_expr, - coefficients, - state_id, - ) - - self.add_component(cl) - self._differential_states[ix].set_conservation_law(cl) - - def get_observable_transformations(self) -> list[ObservableTransformation]: - """ - List of observable transformations - - :return: - list of transformations - """ - return [obs.trafo for obs in self._observables] - - def num_states_rdata(self) -> int: - """ - Number of states. - - :return: - number of state variable symbols - """ - return len(self.sym("x_rdata")) - - def num_states_solver(self) -> int: - """ - Number of states after applying conservation laws. - - :return: - number of state variable symbols - """ - return len(self.sym("x")) - - def num_cons_law(self) -> int: - """ - Number of conservation laws. - - :return: - number of conservation laws - """ - return self.num_states_rdata() - self.num_states_solver() - - def num_state_reinits(self) -> int: - """ - Number of solver states which would be reinitialized after - preequilibration - - :return: - number of state variable symbols with reinitialization - """ - reinit_states = self.eq("x0_fixedParameters") - solver_states = self.eq("x_solver") - return sum(ix in solver_states for ix in reinit_states) - - def num_obs(self) -> int: - """ - Number of Observables. - - :return: - number of observable symbols - """ - return len(self.sym("y")) - - def num_eventobs(self) -> int: - """ - Number of Event Observables. - - :return: - number of event observable symbols - """ - return len(self.sym("z")) - - def num_const(self) -> int: - """ - Number of Constants. - - :return: - number of constant symbols - """ - return len(self.sym("k")) - - def num_par(self) -> int: - """ - Number of Parameters. - - :return: - number of parameter symbols - """ - return len(self.sym("p")) - - def num_expr(self) -> int: - """ - Number of Expressions. - - :return: - number of expression symbols - """ - return len(self.sym("w")) - - def num_events(self) -> int: - """ - Total number of Events (those for which root-functions are added and those without). - - :return: - number of events - """ - return len(self.sym("h")) - - def num_events_solver(self) -> int: - """ - Number of Events. - - :return: - number of event symbols (length of the root vector in AMICI) - """ - return sum( - not event.triggers_at_fixed_timepoint() for event in self.events() - ) - - def sym(self, name: str) -> sp.Matrix: - """ - Returns (and constructs if necessary) the identifiers for a symbolic - entity. - - :param name: - name of the symbolic variable - - :return: - matrix of symbolic identifiers - """ - if name not in self._syms: - self._generate_symbol(name) - - return self._syms[name] - - def sparsesym(self, name: str, force_generate: bool = True) -> list[str]: - """ - Returns (and constructs if necessary) the sparsified identifiers for - a sparsified symbolic variable. - - :param name: - name of the symbolic variable - - :param force_generate: - whether the symbols should be generated if not available - - :return: - linearized Matrix containing the symbolic identifiers - """ - if name not in sparse_functions: - raise ValueError(f"{name} is not marked as sparse") - if name not in self._sparsesyms and force_generate: - self._generate_sparse_symbol(name) - return self._sparsesyms.get(name, []) - - def eq(self, name: str) -> sp.Matrix: - """ - Returns (and constructs if necessary) the formulas for a symbolic - entity. - - :param name: - name of the symbolic variable - - :return: - matrix of symbolic formulas - """ - - if name not in self._eqs: - dec = log_execution_time(f"computing {name}", logger) - dec(self._compute_equation)(name) - return self._eqs[name] - - def sparseeq(self, name) -> sp.Matrix: - """ - Returns (and constructs if necessary) the sparsified formulas for a - sparsified symbolic variable. - - :param name: - name of the symbolic variable - - :return: - linearized matrix containing the symbolic formulas - """ - if name not in sparse_functions: - raise ValueError(f"{name} is not marked as sparse") - if name not in self._sparseeqs: - self._generate_sparse_symbol(name) - return self._sparseeqs[name] - - def colptrs( - self, name: str - ) -> Union[list[sp.Number], list[list[sp.Number]]]: - """ - Returns (and constructs if necessary) the column pointers for - a sparsified symbolic variable. - - :param name: - name of the symbolic variable - - :return: - list containing the column pointers - """ - if name not in sparse_functions: - raise ValueError(f"{name} is not marked as sparse") - if name not in self._sparseeqs: - self._generate_sparse_symbol(name) - return self._colptrs[name] - - def rowvals( - self, name: str - ) -> Union[list[sp.Number], list[list[sp.Number]]]: - """ - Returns (and constructs if necessary) the row values for a - sparsified symbolic variable. - - :param name: - name of the symbolic variable - - :return: - list containing the row values - """ - if name not in sparse_functions: - raise ValueError(f"{name} is not marked as sparse") - if name not in self._sparseeqs: - self._generate_sparse_symbol(name) - return self._rowvals[name] - - def val(self, name: str) -> list[sp.Number]: - """ - Returns (and constructs if necessary) the numeric values of a - symbolic entity - - :param name: - name of the symbolic variable - - :return: - list containing the numeric values - """ - if name not in self._vals: - self._generate_value(name) - return self._vals[name] - - def name(self, name: str) -> list[str]: - """ - Returns (and constructs if necessary) the names of a symbolic - variable - - :param name: - name of the symbolic variable - - :return: - list of names - """ - if name not in self._names: - self._generate_name(name) - return self._names[name] - - def free_symbols(self) -> set[sp.Basic]: - """ - Returns list of free symbols that appear in RHS and initial - conditions. - """ - return set( - chain.from_iterable( - state.get_free_symbols() - for state in self.states() + self.algebraic_equations() - ) - ) - - def _generate_symbol(self, name: str) -> None: - """ - Generates the symbolic identifiers for a symbolic variable - - :param name: - name of the symbolic variable - """ - if name in self._variable_prototype: - components = self._variable_prototype[name]() - self._syms[name] = sp.Matrix( - [comp.get_id() for comp in components] - ) - if name == "y": - self._syms["my"] = sp.Matrix( - [comp.get_measurement_symbol() for comp in components] - ) - if name == "z": - self._syms["mz"] = sp.Matrix( - [comp.get_measurement_symbol() for comp in components] - ) - self._syms["rz"] = sp.Matrix( - [comp.get_regularization_symbol() for comp in components] - ) - return - elif name == "x": - self._syms[name] = sp.Matrix( - [ - state.get_id() - for state in self.states() - if not state.has_conservation_law() - ] - ) - return - elif name == "xdot": - self._syms[name] = sp.Matrix( - [ - f"d{x.get_id()}dt" if self.is_ode() else f"de_{ix}" - for ix, x in enumerate(self._differential_states) - if not x.has_conservation_law() - ] - + [f"ae_{ix}" for ix in range(len(self._algebraic_equations))] - ) - return - elif name == "dx": - self._syms[name] = sp.Matrix( - [ - f"d{state.get_id()}dt" - for state in self.states() - if not state.has_conservation_law() - ] - ) - return - elif name == "sx0": - self._syms[name] = sp.Matrix( - [ - f"s{state.get_id()}_0" - for state in self.states() - if not state.has_conservation_law() - ] - ) - return - elif name == "sx_rdata": - self._syms[name] = sp.Matrix( - [f"sx_rdata_{i}" for i in range(len(self.states()))] - ) - return - elif name == "dtcldp": - # check, whether the CL consists of only one state. Then, - # sensitivities drop out, otherwise generate symbols - self._syms[name] = sp.Matrix( - [ - [ - sp.Symbol( - f"s{strip_pysb(tcl.get_id())}__" - f"{strip_pysb(par.get_id())}", - real=True, - ) - for par in self._parameters - ] - if self.conservation_law_has_multispecies(tcl) - else [0] * self.num_par() - for tcl in self._conservation_laws - ] - ) - return - elif name == "xdot_old": - length = len(self.eq("xdot")) - elif name in sparse_functions: - self._generate_sparse_symbol(name) - return - elif name in self._symboldim_funs: - length = self._symboldim_funs[name]() - elif name == "stau": - length = self.eq(name)[0].shape[1] - elif name in sensi_functions: - length = self.eq(name).shape[0] - elif name == "spl": - # placeholders for the numeric spline values. - # Need to create symbols - self._syms[name] = sp.Matrix( - [[f"spl_{isp}" for isp in range(len(self._splines))]] - ) - return - elif name == "sspl": - # placeholders for spline sensitivities. Need to create symbols - self._syms[name] = sp.Matrix( - [ - [f"sspl_{isp}_{ip}" for ip in range(len(self._syms["p"]))] - for isp in range(len(self._splines)) - ] - ) - return - else: - length = len(self.eq(name)) - self._syms[name] = sp.Matrix( - [ - sp.Symbol(f'{name}{0 if name == "stau" else i}', real=True) - for i in range(length) - ] - ) - - def generate_basic_variables(self) -> None: - """ - Generates the symbolic identifiers for all variables in - ``DEModel._variable_prototype`` - """ - # We need to process events and Heaviside functions in the ``DEModel`, - # before adding it to DEExporter - self.parse_events() - - for var in self._variable_prototype: - if var not in self._syms: - self._generate_symbol(var) - # symbols for spline values need to be created in addition - for var in ["spl", "sspl"]: - self._generate_symbol(var) - - self._generate_symbol("x") - - def parse_events(self) -> None: - """ - This function checks the right-hand side for roots of Heaviside - functions or events, collects the roots, removes redundant roots, - and replaces the formulae of the found roots by identifiers of AMICI's - Heaviside function implementation in the right-hand side - """ - # Track all roots functions in the right-hand side - roots = copy.deepcopy(self._events) - for state in self._differential_states: - state.set_dt(self._process_heavisides(state.get_dt(), roots)) - - for expr in self._expressions: - expr.set_val(self._process_heavisides(expr.get_val(), roots)) - - # remove all possible Heavisides from roots, which may arise from - # the substitution of `'w'` in `_collect_heaviside_roots` - for root in roots: - root.set_val(self._process_heavisides(root.get_val(), roots)) - - # Now add the found roots to the model components - for root in roots: - # skip roots of SBML events, as these have already been added - if root in self._events: - continue - # add roots of heaviside functions - self.add_component(root) - - # re-order events - first those that require root tracking, then the others - self._events = list( - chain( - itertools.filterfalse( - Event.triggers_at_fixed_timepoint, self._events - ), - filter(Event.triggers_at_fixed_timepoint, self._events), - ) - ) - - def get_appearance_counts(self, idxs: list[int]) -> list[int]: - """ - Counts how often a state appears in the time derivative of - another state and expressions for a subset of states - - :param idxs: - list of state indices for which counts are to be computed - - :return: - list of counts for the states ordered according to the provided - indices - """ - free_symbols_dt = list( - itertools.chain.from_iterable( - [str(symbol) for symbol in state.get_dt().free_symbols] - for state in self.states() - ) - ) - - free_symbols_expr = list( - itertools.chain.from_iterable( - [str(symbol) for symbol in expr.get_val().free_symbols] - for expr in self._expressions - ) - ) - - return [ - free_symbols_dt.count(str(self._differential_states[idx].get_id())) - + free_symbols_expr.count( - str(self._differential_states[idx].get_id()) - ) - for idx in idxs - ] - - def _generate_sparse_symbol(self, name: str) -> None: - """ - Generates the sparse symbolic identifiers, symbolic identifiers, - sparse equations, column pointers and row values for a symbolic - variable - - :param name: - name of the symbolic variable - """ - matrix = self.eq(name) - - if match_deriv := DERIVATIVE_PATTERN.match(name): - eq = match_deriv[1] - var = match_deriv[2] - - rownames = self.sym(eq) - colnames = self.sym(var) - - if name == "dJydy": - # One entry per y-slice - self._colptrs[name] = [] - self._rowvals[name] = [] - self._sparseeqs[name] = [] - self._sparsesyms[name] = [] - self._syms[name] = [] - - for iy in range(self.num_obs()): - ( - symbol_col_ptrs, - symbol_row_vals, - sparse_list, - symbol_list, - sparse_matrix, - ) = self._code_printer.csc_matrix( - matrix[iy, :], - rownames=rownames, - colnames=colnames, - identifier=iy, - ) - self._colptrs[name].append(symbol_col_ptrs) - self._rowvals[name].append(symbol_row_vals) - self._sparseeqs[name].append(sparse_list) - self._sparsesyms[name].append(symbol_list) - self._syms[name].append(sparse_matrix) - else: - ( - symbol_col_ptrs, - symbol_row_vals, - sparse_list, - symbol_list, - sparse_matrix, - ) = self._code_printer.csc_matrix( - matrix, - rownames=rownames, - colnames=colnames, - pattern_only=name in nobody_functions, - ) - - self._colptrs[name] = symbol_col_ptrs - self._rowvals[name] = symbol_row_vals - self._sparseeqs[name] = sparse_list - self._sparsesyms[name] = symbol_list - self._syms[name] = sparse_matrix - - def _compute_equation(self, name: str) -> None: - """ - Computes the symbolic formula for a symbolic variable - - :param name: - name of the symbolic variable - """ - # replacement ensures that we don't have to adapt name in abstract - # model and keep backwards compatibility with matlab - match_deriv = DERIVATIVE_PATTERN.match( - re.sub(r"dJ(y|z|rz)dsigma", r"dJ\1dsigma\1", name) - .replace("sigmarz", "sigmaz") - .replace("dJrzdz", "dJrzdrz") - ) - time_symbol = sp.Matrix([amici_time_symbol]) - - if name in self._equation_prototype: - self._equation_from_components( - name, self._equation_prototype[name]() - ) - - elif name in self._total_derivative_prototypes: - args = self._total_derivative_prototypes[name] - args["name"] = name - self._lock_total_derivative += args["chainvars"] - self._total_derivative(**args) - for cv in args["chainvars"]: - self._lock_total_derivative.remove(cv) - - elif name == "xdot": - if self.is_ode(): - self._eqs[name] = sp.Matrix( - [ - state.get_dt() - for state in self._differential_states - if not state.has_conservation_law() - ] - ) - else: - self._eqs[name] = sp.Matrix( - [ - x.get_dt() - dx - for x, dx in zip( - ( - s - for s in self._differential_states - if not s.has_conservation_law() - ), - self.sym("dx"), - ) - ] - + [eq.get_val() for eq in self._algebraic_equations] - ) - - elif name == "x_rdata": - self._eqs[name] = sp.Matrix( - [state.get_x_rdata() for state in self.states()] - ) - - elif name == "x_solver": - self._eqs[name] = sp.Matrix( - [ - state.get_id() - for state in self.states() - if not state.has_conservation_law() - ] - ) - - elif name == "sx_solver": - self._eqs[name] = sp.Matrix( - [ - self.sym("sx_rdata")[ix] - for ix, state in enumerate(self.states()) - if not state.has_conservation_law() - ] - ) - - elif name == "sx0": - self._derivative(name[1:], "p", name=name) - - elif name == "sx0_fixedParameters": - # deltax = -x+x0_fixedParameters if x0_fixedParameters>0 else 0 - # deltasx = -sx+dx0_fixed_parametersdx*sx+dx0_fixedParametersdp - # if x0_fixedParameters>0 else 0 - # sx0_fixedParameters = sx+deltasx = - # dx0_fixed_parametersdx*sx+dx0_fixedParametersdp - self._eqs[name] = smart_jacobian( - self.eq("x0_fixedParameters"), self.sym("p") - ) - - dx0_fixed_parametersdx = smart_jacobian( - self.eq("x0_fixedParameters"), self.sym("x") - ) - - if not smart_is_zero_matrix(dx0_fixed_parametersdx): - if isinstance(self._eqs[name], ImmutableDenseMatrix): - self._eqs[name] = MutableDenseMatrix(self._eqs[name]) - tmp = smart_multiply(dx0_fixed_parametersdx, self.sym("sx0")) - for ip in range(self._eqs[name].shape[1]): - self._eqs[name][:, ip] += tmp - - elif name == "x0_fixedParameters": - k = self.sym("k") - self._x0_fixedParameters_idx = [ - ix - for ix, eq in enumerate(self.eq("x0")) - if any(sym in eq.free_symbols for sym in k) - ] - eq = self.eq("x0") - self._eqs[name] = sp.Matrix( - [eq[ix] for ix in self._x0_fixedParameters_idx] - ) - - elif name == "dtotal_cldx_rdata": - x_rdata = self.sym("x_rdata") - self._eqs[name] = sp.Matrix( - [ - [cl.get_ncoeff(xr) for xr in x_rdata] - for cl in self._conservation_laws - ] - ) - - elif name == "dtcldx": - # this is always zero - self._eqs[name] = sp.zeros( - self.num_cons_law(), self.num_states_solver() - ) - - elif name == "dtcldp": - # force symbols - self._eqs[name] = self.sym(name) - - elif name == "dx_rdatadx_solver": - if self.num_cons_law(): - x_solver = self.sym("x") - self._eqs[name] = sp.Matrix( - [ - [state.get_dx_rdata_dx_solver(xs) for xs in x_solver] - for state in self.states() - ] - ) - else: - # so far, dx_rdatadx_solver is only required for sx_rdata - # in case of no conservation laws, C++ code will directly use - # sx, we don't need this - self._eqs[name] = sp.zeros( - self.num_states_rdata(), self.num_states_solver() - ) - - elif name == "dx_rdatadp": - if self.num_cons_law(): - self._eqs[name] = smart_jacobian( - self.eq("x_rdata"), self.sym("p") - ) - else: - # so far, dx_rdatadp is only required for sx_rdata - # in case of no conservation laws, C++ code will directly use - # sx, we don't need this - self._eqs[name] = sp.zeros( - self.num_states_rdata(), self.num_par() - ) - - elif name == "dx_rdatadtcl": - self._eqs[name] = smart_jacobian( - self.eq("x_rdata"), self.sym("tcl") - ) - - elif name == "dxdotdx_explicit": - # force symbols - self._derivative("xdot", "x", name=name) - - elif name == "dxdotdp_explicit": - # force symbols - self._derivative("xdot", "p", name=name) - - elif name == "spl": - self._eqs[name] = self.sym(name) - - elif name == "sspl": - # force symbols - self._eqs[name] = self.sym(name) - - elif name == "spline_values": - # force symbols - self._eqs[name] = sp.Matrix( - [y for spline in self._splines for y in spline.values_at_nodes] - ) - - elif name == "spline_slopes": - # force symbols - self._eqs[name] = sp.Matrix( - [ - d - for spline in self._splines - for d in ( - sp.zeros(len(spline.derivatives_at_nodes), 1) - if spline.derivatives_by_fd - else spline.derivatives_at_nodes - ) - ] - ) - - elif name == "drootdt": - self._eqs[name] = smart_jacobian(self.eq("root"), time_symbol) - - elif name == "drootdt_total": - # backsubstitution of optimized right-hand side terms into RHS - # calling subs() is costly. Due to looping over events though, the - # following lines are only evaluated if a model has events - w_sorted = toposort_symbols(dict(zip(self.sym("w"), self.eq("w")))) - tmp_xdot = smart_subs_dict(self.eq("xdot"), w_sorted) - self._eqs[name] = self.eq("drootdt") - if self.num_states_solver(): - self._eqs[name] += smart_multiply(self.eq("drootdx"), tmp_xdot) - - elif name == "deltax": - # fill boluses for Heaviside functions, as empty state updates - # would cause problems when writing the function file later - event_eqs = [] - for event in self._events: - if event._state_update is None: - event_eqs.append(sp.zeros(self.num_states_solver(), 1)) - else: - event_eqs.append(event._state_update) - - self._eqs[name] = event_eqs - - elif name == "z": - event_observables = [ - sp.zeros(self.num_eventobs(), 1) for _ in self._events - ] - event_ids = [e.get_id() for e in self._events] - # TODO: get rid of this stupid 1-based indexing as soon as we can - # the matlab interface - z2event = [ - event_ids.index(event_obs.get_event()) + 1 - for event_obs in self._event_observables - ] - for (iz, ie), event_obs in zip( - enumerate(z2event), self._event_observables - ): - event_observables[ie - 1][iz] = event_obs.get_val() - - self._eqs[name] = event_observables - self._z2event = z2event - - elif name in ["ddeltaxdx", "ddeltaxdp", "ddeltaxdt", "dzdp", "dzdx"]: - if match_deriv[2] == "t": - var = time_symbol - else: - var = self.sym(match_deriv[2]) - - self._eqs[name] = [ - smart_jacobian(self.eq(match_deriv[1])[ie], var) - for ie in range(self.num_events()) - ] - if name == "dzdx": - for ie in range(self.num_events()): - dtaudx = ( - -self.eq("drootdx")[ie, :] - / self.eq("drootdt_total")[ie] - ) - for iz in range(self.num_eventobs()): - if ie != self._z2event[iz] - 1: - continue - dzdt = sp.diff(self.eq("z")[ie][iz], time_symbol) - self._eqs[name][ie][iz, :] += dzdt * dtaudx - - elif name in ["rz", "drzdx", "drzdp"]: - eq_events = [] - for ie in range(self.num_events()): - val = sp.zeros( - self.num_eventobs(), - 1 if name == "rz" else len(self.sym(match_deriv[2])), - ) - # match event observables to root function - for iz in range(self.num_eventobs()): - if ie == self._z2event[iz] - 1: - val[iz, :] = self.eq(name.replace("rz", "root"))[ie, :] - eq_events.append(val) - - self._eqs[name] = eq_events - - elif name == "stau": - self._eqs[name] = [ - -self.eq("sroot")[ie, :] / self.eq("drootdt_total")[ie] - if not self.eq("drootdt_total")[ie].is_zero - else sp.zeros(*self.eq("sroot")[ie, :].shape) - for ie in range(self.num_events()) - ] - - elif name == "deltasx": - if self.num_states_solver() * self.num_par() == 0: - self._eqs[name] = [] - return - - event_eqs = [] - for ie, event in enumerate(self._events): - tmp_eq = sp.zeros(self.num_states_solver(), self.num_par()) - - # need to check if equations are zero since we are using - # symbols - if not smart_is_zero_matrix( - self.eq("stau")[ie] - ) and not smart_is_zero_matrix(self.eq("xdot")): - tmp_eq += smart_multiply( - self.sym("xdot_old") - self.sym("xdot"), - self.sym("stau").T, - ) - - # only add deltax part if there is state update - if event._state_update is not None: - # partial derivative for the parameters - tmp_eq += self.eq("ddeltaxdp")[ie] - - # initial part of chain rule state variables - tmp_dxdp = self.sym("sx") * sp.ones(1, self.num_par()) - - # need to check if equations are zero since we are using - # symbols - if not smart_is_zero_matrix(self.eq("stau")[ie]): - # chain rule for the time point - tmp_eq += smart_multiply( - self.eq("ddeltaxdt")[ie], self.sym("stau").T - ) - - # additional part of chain rule state variables - tmp_dxdp += smart_multiply( - self.sym("xdot_old"), self.sym("stau").T - ) - - # finish chain rule for the state variables - tmp_eq += smart_multiply( - self.eq("ddeltaxdx")[ie], tmp_dxdp - ) - - event_eqs.append(tmp_eq) - - self._eqs[name] = event_eqs - - elif name == "xdot_old": - # force symbols - self._eqs[name] = self.sym(name) - - elif name == "dwdx": - if ( - expected := list( - map( - ConservationLaw.get_x_rdata, - reversed(self.conservation_laws()), - ) - ) - ) != (actual := self.eq("w")[: self.num_cons_law()]): - raise AssertionError( - "Conservation laws are not at the beginning of 'w'. " - f"Got {actual}, expected {expected}." - ) - x = self.sym("x") - self._eqs[name] = sp.Matrix( - [ - [-cl.get_ncoeff(xs) for xs in x] - # the insert first in ode_model._add_conservation_law() means - # that we need to reverse the order here - for cl in reversed(self._conservation_laws) - ] - ).col_join( - smart_jacobian(self.eq("w")[self.num_cons_law() :, :], x) - ) - - elif match_deriv: - self._derivative(match_deriv[1], match_deriv[2], name) - - else: - raise ValueError(f"Unknown equation {name}") - - if name in ("sigmay", "sigmaz"): - # check for states in sigma{y,z}, which is currently not supported - syms_x = self.sym("x") - syms_yz = self.sym(name.removeprefix("sigma")) - xs_in_sigma = {} - for sym_yz, eq_yz in zip(syms_yz, self._eqs[name]): - yz_free_syms = eq_yz.free_symbols - if tmp := {x for x in syms_x if x in yz_free_syms}: - xs_in_sigma[sym_yz] = tmp - if xs_in_sigma: - msg = ", ".join( - [f"{yz} depends on {xs}" for yz, xs in xs_in_sigma.items()] - ) - raise NotImplementedError( - f"State-dependent observables are not supported, but {msg}." - ) - - if name == "root": - # Events are processed after the model has been set up. - # Equations are there, but symbols for roots must be added - self.sym("h") - - if name in {"Jy", "dydx"}: - # do not transpose if we compute the partial derivative as part of - # a total derivative - if not len(self._lock_total_derivative): - self._eqs[name] = self._eqs[name].transpose() - - if name in {"dzdx", "drzdx"}: - self._eqs[name] = [e.T for e in self._eqs[name]] - - if self._simplify: - dec = log_execution_time(f"simplifying {name}", logger) - if isinstance(self._eqs[name], list): - self._eqs[name] = [ - dec(_parallel_applyfunc)(sub_eq, self._simplify) - for sub_eq in self._eqs[name] - ] - else: - self._eqs[name] = dec(_parallel_applyfunc)( - self._eqs[name], self._simplify - ) - - def sym_names(self) -> list[str]: - """ - Returns a list of names of generated symbolic variables - - :return: - list of names - """ - return list(self._syms.keys()) - - def _derivative(self, eq: str, var: str, name: str = None) -> None: - """ - Creates a new symbolic variable according to a derivative - - :param eq: - name of the symbolic variable that defines the formula - - :param var: - name of the symbolic variable that defines the identifiers - with respect to which the derivatives are to be computed - - :param name: - name of resulting symbolic variable, default is ``d{eq}d{var}`` - """ - if not name: - name = f"d{eq}d{var}" - - ignore_chainrule = { - ("xdot", "p"): "w", # has generic implementation in c++ code - ("xdot", "x"): "w", # has generic implementation in c++ code - ("w", "w"): "tcl", # dtcldw = 0 - ("w", "x"): "tcl", # dtcldx = 0 - } - # automatically detect chainrule - chainvars = [ - cv - for cv in ["w", "tcl"] - if var_in_function_signature(eq, cv, self.is_ode()) - and cv not in self._lock_total_derivative - and var != cv - and min(self.sym(cv).shape) - and ( - (eq, var) not in ignore_chainrule - or ignore_chainrule[(eq, var)] != cv - ) - ] - if len(chainvars): - self._lock_total_derivative += chainvars - self._total_derivative(name, eq, chainvars, var) - for cv in chainvars: - self._lock_total_derivative.remove(cv) - return - - # partial derivative - sym_eq = self.eq(eq).transpose() if eq == "Jy" else self.eq(eq) - - sym_var = self.sym(var) - - derivative = smart_jacobian(sym_eq, sym_var) - - self._eqs[name] = derivative - - # compute recursion depth based on nilpotency of jacobian. computing - # nilpotency can be done more efficiently on numerical sparsity pattern - if name == "dwdw": - nonzeros = np.asarray( - derivative.applyfunc(lambda x: int(not x.is_zero)) - ).astype(np.int64) - recursion = nonzeros.copy() - if max(recursion.shape): - while recursion.max(): - recursion = recursion.dot(nonzeros) - self._w_recursion_depth += 1 - if self._w_recursion_depth > len(sym_eq): - raise RuntimeError( - "dwdw is not nilpotent. Something, somewhere went " - "terribly wrong. Please file a bug report at " - "https://github.com/AMICI-dev/AMICI/issues and " - "attach this model." - ) - - if name == "dydw" and not smart_is_zero_matrix(derivative): - dwdw = self.eq("dwdw") - # h(k) = d{eq}dw*dwdw^k* (k=1) - h = smart_multiply(derivative, dwdw) - while not smart_is_zero_matrix(h): - self._eqs[name] += h - # h(k+1) = d{eq}dw*dwdw^(k+1) = h(k)*dwdw - h = smart_multiply(h, dwdw) - - def _total_derivative( - self, - name: str, - eq: str, - chainvars: list[str], - var: str, - dydx_name: str = None, - dxdz_name: str = None, - ) -> None: - """ - Creates a new symbolic variable according to a total derivative - using the chain rule - - :param name: - name of resulting symbolic variable - - :param eq: - name of the symbolic variable that defines the formula - - :param chainvars: - names of the symbolic variable that define the - identifiers with respect to which the chain rules are applied - - :param var: - name of the symbolic variable that defines the identifiers - with respect to which the derivatives are to be computed - - :param dydx_name: - defines the name of the symbolic variable that - defines the derivative of the ``eq`` with respect to ``chainvar``, - default is ``d{eq}d{chainvar}`` - - :param dxdz_name: - defines the name of the symbolic variable that - defines the derivative of the ``chainvar`` with respect to ``var``, - default is d{chainvar}d{var} - """ - # compute total derivative according to chainrule - # Dydz = dydx*dxdz + dydz - - # initialize with partial derivative dydz without chain rule - self._eqs[name] = self.sym_or_eq(name, f"d{eq}d{var}") - if not isinstance(self._eqs[name], sp.Symbol): - # if not a Symbol, create a copy using sympy API - # NB deepcopy does not work safely, see sympy issue #7672 - self._eqs[name] = self._eqs[name].copy() - - for chainvar in chainvars: - if dydx_name is None: - dydx_name = f"d{eq}d{chainvar}" - if dxdz_name is None: - dxdz_name = f"d{chainvar}d{var}" - - dydx = self.sym_or_eq(name, dydx_name) - dxdz = self.sym_or_eq(name, dxdz_name) - # Save time for large models if one multiplicand is zero, - # which is not checked for by sympy - if not smart_is_zero_matrix(dydx) and not smart_is_zero_matrix( - dxdz - ): - dydx_times_dxdz = smart_multiply(dydx, dxdz) - if ( - dxdz.shape[1] == 1 - and self._eqs[name].shape[1] != dxdz.shape[1] - ): - for iz in range(self._eqs[name].shape[1]): - self._eqs[name][:, iz] += dydx_times_dxdz - else: - self._eqs[name] += dydx_times_dxdz - - def sym_or_eq(self, name: str, varname: str) -> sp.Matrix: - """ - Returns symbols or equations depending on whether a given - variable appears in the function signature or not. - - :param name: - name of function for which the signature should be checked - - :param varname: - name of the variable which should be contained in the - function signature - - :return: - the variable symbols if the variable is part of the signature and - the variable equations otherwise. - """ - # dwdx and dwdp will be dynamically computed and their ordering - # within a column may differ from the initialization of symbols here, - # so those are not safe to use. Not removing them from signature as - # this would break backwards compatibility. - if var_in_function_signature( - name, varname, self.is_ode() - ) and varname not in [ - "dwdx", - "dwdp", - ]: - return self.sym(varname) - else: - return self.eq(varname) - - def _multiplication( - self, - name: str, - x: str, - y: str, - transpose_x: Optional[bool] = False, - sign: Optional[int] = 1, - ): - """ - Creates a new symbolic variable according to a multiplication - - :param name: - name of resulting symbolic variable, default is ``d{eq}d{var}`` - - :param x: - name of the symbolic variable that defines the first factor - - :param y: - name of the symbolic variable that defines the second factor - - :param transpose_x: - indicates whether the first factor should be - transposed before multiplication - - :param sign: - defines the sign of the product, should be +1 or -1 - """ - if sign not in [-1, 1]: - raise TypeError(f"sign must be +1 or -1, was {sign}") - - variables = { - varname: self.sym(varname) - if var_in_function_signature(name, varname, self.is_ode()) - else self.eq(varname) - for varname in [x, y] - } - - xx = variables[x].transpose() if transpose_x else variables[x] - yy = variables[y] - - self._eqs[name] = sign * smart_multiply(xx, yy) - - def _equation_from_components( - self, name: str, components: list[ModelQuantity] - ) -> None: - """ - Generates the formulas of a symbolic variable from the attributes - - :param name: - name of resulting symbolic variable - - :param component: - name of the attribute - """ - self._eqs[name] = sp.Matrix([comp.get_val() for comp in components]) - - def get_conservation_laws(self) -> list[tuple[sp.Symbol, sp.Expr]]: - """Returns a list of states with conservation law set - - :return: - list of state identifiers - """ - return [ - (state.get_id(), state.get_x_rdata()) - for state in self.states() - if state.has_conservation_law() - ] - - def _generate_value(self, name: str) -> None: - """ - Generates the numeric values of a symbolic variable from value - prototypes - - :param name: - name of resulting symbolic variable - """ - if name in self._value_prototype: - components = self._value_prototype[name]() - else: - raise ValueError(f"No values for {name}") - - self._vals[name] = [comp.get_val() for comp in components] - - def _generate_name(self, name: str) -> None: - """ - Generates the names of a symbolic variable from variable prototypes or - equation prototypes - - :param name: - name of resulting symbolic variable - """ - if name in self._variable_prototype: - components = self._variable_prototype[name]() - elif name in self._equation_prototype: - components = self._equation_prototype[name]() - else: - raise ValueError(f"No names for {name}") - - self._names[name] = [comp.get_name() for comp in components] - - def state_has_fixed_parameter_initial_condition(self, ix: int) -> bool: - """ - Checks whether the state at specified index has a fixed parameter - initial condition - - :param ix: - state index - - :return: - boolean indicating if any of the initial condition free - variables is contained in the model constants - """ - ic = self.states()[ix].get_val() - if not isinstance(ic, sp.Basic): - return False - return any( - fp in (c.get_id() for c in self._constants) - for fp in ic.free_symbols - ) - - def state_has_conservation_law(self, ix: int) -> bool: - """ - Checks whether the state at specified index has a conservation - law set - - :param ix: - state index - - :return: - boolean indicating if conservation_law is not None - """ - return self.states()[ix].has_conservation_law() - - def get_solver_indices(self) -> dict[int, int]: - """ - Returns a mapping that maps rdata species indices to solver indices - - :return: - dictionary mapping rdata species indices to solver indices - """ - solver_index = {} - ix_solver = 0 - for ix in range(len(self.states())): - if self.state_has_conservation_law(ix): - continue - solver_index[ix] = ix_solver - ix_solver += 1 - return solver_index - - def state_is_constant(self, ix: int) -> bool: - """ - Checks whether the temporal derivative of the state is zero - - :param ix: - state index - - :return: - boolean indicating if constant over time - """ - state = self.states()[ix] - if isinstance(state, AlgebraicState): - return False - - return state.get_dt() == 0.0 - - def conservation_law_has_multispecies(self, tcl: ConservationLaw) -> bool: - """ - Checks whether a conservation law has multiple species or it just - defines one constant species - - :param tcl: - conservation law - - :return: - boolean indicating if conservation_law is not None - """ - state_set = set(self.sym("x_rdata")) - n_species = len(state_set.intersection(tcl.get_val().free_symbols)) - return n_species > 1 - - def _expr_is_time_dependent(self, expr: sp.Expr) -> bool: - """Determine whether an expression is time-dependent. - - :param expr: - The expression. - - :returns: - Whether the expression is time-dependent. - """ - # `expr.free_symbols` will be different to `self._states.keys()`, so - # it's easier to compare as `str`. - expr_syms = {str(sym) for sym in expr.free_symbols} - - # Check if the time variable is in the expression. - if "t" in expr_syms: - return True - - # Check if any time-dependent states are in the expression. - state_syms = [str(sym) for sym in self.states()] - return any( - not self.state_is_constant(state_syms.index(state)) - for state in expr_syms.intersection(state_syms) - ) - - def _get_unique_root( - self, - root_found: sp.Expr, - roots: list[Event], - ) -> Union[sp.Symbol, None]: - """ - Collects roots of Heaviside functions and events and stores them in - the roots list. It checks for redundancy to not store symbolically - equivalent root functions more than once. - - :param root_found: - equation of the root function - :param roots: - list of already known root functions with identifier - - :returns: - unique identifier for root, or ``None`` if the root is not - time-dependent - """ - if not self._expr_is_time_dependent(root_found): - return None - - for root in roots: - if sp.simplify(root_found - root.get_val()) == 0: - return root.get_id() - - # create an event for a new root function - root_symstr = f"Heaviside_{len(roots)}" - roots.append( - Event( - identifier=sp.Symbol(root_symstr), - name=root_symstr, - value=root_found, - state_update=None, - ) - ) - return roots[-1].get_id() - - def _collect_heaviside_roots( - self, - args: Sequence[sp.Expr], - ) -> list[sp.Expr]: - """ - Recursively checks an expression for the occurrence of Heaviside - functions and return all roots found - - :param args: - args attribute of the expanded expression +from ._codegen.cxx_functions import ( + _FunctionInfo, + functions, + sparse_functions, + nobody_functions, + sensi_functions, + sparse_sensi_functions, + event_functions, + event_sensi_functions, + multiobs_functions, +) +from ._codegen.model_class import ( + get_function_extern_declaration, + get_sunindex_extern_declaration, + get_model_override_implementation, + get_sunindex_override_implementation, + get_state_independent_event_intializer, +) +from ._codegen.template import apply_template +from .cxxcodeprinter import ( + AmiciCxxCodePrinter, + get_switch_statement, +) +from .de_model import DEModel +from .de_model_components import * +from .import_utils import ( + strip_pysb, +) +from .logging import get_logger, log_execution_time, set_log_level +from .compile import build_model_extension +from .sympy_utils import ( + _custom_pow_eval_derivative, + _monkeypatched, + smart_is_zero_matrix, +) - :returns: - root functions that were extracted from Heaviside function - arguments - """ - root_funs = [] - for arg in args: - if arg.func == sp.Heaviside: - root_funs.append(arg.args[0]) - elif arg.has(sp.Heaviside): - root_funs.extend(self._collect_heaviside_roots(arg.args)) - - if not root_funs: - return [] - - # substitute 'w' expressions into root expressions now, to avoid - # rewriting 'root.cpp' and 'stau.cpp' headers - # to include 'w.h' - w_sorted = toposort_symbols( - dict( - zip( - [expr.get_id() for expr in self._expressions], - [expr.get_val() for expr in self._expressions], - ) - ) - ) - root_funs = [r.subs(w_sorted) for r in root_funs] +if TYPE_CHECKING: + pass - return root_funs - def _process_heavisides( - self, - dxdt: sp.Expr, - roots: list[Event], - ) -> sp.Expr: - """ - Parses the RHS of a state variable, checks for Heaviside functions, - collects unique roots functions that can be tracked by SUNDIALS and - replaces Heaviside Functions by amici helper variables that will be - updated based on SUNDIALS root tracking. +# Template for model simulation main.cpp file +CXX_MAIN_TEMPLATE_FILE = os.path.join(amiciSrcPath, "main.template.cpp") +# Template for model/swig/CMakeLists.txt +SWIG_CMAKE_TEMPLATE_FILE = os.path.join( + amiciSwigPath, "CMakeLists_model.cmake" +) +# Template for model/CMakeLists.txt +MODEL_CMAKE_TEMPLATE_FILE = os.path.join( + amiciSrcPath, "CMakeLists.template.cmake" +) - :param dxdt: - right-hand side of state variable - :param roots: - list of known root functions with identifier +IDENTIFIER_PATTERN = re.compile(r"^[a-zA-Z_]\w*$") - :returns: - dxdt with Heaviside functions replaced by amici helper variables - """ - # track all the old Heaviside expressions in tmp_roots_old - # replace them later by the new expressions - heavisides = [] - # run through the expression tree and get the roots - tmp_roots_old = self._collect_heaviside_roots(dxdt.args) - for tmp_old in unique_preserve_order(tmp_roots_old): - # we want unique identifiers for the roots - tmp_new = self._get_unique_root(tmp_old, roots) - # `tmp_new` is None if the root is not time-dependent. - if tmp_new is None: - continue - # For Heavisides, we need to add the negative function as well - self._get_unique_root(sp.sympify(-tmp_old), roots) - heavisides.append((sp.Heaviside(tmp_old), tmp_new)) +#: list of equations that have ids which may not be unique +non_unique_id_symbols = ["x_rdata", "y"] - if heavisides: - # only apply subs if necessary - for heaviside_sympy, heaviside_amici in heavisides: - dxdt = dxdt.subs(heaviside_sympy, heaviside_amici) +#: custom c++ function replacements +CUSTOM_FUNCTIONS = [ + { + "sympy": "polygamma", + "c++": "boost::math::polygamma", + "include": "#include ", + "build_hint": "Using polygamma requires libboost-math header files.", + }, + {"sympy": "Heaviside", "c++": "amici::heaviside"}, + {"sympy": "DiracDelta", "c++": "amici::dirac"}, +] - return dxdt +#: python log manager +logger = get_logger(__name__, logging.ERROR) class DEExporter: @@ -2884,6 +142,9 @@ class DEExporter: If the given model uses special functions, this set contains hints for model building. + :ivar _code_printer: + Code printer to generate C++ code + :ivar generate_sensitivity_code: Specifies whether code for sensitivity computation is to be generated @@ -2899,13 +160,13 @@ class DEExporter: def __init__( self, de_model: DEModel, - outdir: Optional[Union[Path, str]] = None, - verbose: Optional[Union[bool, int]] = False, - assume_pow_positivity: Optional[bool] = False, - compiler: Optional[str] = None, - allow_reinit_fixpar_initcond: Optional[bool] = True, - generate_sensitivity_code: Optional[bool] = True, - model_name: Optional[str] = "model", + outdir: Path | str | None = None, + verbose: bool | int | None = False, + assume_pow_positivity: bool | None = False, + compiler: str | None = None, + allow_reinit_fixpar_initcond: bool | None = True, + generate_sensitivity_code: bool | None = True, + model_name: str | None = "model", ): """ Generate AMICI C++ files for the DE provided to the constructor. @@ -2950,10 +211,14 @@ def __init__( self.set_name(model_name) self.set_paths(outdir) + self._code_printer = AmiciCxxCodePrinter() + for fun in CUSTOM_FUNCTIONS: + self._code_printer.known_functions[fun["sympy"]] = fun["c++"] + # Signatures and properties of generated model functions (see # include/amici/model.h for details) self.model: DEModel = de_model - self.model._code_printer.known_functions.update( + self._code_printer.known_functions.update( splines.spline_user_functions( self.model._splines, self._get_index("p") ) @@ -2984,7 +249,12 @@ def compile_model(self) -> None: """ Compiles the generated code it into a simulatable module """ - self._compile_c_code(compiler=self.compiler, verbose=self.verbose) + build_model_extension( + package_dir=self.model_path, + compiler=self.compiler, + verbose=self.verbose, + extra_msg="\n".join(self._build_hints), + ) def _prepare_model_folder(self) -> None: """ @@ -3041,69 +311,6 @@ def _generate_c_code(self) -> None: CXX_MAIN_TEMPLATE_FILE, os.path.join(self.model_path, "main.cpp") ) - def _compile_c_code( - self, - verbose: Optional[Union[bool, int]] = False, - compiler: Optional[str] = None, - ) -> None: - """ - Compile the generated model code - - :param verbose: - Make model compilation verbose - - :param compiler: - Absolute path to the compiler executable to be used to build the Python - extension, e.g. ``/usr/bin/clang``. - """ - # setup.py assumes it is run from within the model directory - module_dir = self.model_path - script_args = [sys.executable, os.path.join(module_dir, "setup.py")] - - if verbose: - script_args.append("--verbose") - else: - script_args.append("--quiet") - - script_args.extend( - [ - "build_ext", - f"--build-lib={module_dir}", - # This is generally not required, but helps to reduce the path - # length of intermediate build files, that may easily become - # problematic on Windows, due to its ridiculous 255-character path - # length limit. - f'--build-temp={Path(module_dir, "build")}', - ] - ) - - env = os.environ.copy() - if compiler is not None: - # CMake will use the compiler specified in the CXX environment variable - env["CXX"] = compiler - - # distutils.core.run_setup looks nicer, but does not let us check the - # result easily - try: - result = subprocess.run( - script_args, - cwd=module_dir, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - check=True, - env=env, - ) - except subprocess.CalledProcessError as e: - print(e.output.decode("utf-8")) - print("Failed building the model extension.") - if self._build_hints: - print("Note:") - print("\n".join(self._build_hints)) - raise - - if verbose: - print(result.stdout.decode("utf-8")) - def _generate_m_code(self) -> None: """ Create a Matlab script for compiling code files to a mex file @@ -3519,7 +726,7 @@ def _get_function_body( f"reinitialization_state_idxs.cend(), {index}) != " "reinitialization_state_idxs.cend())", f" {function}[{index}] = " - f"{self.model._code_printer.doprint(formula)};", + f"{self._code_printer.doprint(formula)};", ] ) cases[ipar] = expressions @@ -3534,12 +741,12 @@ def _get_function_body( f"reinitialization_state_idxs.cend(), {index}) != " "reinitialization_state_idxs.cend())\n " f"{function}[{index}] = " - f"{self.model._code_printer.doprint(formula)};" + f"{self._code_printer.doprint(formula)};" ) elif function in event_functions: cases = { - ie: self.model._code_printer._get_sym_lines_array( + ie: self._code_printer._get_sym_lines_array( equations[ie], function, 0 ) for ie in range(self.model.num_events()) @@ -3552,7 +759,7 @@ def _get_function_body( for ie, inner_equations in enumerate(equations): inner_lines = [] inner_cases = { - ipar: self.model._code_printer._get_sym_lines_array( + ipar: self._code_printer._get_sym_lines_array( inner_equations[:, ipar], function, 0 ) for ipar in range(self.model.num_par()) @@ -3567,7 +774,7 @@ def _get_function_body( and equations.shape[1] == self.model.num_par() ): cases = { - ipar: self.model._code_printer._get_sym_lines_array( + ipar: self._code_printer._get_sym_lines_array( equations[:, ipar], function, 0 ) for ipar in range(self.model.num_par()) @@ -3577,7 +784,7 @@ def _get_function_body( elif function in multiobs_functions: if function == "dJydy": cases = { - iobs: self.model._code_printer._get_sym_lines_array( + iobs: self._code_printer._get_sym_lines_array( equations[iobs], function, 0 ) for iobs in range(self.model.num_obs()) @@ -3585,7 +792,7 @@ def _get_function_body( } else: cases = { - iobs: self.model._code_printer._get_sym_lines_array( + iobs: self._code_printer._get_sym_lines_array( equations[:, iobs], function, 0 ) for iobs in range(equations.shape[1]) @@ -3605,12 +812,60 @@ def _get_function_body( symbols = list(map(sp.Symbol, self.model.sparsesym(function))) else: symbols = self.model.sym(function) - lines += self.model._code_printer._get_sym_lines_symbols( - symbols, equations, function, 4 - ) + + if function in ("w", "dwdw", "dwdx", "dwdp"): + # Split into a block of static and dynamic expressions. + if len(static_idxs := self.model.static_indices(function)) > 0: + tmp_symbols = sp.Matrix( + [[symbols[i]] for i in static_idxs] + ) + tmp_equations = sp.Matrix( + [equations[i] for i in static_idxs] + ) + tmp_lines = self._code_printer._get_sym_lines_symbols( + tmp_symbols, + tmp_equations, + function, + 8, + static_idxs, + ) + if tmp_lines: + lines.extend( + [ + " // static expressions", + " if (include_static) {", + *tmp_lines, + " }", + ] + ) + + # dynamic expressions + if len(dynamic_idxs := self.model.dynamic_indices(function)): + tmp_symbols = sp.Matrix( + [[symbols[i]] for i in dynamic_idxs] + ) + tmp_equations = sp.Matrix( + [equations[i] for i in dynamic_idxs] + ) + + tmp_lines = self._code_printer._get_sym_lines_symbols( + tmp_symbols, + tmp_equations, + function, + 4, + dynamic_idxs, + ) + if tmp_lines: + lines.append("\n // dynamic expressions") + lines.extend(tmp_lines) + + else: + lines += self._code_printer._get_sym_lines_symbols( + symbols, equations, function, 4 + ) else: - lines += self.model._code_printer._get_sym_lines_array( + lines += self._code_printer._get_sym_lines_array( equations, function, 4 ) @@ -3766,10 +1021,10 @@ def _write_model_header_cpp(self) -> None: "NK": self.model.num_const(), "O2MODE": "amici::SecondOrderMode::none", # using code printer ensures proper handling of nan/inf - "PARAMETERS": self.model._code_printer.doprint( - self.model.val("p") - )[1:-1], - "FIXED_PARAMETERS": self.model._code_printer.doprint( + "PARAMETERS": self._code_printer.doprint(self.model.val("p"))[ + 1:-1 + ], + "FIXED_PARAMETERS": self._code_printer.doprint( self.model.val("k") )[1:-1], "PARAMETER_NAMES_INITIALIZER_LIST": self._get_symbol_name_initializer_list( @@ -3831,7 +1086,9 @@ def _write_model_header_cpp(self) -> None: ) ), "Z2EVENT": ", ".join(map(str, self.model._z2event)), - "STATE_INDEPENDENT_EVENTS": self._get_state_independent_event_intializer(), + "STATE_INDEPENDENT_EVENTS": get_state_independent_event_intializer( + self.model.events() + ), "ID": ", ".join( str(float(isinstance(s, DifferentialState))) for s in self.model.states() @@ -3961,40 +1218,21 @@ def _get_symbol_id_initializer_list(self, name: str) -> str: Template initializer list of ids """ return "\n".join( - f'"{self.model._code_printer.doprint(symbol)}", // {name}[{idx}]' + f'"{self._code_printer.doprint(symbol)}", // {name}[{idx}]' for idx, symbol in enumerate(self.model.sym(name)) ) - def _get_state_independent_event_intializer(self) -> str: - """Get initializer list for state independent events in amici::Model.""" - map_time_to_event_idx = {} - for event_idx, event in enumerate(self.model.events()): - if not event.triggers_at_fixed_timepoint(): - continue - trigger_time = float(event.get_trigger_time()) - try: - map_time_to_event_idx[trigger_time].append(event_idx) - except KeyError: - map_time_to_event_idx[trigger_time] = [event_idx] - - def vector_initializer(v): - """std::vector initializer list with elements from `v`""" - return f"{{{', '.join(map(str, v))}}}" - - return ", ".join( - f"{{{trigger_time}, {vector_initializer(event_idxs)}}}" - for trigger_time, event_idxs in map_time_to_event_idx.items() - ) - def _write_c_make_file(self): """Write CMake ``CMakeLists.txt`` file for this model.""" sources = "\n".join( - f + " " - for f in os.listdir(self.model_path) - if f.endswith( - (".cpp", ".h"), + sorted( + f + " " + for f in os.listdir(self.model_path) + if f.endswith( + (".cpp", ".h"), + ) + and f != "main.cpp" ) - and f != "main.cpp" ) template_data = { @@ -4051,7 +1289,7 @@ def _write_module_setup(self) -> None: template_data, ) - def set_paths(self, output_dir: Optional[Union[str, Path]] = None) -> None: + def set_paths(self, output_dir: str | Path | None = None) -> None: """ Set output paths for the model and create if necessary @@ -4086,204 +1324,6 @@ def set_name(self, model_name: str) -> None: self.model_name = model_name -class TemplateAmici(Template): - """ - Template format used in AMICI (see :class:`string.Template` for more - details). - - :cvar delimiter: - delimiter that identifies template variables - """ - - delimiter = "TPL_" - - -def apply_template( - source_file: Union[str, Path], - target_file: Union[str, Path], - template_data: dict[str, str], -) -> None: - """ - Load source file, apply template substitution as provided in - templateData and save as targetFile. - - :param source_file: - relative or absolute path to template file - - :param target_file: - relative or absolute path to output file - - :param template_data: - template keywords to substitute (key is template - variable without :attr:`TemplateAmici.delimiter`) - """ - with open(source_file) as filein: - src = TemplateAmici(filein.read()) - result = src.safe_substitute(template_data) - with open(target_file, "w") as fileout: - fileout.write(result) - - -def get_function_extern_declaration(fun: str, name: str, ode: bool) -> str: - """ - Constructs the extern function declaration for a given function - - :param fun: - function name - :param name: - model name - :param ode: - whether to generate declaration for DAE or ODE - - :return: - C++ function definition string - """ - f = functions[fun] - return f"extern {f.return_type} {fun}_{name}({f.arguments(ode)});" - - -def get_sunindex_extern_declaration( - fun: str, name: str, indextype: str -) -> str: - """ - Constructs the function declaration for an index function of a given - function - - :param fun: - function name - - :param name: - model name - - :param indextype: - index function {'colptrs', 'rowvals'} - - :return: - C++ function declaration string - """ - index_arg = ", int index" if fun in multiobs_functions else "" - return ( - f"extern void {fun}_{indextype}_{name}" - f"(SUNMatrixWrapper &{indextype}{index_arg});" - ) - - -def get_model_override_implementation( - fun: str, name: str, ode: bool, nobody: bool = False -) -> str: - """ - Constructs ``amici::Model::*`` override implementation for a given function - - :param fun: - function name - - :param name: - model name - - :param nobody: - whether the function has a nontrivial implementation - - :return: - C++ function implementation string - """ - func_info = functions[fun] - body = ( - "" - if nobody - else "\n{ind8}{maybe_return}{fun}_{name}({eval_signature});{ind4}\n".format( - ind4=" " * 4, - ind8=" " * 8, - maybe_return="" if func_info.return_type == "void" else "return ", - fun=fun, - name=name, - eval_signature=remove_argument_types(func_info.arguments(ode)), - ) - ) - return "{return_type} f{fun}({signature}) override {{{body}}}\n".format( - return_type=func_info.return_type, - fun=fun, - signature=func_info.arguments(ode), - body=body, - ) - - -def get_sunindex_override_implementation( - fun: str, name: str, indextype: str, nobody: bool = False -) -> str: - """ - Constructs the ``amici::Model`` function implementation for an index - function of a given function - - :param fun: - function name - - :param name: - model name - - :param indextype: - index function {'colptrs', 'rowvals'} - - :param nobody: - whether the corresponding function has a nontrivial implementation - - :return: - C++ function implementation string - """ - index_arg = ", int index" if fun in multiobs_functions else "" - index_arg_eval = ", index" if fun in multiobs_functions else "" - - impl = "void f{fun}_{indextype}({signature}) override {{" - - if nobody: - impl += "}}\n" - else: - impl += "{ind8}{fun}_{indextype}_{name}({eval_signature});\n{ind4}}}\n" - - return impl.format( - ind4=" " * 4, - ind8=" " * 8, - fun=fun, - indextype=indextype, - name=name, - signature=f"SUNMatrixWrapper &{indextype}{index_arg}", - eval_signature=f"{indextype}{index_arg_eval}", - ) - - -def remove_argument_types(signature: str) -> str: - """ - Strips argument types from a function signature - - :param signature: - function signature - - :return: - string that can be used to construct function calls with the same - variable names and ordering as in the function signature - """ - # remove * prefix for pointers (pointer must always be removed before - # values otherwise we will inadvertently dereference values, - # same applies for const specifications) - # - # always add whitespace after type definition for cosmetic reasons - known_types = [ - "const realtype *", - "const double *", - "const realtype ", - "double *", - "realtype *", - "const int ", - "int ", - "SUNMatrixContent_Sparse ", - "gsl::span", - ] - - for type_str in known_types: - signature = signature.replace(type_str, "") - - return signature - - def is_valid_identifier(x: str) -> bool: """ Check whether `x` is a valid identifier for conditions, parameters, @@ -4300,94 +1340,6 @@ def is_valid_identifier(x: str) -> bool: return IDENTIFIER_PATTERN.match(x) is not None -@contextlib.contextmanager -def _monkeypatched(obj: object, name: str, patch: Any): - """ - Temporarily monkeypatches an object. - - :param obj: - object to be patched - - :param name: - name of the attribute to be patched - - :param patch: - patched value - """ - pre_patched_value = getattr(obj, name) - setattr(obj, name, patch) - try: - yield object - finally: - setattr(obj, name, pre_patched_value) - - -def _custom_pow_eval_derivative(self, s): - """ - Custom Pow derivative that removes a removable singularity for - ``self.base == 0`` and ``self.base.diff(s) == 0``. This function is - intended to be monkeypatched into :py:method:`sympy.Pow._eval_derivative`. - - :param self: - sp.Pow class - - :param s: - variable with respect to which the derivative will be computed - """ - dbase = self.base.diff(s) - dexp = self.exp.diff(s) - part1 = sp.Pow(self.base, self.exp - 1) * self.exp * dbase - part2 = self * dexp * sp.log(self.base) - if self.base.is_nonzero or dbase.is_nonzero or part2.is_zero: - # first piece never applies or is zero anyways - return part1 + part2 - - return part1 + sp.Piecewise( - (self.base, sp.And(sp.Eq(self.base, 0), sp.Eq(dbase, 0))), - (part2, True), - ) - - -def _jacobian_element(i, j, eq_i, sym_var_j): - """Compute a single element of a jacobian""" - return (i, j), eq_i.diff(sym_var_j) - - -def _parallel_applyfunc(obj: sp.Matrix, func: Callable) -> sp.Matrix: - """Parallel implementation of sympy's Matrix.applyfunc""" - if (n_procs := int(os.environ.get("AMICI_IMPORT_NPROCS", 1))) == 1: - # serial - return obj.applyfunc(func) - - # parallel - from multiprocessing import get_context - from pickle import PicklingError - - from sympy.matrices.dense import DenseMatrix - - # "spawn" should avoid potential deadlocks occurring with fork - # see e.g. https://stackoverflow.com/a/66113051 - ctx = get_context("spawn") - with ctx.Pool(n_procs) as p: - try: - if isinstance(obj, DenseMatrix): - return obj._new(obj.rows, obj.cols, p.map(func, obj)) - elif isinstance(obj, sp.SparseMatrix): - dok = obj.todok() - mapped = p.map(func, dok.values()) - dok = {k: v for k, v in zip(dok.keys(), mapped) if v != 0} - return obj._new(obj.rows, obj.cols, dok) - else: - raise ValueError(f"Unsupported matrix type {type(obj)}") - except PicklingError as e: - raise ValueError( - f"Couldn't pickle {func}. This is likely because the argument " - "was not a module-level function. Either rewrite the argument " - "to a module-level function or disable parallelization by " - "setting `AMICI_IMPORT_NPROCS=1`." - ) from e - - def _write_gitignore(dest_dir: Path) -> None: """Write .gitignore file. diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model.py index c20509407a..ea2807df52 100644 --- a/python/sdist/amici/de_model.py +++ b/python/sdist/amici/de_model.py @@ -1,734 +1,2276 @@ -"""Objects for AMICI's internal differential equation model representation""" -import abc -import numbers -from typing import Optional, SupportsFloat, Union - +"""Symbolic differential equation model.""" +from __future__ import annotations + +import contextlib +import copy +import itertools +import re +from itertools import chain +from typing import Callable, TYPE_CHECKING +from collections.abc import Sequence + +import numpy as np import sympy as sp +from sympy import ImmutableDenseMatrix, MutableDenseMatrix +from ._codegen.cxx_functions import ( + sparse_functions, + sensi_functions, + nobody_functions, + var_in_function_signature, +) +from .cxxcodeprinter import csc_matrix +from .de_model_components import ( + DifferentialState, + AlgebraicState, + AlgebraicEquation, + Observable, + EventObservable, + SigmaY, + SigmaZ, + Parameter, + Constant, + LogLikelihoodY, + LogLikelihoodZ, + LogLikelihoodRZ, + Expression, + ConservationLaw, + Event, + State, + ModelQuantity, +) from .import_utils import ( - RESERVED_SYMBOLS, + _default_simplify, + SBMLException, + toposort_symbols, + smart_subs_dict, ObservableTransformation, amici_time_symbol, - cast_to_sym, - generate_measurement_symbol, - generate_regularization_symbol, + strip_pysb, + unique_preserve_order, ) +from .sympy_utils import ( + smart_jacobian, + smart_is_zero_matrix, + smart_multiply, + _parallel_applyfunc, +) +from .logging import get_logger, log_execution_time, set_log_level +import logging + +if TYPE_CHECKING: + from .splines import AbstractSpline -__all__ = [ - "ConservationLaw", - "Constant", - "Event", - "Expression", - "LogLikelihoodY", - "LogLikelihoodZ", - "LogLikelihoodRZ", - "ModelQuantity", - "Observable", - "Parameter", - "SigmaY", - "SigmaZ", - "DifferentialState", - "EventObservable", - "AlgebraicState", - "AlgebraicEquation", - "State", -] - - -class ModelQuantity: +logger = get_logger(__name__, logging.ERROR) + + +DERIVATIVE_PATTERN = re.compile(r"^d(x_rdata|xdot|\w+?)d(\w+?)(?:_explicit)?$") + + +class DEModel: """ - Base class for model components + Defines a Differential Equation as set of ModelQuantities. + This class provides general purpose interfaces to compute arbitrary + symbolic derivatives that are necessary for model simulation or + sensitivity computation. + + :ivar _differential_states: + list of differential state variables + + :ivar _algebraic_states: + list of algebraic state variables + + :ivar _observables: + list of observables + + :ivar _event_observables: + list of event observables + + :ivar _sigma_ys: + list of sigmas for observables + + :ivar _sigma_zs: + list of sigmas for event observables + + :ivar _parameters: + list of parameters + + :ivar _log_likelihood_ys: + list of loglikelihoods for observables + + :ivar _log_likelihood_zs: + list of loglikelihoods for event observables + + :ivar _log_likelihood_rzs: + list of loglikelihoods for event observable regularizations + + :ivar _expressions: + list of expressions instances + + :ivar _conservation_laws: + list of conservation laws + + :ivar _symboldim_funs: + define functions that compute model dimensions, these + are functions as the underlying symbolic expressions have not been + populated at compile time + + :ivar _eqs: + carries symbolic formulas of the symbolic variables of the model + + :ivar _sparseeqs: + carries linear list of all symbolic formulas for sparsified + variables + + :ivar _vals: + carries numeric values of symbolic identifiers of the symbolic + variables of the model + + :ivar _names: + carries the names of symbolic identifiers of the symbolic variables + of the model + + :ivar _syms: + carries symbolic identifiers of the symbolic variables of the + model + + :ivar _sparsesyms: + carries linear list of all symbolic identifiers for sparsified + variables + + :ivar _colptrs: + carries column pointers for sparsified variables. See + SUNMatrixContent_Sparse definition in ``sunmatrix/sunmatrix_sparse.h`` + + :ivar _rowvals: + carries row values for sparsified variables. See + SUNMatrixContent_Sparse definition in ``sunmatrix/sunmatrix_sparse.h`` + + :ivar _equation_prototype: + defines the attribute from which an equation should be generated via + list comprehension (see :meth:`OEModel._generate_equation`) + + :ivar _variable_prototype: + defines the attribute from which a variable should be generated via + list comprehension (see :meth:`DEModel._generate_symbol`) + + :ivar _value_prototype: + defines the attribute from which a value should be generated via + list comprehension (see :meth:`DEModel._generate_value`) + + :ivar _total_derivative_prototypes: + defines how a total derivative equation is computed for an equation, + key defines the name and values should be arguments for + :meth:`DEModel.totalDerivative` + + :ivar _lock_total_derivative: + add chainvariables to this set when computing total derivative from + a partial derivative call to enforce a partial derivative in the + next recursion. prevents infinite recursion + + :ivar _simplify: + If not None, this function will be used to simplify symbolic + derivative expressions. Receives sympy expressions as only argument. + To apply multiple simplifications, wrap them in a lambda expression. + + :ivar _x0_fixedParameters_idx: + Index list of subset of states for which x0_fixedParameters was + computed + + :ivar _w_recursion_depth: + recursion depth in w, quantified as nilpotency of dwdw + + :ivar _has_quadratic_nllh: + whether all observables have a gaussian noise model, i.e. whether + res and FIM make sense. + + :ivar _static_indices: + dict of lists list of indices of static variables for different + model entities. + + :ivar _z2event: + list of event indices for each event observable """ def __init__( self, - identifier: sp.Symbol, - name: str, - value: Union[SupportsFloat, numbers.Number, sp.Expr], + verbose: bool | int | None = False, + simplify: Callable | None = _default_simplify, + cache_simplify: bool = False, ): """ - Create a new ModelQuantity instance. + Create a new DEModel instance. + + :param verbose: + verbosity level for logging, True/False default to + ``logging.DEBUG``/``logging.ERROR`` + + :param simplify: + see :meth:`DEModel._simplify` + + :param cache_simplify: + Whether to cache calls to the simplify method. Can e.g. decrease + import times for models with events. + """ + self._differential_states: list[DifferentialState] = [] + self._algebraic_states: list[AlgebraicState] = [] + self._algebraic_equations: list[AlgebraicEquation] = [] + self._observables: list[Observable] = [] + self._event_observables: list[EventObservable] = [] + self._sigma_ys: list[SigmaY] = [] + self._sigma_zs: list[SigmaZ] = [] + self._parameters: list[Parameter] = [] + self._constants: list[Constant] = [] + self._log_likelihood_ys: list[LogLikelihoodY] = [] + self._log_likelihood_zs: list[LogLikelihoodZ] = [] + self._log_likelihood_rzs: list[LogLikelihoodRZ] = [] + self._expressions: list[Expression] = [] + self._conservation_laws: list[ConservationLaw] = [] + self._events: list[Event] = [] + self._splines: list[AbstractSpline] = [] + self._symboldim_funs: dict[str, Callable[[], int]] = { + "sx": self.num_states_solver, + "v": self.num_states_solver, + "vB": self.num_states_solver, + "xB": self.num_states_solver, + "sigmay": self.num_obs, + "sigmaz": self.num_eventobs, + } + self._eqs: dict[ + str, + (sp.Matrix | sp.SparseMatrix | list[sp.Matrix | sp.SparseMatrix]), + ] = dict() + self._sparseeqs: dict[str, sp.Matrix | list[sp.Matrix]] = dict() + self._vals: dict[str, list[sp.Expr]] = dict() + self._names: dict[str, list[str]] = dict() + self._syms: dict[str, sp.Matrix | list[sp.Matrix]] = dict() + self._sparsesyms: dict[str, list[str] | list[list[str]]] = dict() + self._colptrs: dict[str, list[int] | list[list[int]]] = dict() + self._rowvals: dict[str, list[int] | list[list[int]]] = dict() + + self._equation_prototype: dict[str, Callable] = { + "total_cl": self.conservation_laws, + "x0": self.states, + "y": self.observables, + "Jy": self.log_likelihood_ys, + "Jz": self.log_likelihood_zs, + "Jrz": self.log_likelihood_rzs, + "w": self.expressions, + "root": self.events, + "sigmay": self.sigma_ys, + "sigmaz": self.sigma_zs, + } + self._variable_prototype: dict[str, Callable] = { + "tcl": self.conservation_laws, + "x_rdata": self.states, + "y": self.observables, + "z": self.event_observables, + "p": self.parameters, + "k": self.constants, + "w": self.expressions, + "sigmay": self.sigma_ys, + "sigmaz": self.sigma_zs, + "h": self.events, + } + self._value_prototype: dict[str, Callable] = { + "p": self.parameters, + "k": self.constants, + } + self._total_derivative_prototypes: dict[ + str, dict[str, str | list[str]] + ] = { + "sroot": { + "eq": "root", + "chainvars": ["x"], + "var": "p", + "dxdz_name": "sx", + }, + } + + self._lock_total_derivative: list[str] = list() + self._simplify: Callable = simplify + if cache_simplify and simplify is not None: + + def cached_simplify( + expr: sp.Expr, + _simplified: dict[str, sp.Expr] = {}, # noqa B006 + _simplify: Callable = simplify, + ) -> sp.Expr: + """Speed up expression simplification with caching. + + NB: This can decrease model import times for models that have + many repeated expressions during C++ file generation. + For example, this can be useful for models with events. + However, for other models, this may increase model import + times. + + :param expr: + The SymPy expression. + :param _simplified: + The cache. + :param _simplify: + The simplification method. + + :return: + The simplified expression. + """ + expr_str = repr(expr) + if expr_str not in _simplified: + _simplified[expr_str] = _simplify(expr) + return _simplified[expr_str] + + self._simplify = cached_simplify + self._x0_fixedParameters_idx: None | Sequence[int] + self._w_recursion_depth: int = 0 + self._has_quadratic_nllh: bool = True + set_log_level(logger, verbose) + + self._static_indices: dict[str, list[int]] = {} + + def differential_states(self) -> list[DifferentialState]: + """Get all differential states.""" + return self._differential_states + + def algebraic_states(self) -> list[AlgebraicState]: + """Get all algebraic states.""" + return self._algebraic_states + + def observables(self) -> list[Observable]: + """Get all observables.""" + return self._observables + + def parameters(self) -> list[Parameter]: + """Get all parameters.""" + return self._parameters + + def constants(self) -> list[Constant]: + """Get all constants.""" + return self._constants + + def expressions(self) -> list[Expression]: + """Get all expressions.""" + return self._expressions + + def events(self) -> list[Event]: + """Get all events.""" + return self._events + + def event_observables(self) -> list[EventObservable]: + """Get all event observables.""" + return self._event_observables + + def sigma_ys(self) -> list[SigmaY]: + """Get all observable sigmas.""" + return self._sigma_ys + + def sigma_zs(self) -> list[SigmaZ]: + """Get all event observable sigmas.""" + return self._sigma_zs + + def conservation_laws(self) -> list[ConservationLaw]: + """Get all conservation laws.""" + return self._conservation_laws + + def log_likelihood_ys(self) -> list[LogLikelihoodY]: + """Get all observable log likelihoodss.""" + return self._log_likelihood_ys + + def log_likelihood_zs(self) -> list[LogLikelihoodZ]: + """Get all event observable log likelihoods.""" + return self._log_likelihood_zs + + def log_likelihood_rzs(self) -> list[LogLikelihoodRZ]: + """Get all event observable regularization log likelihoods.""" + return self._log_likelihood_rzs + + def is_ode(self) -> bool: + """Check if model is ODE model.""" + return len(self._algebraic_equations) == 0 + + def states(self) -> list[State]: + """Get all states.""" + return self._differential_states + self._algebraic_states + + def _process_sbml_rate_of(self) -> None: + """Substitute any SBML-rateOf constructs in the model equations""" + rate_of_func = sp.core.function.UndefinedFunction("rateOf") + species_sym_to_xdot = dict(zip(self.sym("x"), self.sym("xdot"))) + species_sym_to_idx = {x: i for i, x in enumerate(self.sym("x"))} + + def get_rate(symbol: sp.Symbol): + """Get rate of change of the given symbol""" + if symbol.find(rate_of_func): + raise SBMLException("Nesting rateOf() is not allowed.") + + # Replace all rateOf(some_species) by their respective xdot equation + with contextlib.suppress(KeyError): + return self._eqs["xdot"][species_sym_to_idx[symbol]] + + # For anything other than a state, rateOf(.) is 0 or invalid + return 0 + + # replace rateOf-instances in xdot by xdot symbols + made_substitutions = False + for i_state in range(len(self.eq("xdot"))): + if rate_ofs := self._eqs["xdot"][i_state].find(rate_of_func): + self._eqs["xdot"][i_state] = self._eqs["xdot"][i_state].subs( + { + # either the rateOf argument is a state, or it's 0 + rate_of: species_sym_to_xdot.get(rate_of.args[0], 0) + for rate_of in rate_ofs + } + ) + made_substitutions = True + + if made_substitutions: + # substitute in topological order + subs = toposort_symbols( + dict(zip(self.sym("xdot"), self.eq("xdot"))) + ) + self._eqs["xdot"] = smart_subs_dict(self.eq("xdot"), subs) + + # replace rateOf-instances in x0 by xdot equation + for i_state in range(len(self.eq("x0"))): + if rate_ofs := self._eqs["x0"][i_state].find(rate_of_func): + self._eqs["x0"][i_state] = self._eqs["x0"][i_state].subs( + { + rate_of: get_rate(rate_of.args[0]) + for rate_of in rate_ofs + } + ) + + # replace rateOf-instances in w by xdot equation + # here we may need toposort, as xdot may depend on w + made_substitutions = False + for i_expr in range(len(self.eq("w"))): + if rate_ofs := self._eqs["w"][i_expr].find(rate_of_func): + self._eqs["w"][i_expr] = self._eqs["w"][i_expr].subs( + { + rate_of: get_rate(rate_of.args[0]) + for rate_of in rate_ofs + } + ) + made_substitutions = True + + if made_substitutions: + # Sort expressions in self._expressions, w symbols, and w equations + # in topological order. Ideally, this would already happen before + # adding the expressions to the model, but at that point, we don't + # have access to xdot yet. + # NOTE: elsewhere, conservations law expressions are expected to + # occur before any other w expressions, so we must maintain their + # position + # toposort everything but conservation law expressions, + # then prepend conservation laws + w_sorted = toposort_symbols( + dict( + zip( + self.sym("w")[self.num_cons_law() :, :], + self.eq("w")[self.num_cons_law() :, :], + ) + ) + ) + w_sorted = ( + dict( + zip( + self.sym("w")[: self.num_cons_law(), :], + self.eq("w")[: self.num_cons_law(), :], + ) + ) + | w_sorted + ) + old_syms = tuple(self._syms["w"]) + topo_expr_syms = tuple(w_sorted.keys()) + new_order = [old_syms.index(s) for s in topo_expr_syms] + self._expressions = [self._expressions[i] for i in new_order] + self._syms["w"] = sp.Matrix(topo_expr_syms) + self._eqs["w"] = sp.Matrix(list(w_sorted.values())) + + for component in chain( + self.observables(), + self.events(), + self._algebraic_equations, + ): + if rate_ofs := component.get_val().find(rate_of_func): + if isinstance(component, Event): + # TODO froot(...) can currently not depend on `w`, so this substitution fails for non-zero rates + # see, e.g., sbml test case 01293 + raise SBMLException( + "AMICI does currently not support rateOf(.) inside event trigger functions." + ) + + if isinstance(component, AlgebraicEquation): + # TODO IDACalcIC fails with + # "The linesearch algorithm failed: step too small or too many backtracks." + # see, e.g., sbml test case 01482 + raise SBMLException( + "AMICI does currently not support rateOf(.) inside AlgebraicRules." + ) + + component.set_val( + component.get_val().subs( + { + rate_of: get_rate(rate_of.args[0]) + for rate_of in rate_ofs + } + ) + ) + + for event in self.events(): + if event._state_update is None: + continue + + for i_state in range(len(event._state_update)): + if rate_ofs := event._state_update[i_state].find(rate_of_func): + raise SBMLException( + "AMICI does currently not support rateOf(.) inside event state updates." + ) + # TODO here we need xdot sym, not eqs + # event._state_update[i_state] = event._state_update[i_state].subs( + # {rate_of: get_rate(rate_of.args[0]) for rate_of in rate_ofs} + # ) + + def add_component( + self, component: ModelQuantity, insert_first: bool | None = False + ) -> None: + """ + Adds a new ModelQuantity to the model. + + :param component: + model quantity to be added + + :param insert_first: + whether to add quantity first or last, relevant when components + may refer to other components of the same type. + """ + if type(component) not in { + Observable, + Expression, + Parameter, + Constant, + DifferentialState, + AlgebraicState, + AlgebraicEquation, + LogLikelihoodY, + LogLikelihoodZ, + LogLikelihoodRZ, + SigmaY, + SigmaZ, + ConservationLaw, + Event, + EventObservable, + }: + raise ValueError(f"Invalid component type {type(component)}") + + component_list = getattr( + self, + "_" + + "_".join( + s.lower() + for s in re.split(r"([A-Z][^A-Z]+)", type(component).__name__) + if s + ) + + "s", + ) + if insert_first: + component_list.insert(0, component) + else: + component_list.append(component) - :param identifier: - unique identifier of the quantity + def add_conservation_law( + self, + state: sp.Symbol, + total_abundance: sp.Symbol, + coefficients: dict[sp.Symbol, sp.Expr], + ) -> None: + r""" + Adds a new conservation law to the model. A conservation law is defined + by the conserved quantity :math:`T = \sum_i(a_i * x_i)`, where + :math:`a_i` are coefficients and :math:`x_i` are different state + variables. - :param name: - individual name of the quantity (does not need to be unique) + :param state: + symbolic identifier of the state that should be replaced by + the conservation law (:math:`x_j`) - :param value: - either formula, numeric value or initial value - """ + :param total_abundance: + symbolic identifier of the total abundance (:math:`T/a_j`) - if not isinstance(identifier, sp.Symbol): - raise TypeError( - f"identifier must be sympy.Symbol, was " f"{type(identifier)}" + :param coefficients: + Dictionary of coefficients {x_i: a_i} + """ + try: + ix = next( + filter( + lambda is_s: is_s[1].get_id() == state, + enumerate(self._differential_states), + ) + )[0] + except StopIteration: + raise ValueError( + f"Specified state {state} was not found in the " + f"model states." ) - if str(identifier) in RESERVED_SYMBOLS or ( - hasattr(identifier, "name") and identifier.name in RESERVED_SYMBOLS - ): - raise ValueError( - f'Cannot add model quantity with name "{name}", ' - f"please rename." + state_id = self._differential_states[ix].get_id() + + # \sum_{i≠j}(a_i * x_i)/a_j + target_expression = ( + sp.Add( + *( + c_i * x_i + for x_i, c_i in coefficients.items() + if x_i != state + ) ) - self._identifier: sp.Symbol = identifier + / coefficients[state] + ) - if not isinstance(name, str): - raise TypeError(f"name must be str, was {type(name)}") + # x_j = T/a_j - \sum_{i≠j}(a_i * x_i)/a_j + state_expr = total_abundance - target_expression - self._name: str = name + # T/a_j = \sum_{i≠j}(a_i * x_i)/a_j + x_j + abundance_expr = target_expression + state_id - self._value: sp.Expr = cast_to_sym(value, "value") + self.add_component( + Expression(state_id, str(state_id), state_expr), insert_first=True + ) - def __repr__(self) -> str: - """ - Representation of the ModelQuantity object + cl = ConservationLaw( + total_abundance, + f"total_{state_id}", + abundance_expr, + coefficients, + state_id, + ) - :return: - string representation of the ModelQuantity + self.add_component(cl) + self._differential_states[ix].set_conservation_law(cl) + + def add_spline(self, spline: AbstractSpline, spline_expr: sp.Expr) -> None: + """Add a spline to the model. + + :param spline: + Spline instance to be added + :param spline_expr: + Sympy function representation of `spline` from + ``spline.ode_model_symbol()``. """ - return str(self._identifier) + self._splines.append(spline) + self.add_component( + Expression( + identifier=spline.sbml_id, + name=str(spline.sbml_id), + value=spline_expr, + ) + ) - def get_id(self) -> sp.Symbol: + def get_observable_transformations(self) -> list[ObservableTransformation]: """ - ModelQuantity identifier + List of observable transformations :return: - identifier of the ModelQuantity + list of transformations """ - return self._identifier + return [obs.trafo for obs in self._observables] - def get_name(self) -> str: + def num_states_rdata(self) -> int: """ - ModelQuantity name + Number of states. :return: - name of the ModelQuantity + number of state variable symbols """ - return self._name + return len(self.sym("x_rdata")) - def get_val(self) -> sp.Expr: + def num_states_solver(self) -> int: """ - ModelQuantity value + Number of states after applying conservation laws. :return: - value of the ModelQuantity + number of state variable symbols """ - return self._value + return len(self.sym("x")) - def set_val(self, val: sp.Expr): + def num_cons_law(self) -> int: """ - Set ModelQuantity value + Number of conservation laws. :return: - value of the ModelQuantity + number of conservation laws """ - self._value = cast_to_sym(val, "value") - + return self.num_states_rdata() - self.num_states_solver() -class ConservationLaw(ModelQuantity): - """ - A conservation law defines the absolute the total amount of a - (weighted) sum of states - - """ - - def __init__( - self, - identifier: sp.Symbol, - name: str, - value: sp.Expr, - coefficients: dict[sp.Symbol, sp.Expr], - state_id: sp.Symbol, - ): + def num_state_reinits(self) -> int: """ - Create a new ConservationLaw instance. + Number of solver states which would be reinitialized after + preequilibration - :param identifier: - unique identifier of the ConservationLaw + :return: + number of state variable symbols with reinitialization + """ + reinit_states = self.eq("x0_fixedParameters") + solver_states = self.eq("x_solver") + return sum(ix in solver_states for ix in reinit_states) - :param name: - individual name of the ConservationLaw (does not need to be - unique) + def num_obs(self) -> int: + """ + Number of Observables. - :param value: formula (sum of states) + :return: + number of observable symbols + """ + return len(self.sym("y")) - :param coefficients: - coefficients of the states in the sum + def num_eventobs(self) -> int: + """ + Number of Event Observables. - :param state_id: - identifier of the state that this conservation law replaces + :return: + number of event observable symbols """ - self._state_expr: sp.Symbol = identifier - (value - state_id) - self._coefficients: dict[sp.Symbol, sp.Expr] = coefficients - self._ncoeff: sp.Expr = coefficients[state_id] - super().__init__(identifier, name, value) + return len(self.sym("z")) - def get_ncoeff(self, state_id) -> Union[sp.Expr, int, float]: + def num_const(self) -> int: """ - Computes the normalized coefficient a_i/a_j where i is the index of - the provided state_id and j is the index of the state that is - replaced by this conservation law. This can be used to compute both - dtotal_cl/dx_rdata (=ncoeff) and dx_rdata/dx_solver (=-ncoeff). + Number of Constants. - :param state_id: - identifier of the state + :return: + number of constant symbols + """ + return len(self.sym("k")) - :return: normalized coefficent of the state + def num_par(self) -> int: """ - return self._coefficients.get(state_id, 0.0) / self._ncoeff + Number of Parameters. - def get_x_rdata(self): + :return: + number of parameter symbols """ - Returns the expression that allows computation of x_rdata for the state - that this conservation law replaces. + return len(self.sym("p")) - :return: x_rdata expression + def num_expr(self) -> int: """ - return self._state_expr + Number of Expressions. + :return: + number of expression symbols + """ + return len(self.sym("w")) -class AlgebraicEquation(ModelQuantity): - """ - An AlgebraicEquation defines an algebraic equation. - """ + def num_events(self) -> int: + """ + Total number of Events (those for which root-functions are added and those without). - def __init__(self, identifier: str, value: sp.Expr): + :return: + number of events """ - Create a new AlgebraicEquation instance. + return len(self.sym("h")) - :param value: - formula of the algebraic equation, solution is given by - ``formula == 0`` + def num_events_solver(self) -> int: """ - super().__init__(sp.Symbol(identifier), identifier, value) + Number of Events. - def get_free_symbols(self): - return self._value.free_symbols + :return: + number of event symbols (length of the root vector in AMICI) + """ + return sum( + not event.triggers_at_fixed_timepoint() for event in self.events() + ) - def __repr__(self): - return str(self._value) + def sym(self, name: str) -> sp.Matrix: + """ + Returns (and constructs if necessary) the identifiers for a symbolic + entity. + :param name: + name of the symbolic variable -class State(ModelQuantity): - """ - Base class for differential and algebraic model states - """ + :return: + matrix of symbolic identifiers + """ + if name not in self._syms: + self._generate_symbol(name) - _conservation_law: Optional[ConservationLaw] = None + return self._syms[name] - def get_x_rdata(self): + def sparsesym(self, name: str, force_generate: bool = True) -> list[str]: """ - Returns the expression that allows computation of x_rdata for this - state, accounting for conservation laws. + Returns (and constructs if necessary) the sparsified identifiers for + a sparsified symbolic variable. - :return: x_rdata expression - """ - if self._conservation_law is None: - return self.get_id() - else: - return self._conservation_law.get_x_rdata() + :param name: + name of the symbolic variable - def get_dx_rdata_dx_solver(self, state_id): - """ - Returns the expression that allows computation of - ``dx_rdata_dx_solver`` for this state, accounting for conservation - laws. + :param force_generate: + whether the symbols should be generated if not available - :return: dx_rdata_dx_solver expression + :return: + linearized Matrix containing the symbolic identifiers """ - if self._conservation_law is None: - return sp.Integer(self._identifier == state_id) - else: - return -self._conservation_law.get_ncoeff(state_id) + if name not in sparse_functions: + raise ValueError(f"{name} is not marked as sparse") + if name not in self._sparsesyms and force_generate: + self._generate_sparse_symbol(name) + return self._sparsesyms.get(name, []) - @abc.abstractmethod - def has_conservation_law(self): + def eq(self, name: str) -> sp.Matrix: """ - Checks whether this state has a conservation law assigned. + Returns (and constructs if necessary) the formulas for a symbolic + entity. - :return: True if assigned, False otherwise - """ - ... + :param name: + name of the symbolic variable + :return: + matrix of symbolic formulas + """ -class AlgebraicState(State): - """ - An AlgebraicState defines an entity that is algebraically determined - """ + if name not in self._eqs: + dec = log_execution_time(f"computing {name}", logger) + dec(self._compute_equation)(name) + return self._eqs[name] - def __init__(self, identifier: sp.Symbol, name: str, init: sp.Expr): + def sparseeq(self, name) -> sp.Matrix: """ - Create a new AlgebraicState instance. - - :param identifier: - unique identifier of the AlgebraicState + Returns (and constructs if necessary) the sparsified formulas for a + sparsified symbolic variable. :param name: - individual name of the AlgebraicState (does not need to be unique) + name of the symbolic variable - :param init: - initial value of the AlgebraicState - """ - super().__init__(identifier, name, init) - - def has_conservation_law(self): + :return: + linearized matrix containing the symbolic formulas """ - Checks whether this state has a conservation law assigned. + if name not in sparse_functions: + raise ValueError(f"{name} is not marked as sparse") + if name not in self._sparseeqs: + self._generate_sparse_symbol(name) + return self._sparseeqs[name] - :return: True if assigned, False otherwise + def colptrs(self, name: str) -> list[sp.Number] | list[list[sp.Number]]: """ - return False + Returns (and constructs if necessary) the column pointers for + a sparsified symbolic variable. - def get_free_symbols(self): - return self._value.free_symbols + :param name: + name of the symbolic variable - def get_x_rdata(self): - return self._identifier + :return: + list containing the column pointers + """ + if name not in sparse_functions: + raise ValueError(f"{name} is not marked as sparse") + if name not in self._sparseeqs: + self._generate_sparse_symbol(name) + return self._colptrs[name] + def rowvals(self, name: str) -> list[sp.Number] | list[list[sp.Number]]: + """ + Returns (and constructs if necessary) the row values for a + sparsified symbolic variable. -class DifferentialState(State): - """ - A State variable defines an entity that evolves with time according to - the provided time derivative, abbreviated by ``x``. + :param name: + name of the symbolic variable - :ivar _conservation_law: - algebraic formula that allows computation of this - state according to a conservation law + :return: + list containing the row values + """ + if name not in sparse_functions: + raise ValueError(f"{name} is not marked as sparse") + if name not in self._sparseeqs: + self._generate_sparse_symbol(name) + return self._rowvals[name] - :ivar _dt: - algebraic formula that defines the temporal derivative of this state + def val(self, name: str) -> list[sp.Number]: + """ + Returns (and constructs if necessary) the numeric values of a + symbolic entity - """ + :param name: + name of the symbolic variable - def __init__( - self, identifier: sp.Symbol, name: str, init: sp.Expr, dt: sp.Expr - ): + :return: + list containing the numeric values """ - Create a new State instance. Extends :meth:`ModelQuantity.__init__` - by ``dt`` + if name not in self._vals: + self._generate_value(name) + return self._vals[name] - :param identifier: - unique identifier of the state + def name(self, name: str) -> list[str]: + """ + Returns (and constructs if necessary) the names of a symbolic + variable :param name: - individual name of the state (does not need to be unique) - - :param init: - initial value + name of the symbolic variable - :param dt: - time derivative + :return: + list of names """ - super().__init__(identifier, name, init) - self._dt = cast_to_sym(dt, "dt") - self._conservation_law: Union[ConservationLaw, None] = None + if name not in self._names: + self._generate_name(name) + return self._names[name] - def set_conservation_law(self, law: ConservationLaw) -> None: + def free_symbols(self) -> set[sp.Basic]: + """ + Returns list of free symbols that appear in RHS and initial + conditions. """ - Sets the conservation law of a state. + return set( + chain.from_iterable( + state.get_free_symbols() for state in self.states() + ) + ) - If a conservation law is set, the respective state will be replaced by - an algebraic formula according to the respective conservation law. + def static_indices(self, name: str) -> list[int]: + """ + Returns the indices of static expressions in the given model entity. + + Static expressions are those that do not depend on time, + neither directly nor indirectly. + + :param name: Name of the model entity. + :return: List of indices of static expressions. + """ + # already computed? + if (res := self._static_indices.get(name)) is not None: + return res + + if name == "w": + dwdx = self.sym("dwdx") + dwdw = self.sym("dwdw") + w = self.eq("w") + + # Check for direct (via `t`) or indirect (via `x`, `h`, or splines) + # time dependency. + # To avoid lengthy symbolic computations, we only check if we have + # any non-zeros in hierarchy. We currently neglect the case where + # different hierarchy levels may cancel out. Treating a static + # expression as dynamic in such rare cases shouldn't be a problem. + dynamic_dependency = np.asarray( + dwdx.applyfunc(lambda x: int(not x.is_zero)) + ).astype(np.int64) + # to check for other time-dependence, we add a column to the dwdx + # matrix + dynamic_syms = [ + # FIXME: see spline comment below + # *self.sym("spl"), + *self.sym("h"), + amici_time_symbol, + ] + dynamic_dependency = np.hstack( + ( + dynamic_dependency, + np.array( + [ + expr.has(*dynamic_syms) + # FIXME: the current spline implementation is a giant pita + # currently, the splines occur in the form of sympy functions, e.g.: + # AmiciSpline(y0, time, y0_3, y0_1) + # AmiciSplineSensitivity(y0, time, y0_1, y0_3, y0_1) + # until it uses the proper self.sym("spl") / self.sym("sspl") + # symbols, which will require quite some refactoring, + # we just do dumb string checks :| + or ( + bool(self._splines) + and "AmiciSpline" in str(expr) + ) + for expr in w + ] + )[:, np.newaxis], + ) + ) - :param law: - linear sum of states that if added to this state remain - constant over time - """ - if not isinstance(law, ConservationLaw): - raise TypeError( - f"conservation law must have type ConservationLaw" - f", was {type(law)}" + nonzero_dwdw = np.asarray( + dwdw.applyfunc(lambda x: int(not x.is_zero)) + ).astype(np.int64) + + # `w` is made up an expression hierarchy. Any given entry is only + # static if all its dependencies are static. Here, we unravel + # the hierarchical structure of `w`. + # If for an entry in `w`, the row sum of the intermediate products + # is 0 across all levels, the expression is static. + tmp = dynamic_dependency + res = np.sum(tmp, axis=1) + while np.any(tmp != 0): + tmp = nonzero_dwdw.dot(tmp) + res += np.sum(tmp, axis=1) + self._static_indices[name] = ( + np.argwhere(res == 0).flatten().tolist() ) - self._conservation_law = law + return self._static_indices[name] + + if name in ("dwdw", "dwdx", "dwdp"): + static_indices_w = set(self.static_indices("w")) + dynamic_syms = [ + *( + sym + for i, sym in enumerate(self.sym("w")) + if i not in static_indices_w + ), + amici_time_symbol, + *self.sym("x"), + *self.sym("h"), + # FIXME see spline comment above + # *(self.sym("spl") if name in ("dwdw", "dwdx") else ()), + # *(self.sym("sspl") if name == "dwdp" else ()), + ] + dynamic_syms = sp.Matrix(dynamic_syms) + rowvals = self.rowvals(name) + sparseeq = self.sparseeq(name) + + # collect the indices of static expressions of dwd* from the list + # of non-zeros entries of the sparse matrix + self._static_indices[name] = [ + i + for i, (expr, row_idx) in enumerate(zip(sparseeq, rowvals)) + # derivative of a static expression is static + if row_idx in static_indices_w + # constant expressions + or expr.is_Number + # check for dependencies on non-static entities + or ( + # FIXME see spline comment above + # (check str before diff, as diff will fail on spline functions) + ( + # splines: non-static + not self._splines or "AmiciSpline" not in str(expr) + ) + and ( + # If the expression contains dynamic symbols, it might + # still be static. However, checking the derivative + # is currently too expensive, and we rather accept + # false negatives. + not expr.has(*dynamic_syms) + # or all( + # expr.diff(dyn_sym).is_zero + # for dyn_sym in dynamic_syms + # ) + ) + ) + ] + return self._static_indices[name] + + raise NotImplementedError(name) + + def dynamic_indices(self, name: str) -> list[int]: + """ + Return the indices of dynamic expressions in the given model entity. + + :param name: Name of the model entity. + :return: List of indices of dynamic expressions. + """ + static_idxs = set(self.static_indices(name)) + length = len( + self.sparsesym(name) + if name in sparse_functions + else self.sym(name) + ) + return [i for i in range(length) if i not in static_idxs] - def set_dt(self, dt: sp.Expr) -> None: + def _generate_symbol(self, name: str) -> None: """ - Sets the time derivative + Generates the symbolic identifiers for a symbolic variable - :param dt: - time derivative + :param name: + name of the symbolic variable """ - self._dt = cast_to_sym(dt, "dt") + if name in self._variable_prototype: + components = self._variable_prototype[name]() + self._syms[name] = sp.Matrix( + [comp.get_id() for comp in components] + ) + if name == "y": + self._syms["my"] = sp.Matrix( + [comp.get_measurement_symbol() for comp in components] + ) + if name == "z": + self._syms["mz"] = sp.Matrix( + [comp.get_measurement_symbol() for comp in components] + ) + self._syms["rz"] = sp.Matrix( + [comp.get_regularization_symbol() for comp in components] + ) + return + elif name == "x": + self._syms[name] = sp.Matrix( + [ + state.get_id() + for state in self.states() + if not state.has_conservation_law() + ] + ) + return + elif name == "xdot": + self._syms[name] = sp.Matrix( + [ + f"d{x.get_id()}dt" if self.is_ode() else f"de_{ix}" + for ix, x in enumerate(self._differential_states) + if not x.has_conservation_law() + ] + + [f"ae_{ix}" for ix in range(len(self._algebraic_equations))] + ) + return + elif name == "dx": + self._syms[name] = sp.Matrix( + [ + f"d{state.get_id()}dt" + for state in self.states() + if not state.has_conservation_law() + ] + ) + return + elif name == "sx0": + self._syms[name] = sp.Matrix( + [ + f"s{state.get_id()}_0" + for state in self.states() + if not state.has_conservation_law() + ] + ) + return + elif name == "sx_rdata": + self._syms[name] = sp.Matrix( + [f"sx_rdata_{i}" for i in range(len(self.states()))] + ) + return + elif name == "dtcldp": + # check, whether the CL consists of only one state. Then, + # sensitivities drop out, otherwise generate symbols + self._syms[name] = sp.Matrix( + [ + [ + sp.Symbol( + f"s{strip_pysb(tcl.get_id())}__" + f"{strip_pysb(par.get_id())}", + real=True, + ) + for par in self._parameters + ] + if self.conservation_law_has_multispecies(tcl) + else [0] * self.num_par() + for tcl in self._conservation_laws + ] + ) + return + elif name == "xdot_old": + length = len(self.eq("xdot")) + elif name in sparse_functions: + self._generate_sparse_symbol(name) + return + elif name in self._symboldim_funs: + length = self._symboldim_funs[name]() + elif name == "stau": + length = self.eq(name)[0].shape[1] + elif name in sensi_functions: + length = self.eq(name).shape[0] + elif name == "spl": + # placeholders for the numeric spline values. + # Need to create symbols + self._syms[name] = sp.Matrix( + [[f"spl_{isp}" for isp in range(len(self._splines))]] + ) + return + elif name == "sspl": + # placeholders for spline sensitivities. Need to create symbols + self._syms[name] = sp.Matrix( + [ + [f"sspl_{isp}_{ip}" for ip in range(len(self._syms["p"]))] + for isp in range(len(self._splines)) + ] + ) + return + else: + length = len(self.eq(name)) + self._syms[name] = sp.Matrix( + [ + sp.Symbol(f'{name}{0 if name == "stau" else i}', real=True) + for i in range(length) + ] + ) - def get_dt(self) -> sp.Expr: - """ - Gets the time derivative + def generate_basic_variables(self) -> None: + """ + Generates the symbolic identifiers for all variables in + ``DEModel._variable_prototype`` + """ + # We need to process events and Heaviside functions in the ``DEModel`, + # before adding it to DEExporter + self.parse_events() + + for var in self._variable_prototype: + if var not in self._syms: + self._generate_symbol(var) + # symbols for spline values need to be created in addition + for var in ["spl", "sspl"]: + self._generate_symbol(var) + + self._generate_symbol("x") + + def parse_events(self) -> None: + """ + This function checks the right-hand side for roots of Heaviside + functions or events, collects the roots, removes redundant roots, + and replaces the formulae of the found roots by identifiers of AMICI's + Heaviside function implementation in the right-hand side + """ + # Track all roots functions in the right-hand side + roots = copy.deepcopy(self._events) + for state in self._differential_states: + state.set_dt(self._process_heavisides(state.get_dt(), roots)) + + for expr in self._expressions: + expr.set_val(self._process_heavisides(expr.get_val(), roots)) + + # remove all possible Heavisides from roots, which may arise from + # the substitution of `'w'` in `_collect_heaviside_roots` + for root in roots: + root.set_val(self._process_heavisides(root.get_val(), roots)) + + # Now add the found roots to the model components + for root in roots: + # skip roots of SBML events, as these have already been added + if root in self._events: + continue + # add roots of heaviside functions + self.add_component(root) + + # re-order events - first those that require root tracking, then the others + self._events = list( + chain( + itertools.filterfalse( + Event.triggers_at_fixed_timepoint, self._events + ), + filter(Event.triggers_at_fixed_timepoint, self._events), + ) + ) - :return: - time derivative + def get_appearance_counts(self, idxs: list[int]) -> list[int]: """ - return self._dt + Counts how often a state appears in the time derivative of + another state and expressions for a subset of states - def get_free_symbols(self) -> set[sp.Basic]: - """ - Gets the set of free symbols in time derivative and initial conditions + :param idxs: + list of state indices for which counts are to be computed :return: - free symbols + list of counts for the states ordered according to the provided + indices """ - return self._dt.free_symbols.union(self._value.free_symbols) + free_symbols_dt = list( + itertools.chain.from_iterable( + [str(symbol) for symbol in state.get_dt().free_symbols] + for state in self.states() + ) + ) - def has_conservation_law(self): - """ - Checks whether this state has a conservation law assigned. + free_symbols_expr = list( + itertools.chain.from_iterable( + [str(symbol) for symbol in expr.get_val().free_symbols] + for expr in self._expressions + ) + ) + + return [ + free_symbols_dt.count(str(self._differential_states[idx].get_id())) + + free_symbols_expr.count( + str(self._differential_states[idx].get_id()) + ) + for idx in idxs + ] - :return: True if assigned, False otherwise + def _generate_sparse_symbol(self, name: str) -> None: """ - return self._conservation_law is not None + Generates the sparse symbolic identifiers, symbolic identifiers, + sparse equations, column pointers and row values for a symbolic + variable + :param name: + name of the symbolic variable + """ + matrix = self.eq(name) + + if match_deriv := DERIVATIVE_PATTERN.match(name): + eq = match_deriv[1] + var = match_deriv[2] + + rownames = self.sym(eq) + colnames = self.sym(var) + + if name == "dJydy": + # One entry per y-slice + self._colptrs[name] = [] + self._rowvals[name] = [] + self._sparseeqs[name] = [] + self._sparsesyms[name] = [] + self._syms[name] = [] + + for iy in range(self.num_obs()): + ( + symbol_col_ptrs, + symbol_row_vals, + sparse_list, + symbol_list, + sparse_matrix, + ) = csc_matrix( + matrix[iy, :], + rownames=rownames, + colnames=colnames, + identifier=iy, + ) + self._colptrs[name].append(symbol_col_ptrs) + self._rowvals[name].append(symbol_row_vals) + self._sparseeqs[name].append(sparse_list) + self._sparsesyms[name].append(symbol_list) + self._syms[name].append(sparse_matrix) + else: + ( + symbol_col_ptrs, + symbol_row_vals, + sparse_list, + symbol_list, + sparse_matrix, + ) = csc_matrix( + matrix, + rownames=rownames, + colnames=colnames, + pattern_only=name in nobody_functions, + ) -class Observable(ModelQuantity): - """ - An Observable links model simulations to experimental measurements, - abbreviated by ``y``. + self._colptrs[name] = symbol_col_ptrs + self._rowvals[name] = symbol_row_vals + self._sparseeqs[name] = sparse_list + self._sparsesyms[name] = symbol_list + self._syms[name] = sparse_matrix - :ivar _measurement_symbol: - sympy symbol used in the objective function to represent - measurements to this observable + def _compute_equation(self, name: str) -> None: + """ + Computes the symbolic formula for a symbolic variable - :ivar trafo: - observable transformation, only applies when evaluating objective - function or residuals - """ + :param name: + name of the symbolic variable + """ + # replacement ensures that we don't have to adapt name in abstract + # model and keep backwards compatibility with matlab + match_deriv = DERIVATIVE_PATTERN.match( + re.sub(r"dJ(y|z|rz)dsigma", r"dJ\1dsigma\1", name) + .replace("sigmarz", "sigmaz") + .replace("dJrzdz", "dJrzdrz") + ) + time_symbol = sp.Matrix([amici_time_symbol]) - _measurement_symbol: Union[sp.Symbol, None] = None + if name in self._equation_prototype: + self._equation_from_components( + name, self._equation_prototype[name]() + ) - def __init__( - self, - identifier: sp.Symbol, - name: str, - value: sp.Expr, - measurement_symbol: Optional[sp.Symbol] = None, - transformation: Optional[ - ObservableTransformation - ] = ObservableTransformation.LIN, - ): - """ - Create a new Observable instance. + elif name in self._total_derivative_prototypes: + args = self._total_derivative_prototypes[name] + args["name"] = name + self._lock_total_derivative += args["chainvars"] + self._total_derivative(**args) + for cv in args["chainvars"]: + self._lock_total_derivative.remove(cv) + + elif name == "xdot": + if self.is_ode(): + self._eqs[name] = sp.Matrix( + [ + state.get_dt() + for state in self._differential_states + if not state.has_conservation_law() + ] + ) + else: + self._eqs[name] = sp.Matrix( + [ + x.get_dt() - dx + for x, dx in zip( + ( + s + for s in self._differential_states + if not s.has_conservation_law() + ), + self.sym("dx"), + ) + ] + + [eq.get_val() for eq in self._algebraic_equations] + ) + + elif name == "x_rdata": + self._eqs[name] = sp.Matrix( + [state.get_x_rdata() for state in self.states()] + ) - :param identifier: - unique identifier of the Observable + elif name == "x_solver": + self._eqs[name] = sp.Matrix( + [ + state.get_id() + for state in self.states() + if not state.has_conservation_law() + ] + ) - :param name: - individual name of the Observable (does not need to be unique) + elif name == "sx_solver": + self._eqs[name] = sp.Matrix( + [ + self.sym("sx_rdata")[ix] + for ix, state in enumerate(self.states()) + if not state.has_conservation_law() + ] + ) - :param value: - formula + elif name == "sx0": + self._derivative(name[1:], "p", name=name) + + elif name == "sx0_fixedParameters": + # deltax = -x+x0_fixedParameters if x0_fixedParameters>0 else 0 + # deltasx = -sx+dx0_fixed_parametersdx*sx+dx0_fixedParametersdp + # if x0_fixedParameters>0 else 0 + # sx0_fixedParameters = sx+deltasx = + # dx0_fixed_parametersdx*sx+dx0_fixedParametersdp + self._eqs[name] = smart_jacobian( + self.eq("x0_fixedParameters"), self.sym("p") + ) - :param transformation: - observable transformation, only applies when evaluating objective - function or residuals - """ - super().__init__(identifier, name, value) - self._measurement_symbol = measurement_symbol - self._regularization_symbol = None - self.trafo = transformation + dx0_fixed_parametersdx = smart_jacobian( + self.eq("x0_fixedParameters"), self.sym("x") + ) - def get_measurement_symbol(self) -> sp.Symbol: - if self._measurement_symbol is None: - self._measurement_symbol = generate_measurement_symbol( - self.get_id() + if not smart_is_zero_matrix(dx0_fixed_parametersdx): + if isinstance(self._eqs[name], ImmutableDenseMatrix): + self._eqs[name] = MutableDenseMatrix(self._eqs[name]) + tmp = smart_multiply(dx0_fixed_parametersdx, self.sym("sx0")) + for ip in range(self._eqs[name].shape[1]): + self._eqs[name][:, ip] += tmp + + elif name == "x0_fixedParameters": + k = self.sym("k") + self._x0_fixedParameters_idx = [ + ix + for ix, eq in enumerate(self.eq("x0")) + if any(sym in eq.free_symbols for sym in k) + ] + eq = self.eq("x0") + self._eqs[name] = sp.Matrix( + [eq[ix] for ix in self._x0_fixedParameters_idx] ) - return self._measurement_symbol + elif name == "dtotal_cldx_rdata": + x_rdata = self.sym("x_rdata") + self._eqs[name] = sp.Matrix( + [ + [cl.get_ncoeff(xr) for xr in x_rdata] + for cl in self._conservation_laws + ] + ) - def get_regularization_symbol(self) -> sp.Symbol: - if self._regularization_symbol is None: - self._regularization_symbol = generate_regularization_symbol( - self.get_id() + elif name == "dtcldx": + # this is always zero + self._eqs[name] = sp.zeros( + self.num_cons_law(), self.num_states_solver() ) - return self._regularization_symbol + elif name == "dtcldp": + # force symbols + self._eqs[name] = self.sym(name) + + elif name == "dx_rdatadx_solver": + if self.num_cons_law(): + x_solver = self.sym("x") + self._eqs[name] = sp.Matrix( + [ + [state.get_dx_rdata_dx_solver(xs) for xs in x_solver] + for state in self.states() + ] + ) + else: + # so far, dx_rdatadx_solver is only required for sx_rdata + # in case of no conservation laws, C++ code will directly use + # sx, we don't need this + self._eqs[name] = sp.zeros( + self.num_states_rdata(), self.num_states_solver() + ) + + elif name == "dx_rdatadp": + if self.num_cons_law(): + self._eqs[name] = smart_jacobian( + self.eq("x_rdata"), self.sym("p") + ) + else: + # so far, dx_rdatadp is only required for sx_rdata + # in case of no conservation laws, C++ code will directly use + # sx, we don't need this + self._eqs[name] = sp.zeros( + self.num_states_rdata(), self.num_par() + ) + + elif name == "dx_rdatadtcl": + self._eqs[name] = smart_jacobian( + self.eq("x_rdata"), self.sym("tcl") + ) + elif name == "dxdotdx_explicit": + # force symbols + self._derivative("xdot", "x", name=name) -class EventObservable(Observable): - """ - An Event Observable links model simulations to event related experimental - measurements, abbreviated by ``z``. + elif name == "dxdotdp_explicit": + # force symbols + self._derivative("xdot", "p", name=name) - :ivar _event: - symbolic event identifier - """ + elif name == "spl": + self._eqs[name] = self.sym(name) - def __init__( - self, - identifier: sp.Symbol, - name: str, - value: sp.Expr, - event: sp.Symbol, - measurement_symbol: Optional[sp.Symbol] = None, - transformation: Optional[ObservableTransformation] = "lin", - ): - """ - Create a new EventObservable instance. + elif name == "sspl": + # force symbols + self._eqs[name] = self.sym(name) - :param identifier: - See :py:meth:`Observable.__init__`. + elif name == "spline_values": + # force symbols + self._eqs[name] = sp.Matrix( + [y for spline in self._splines for y in spline.values_at_nodes] + ) - :param name: - See :py:meth:`Observable.__init__`. + elif name == "spline_slopes": + # force symbols + self._eqs[name] = sp.Matrix( + [ + d + for spline in self._splines + for d in ( + sp.zeros(len(spline.derivatives_at_nodes), 1) + if spline.derivatives_by_fd + else spline.derivatives_at_nodes + ) + ] + ) - :param value: - See :py:meth:`Observable.__init__`. + elif name == "drootdt": + self._eqs[name] = smart_jacobian(self.eq("root"), time_symbol) + + elif name == "drootdt_total": + # backsubstitution of optimized right-hand side terms into RHS + # calling subs() is costly. Due to looping over events though, the + # following lines are only evaluated if a model has events + w_sorted = toposort_symbols(dict(zip(self.sym("w"), self.eq("w")))) + tmp_xdot = smart_subs_dict(self.eq("xdot"), w_sorted) + self._eqs[name] = self.eq("drootdt") + if self.num_states_solver(): + self._eqs[name] += smart_multiply(self.eq("drootdx"), tmp_xdot) + + elif name == "deltax": + # fill boluses for Heaviside functions, as empty state updates + # would cause problems when writing the function file later + event_eqs = [] + for event in self._events: + if event._state_update is None: + event_eqs.append(sp.zeros(self.num_states_solver(), 1)) + else: + event_eqs.append(event._state_update) + + self._eqs[name] = event_eqs + + elif name == "z": + event_observables = [ + sp.zeros(self.num_eventobs(), 1) for _ in self._events + ] + event_ids = [e.get_id() for e in self._events] + # TODO: get rid of this stupid 1-based indexing as soon as we can + # the matlab interface + z2event = [ + event_ids.index(event_obs.get_event()) + 1 + for event_obs in self._event_observables + ] + for (iz, ie), event_obs in zip( + enumerate(z2event), self._event_observables + ): + event_observables[ie - 1][iz] = event_obs.get_val() + + self._eqs[name] = event_observables + self._z2event = z2event + + elif name in ["ddeltaxdx", "ddeltaxdp", "ddeltaxdt", "dzdp", "dzdx"]: + if match_deriv[2] == "t": + var = time_symbol + else: + var = self.sym(match_deriv[2]) + + self._eqs[name] = [ + smart_jacobian(self.eq(match_deriv[1])[ie], var) + for ie in range(self.num_events()) + ] + if name == "dzdx": + for ie in range(self.num_events()): + dtaudx = ( + -self.eq("drootdx")[ie, :] + / self.eq("drootdt_total")[ie] + ) + for iz in range(self.num_eventobs()): + if ie != self._z2event[iz] - 1: + continue + dzdt = sp.diff(self.eq("z")[ie][iz], time_symbol) + self._eqs[name][ie][iz, :] += dzdt * dtaudx + + elif name in ["rz", "drzdx", "drzdp"]: + eq_events = [] + for ie in range(self.num_events()): + val = sp.zeros( + self.num_eventobs(), + 1 if name == "rz" else len(self.sym(match_deriv[2])), + ) + # match event observables to root function + for iz in range(self.num_eventobs()): + if ie == self._z2event[iz] - 1: + val[iz, :] = self.eq(name.replace("rz", "root"))[ie, :] + eq_events.append(val) + + self._eqs[name] = eq_events + + elif name == "stau": + self._eqs[name] = [ + -self.eq("sroot")[ie, :] / self.eq("drootdt_total")[ie] + if not self.eq("drootdt_total")[ie].is_zero + else sp.zeros(*self.eq("sroot")[ie, :].shape) + for ie in range(self.num_events()) + ] + + elif name == "deltasx": + if self.num_states_solver() * self.num_par() == 0: + self._eqs[name] = [] + return + + event_eqs = [] + for ie, event in enumerate(self._events): + tmp_eq = sp.zeros(self.num_states_solver(), self.num_par()) + + # need to check if equations are zero since we are using + # symbols + if not smart_is_zero_matrix( + self.eq("stau")[ie] + ) and not smart_is_zero_matrix(self.eq("xdot")): + tmp_eq += smart_multiply( + self.sym("xdot_old") - self.sym("xdot"), + self.sym("stau").T, + ) + + # only add deltax part if there is state update + if event._state_update is not None: + # partial derivative for the parameters + tmp_eq += self.eq("ddeltaxdp")[ie] + + # initial part of chain rule state variables + tmp_dxdp = self.sym("sx") * sp.ones(1, self.num_par()) + + # need to check if equations are zero since we are using + # symbols + if not smart_is_zero_matrix(self.eq("stau")[ie]): + # chain rule for the time point + tmp_eq += smart_multiply( + self.eq("ddeltaxdt")[ie], self.sym("stau").T + ) + + # additional part of chain rule state variables + tmp_dxdp += smart_multiply( + self.sym("xdot_old"), self.sym("stau").T + ) + + # finish chain rule for the state variables + tmp_eq += smart_multiply( + self.eq("ddeltaxdx")[ie], tmp_dxdp + ) + + event_eqs.append(tmp_eq) + + self._eqs[name] = event_eqs + + elif name == "xdot_old": + # force symbols + self._eqs[name] = self.sym(name) + + elif name == "dwdx": + if ( + expected := list( + map( + ConservationLaw.get_x_rdata, + reversed(self.conservation_laws()), + ) + ) + ) != (actual := self.eq("w")[: self.num_cons_law()]): + raise AssertionError( + "Conservation laws are not at the beginning of 'w'. " + f"Got {actual}, expected {expected}." + ) + x = self.sym("x") + self._eqs[name] = sp.Matrix( + [ + [-cl.get_ncoeff(xs) for xs in x] + # the insert first in ode_model._add_conservation_law() means + # that we need to reverse the order here + for cl in reversed(self._conservation_laws) + ] + ).col_join( + smart_jacobian(self.eq("w")[self.num_cons_law() :, :], x) + ) - :param transformation: - See :py:meth:`Observable.__init__`. + elif match_deriv: + self._derivative(match_deriv[1], match_deriv[2], name) - :param event: - Symbolic identifier of the corresponding event. - """ - super().__init__( - identifier, name, value, measurement_symbol, transformation - ) - self._event: sp.Symbol = event + else: + raise ValueError(f"Unknown equation {name}") + + if name in ("sigmay", "sigmaz"): + # check for states in sigma{y,z}, which is currently not supported + syms_x = self.sym("x") + syms_yz = self.sym(name.removeprefix("sigma")) + xs_in_sigma = {} + for sym_yz, eq_yz in zip(syms_yz, self._eqs[name]): + yz_free_syms = eq_yz.free_symbols + if tmp := {x for x in syms_x if x in yz_free_syms}: + xs_in_sigma[sym_yz] = tmp + if xs_in_sigma: + msg = ", ".join( + [f"{yz} depends on {xs}" for yz, xs in xs_in_sigma.items()] + ) + raise NotImplementedError( + f"State-dependent observables are not supported, but {msg}." + ) + + if name == "root": + # Events are processed after the model has been set up. + # Equations are there, but symbols for roots must be added + self.sym("h") + + if name in {"Jy", "dydx"}: + # do not transpose if we compute the partial derivative as part of + # a total derivative + if not len(self._lock_total_derivative): + self._eqs[name] = self._eqs[name].transpose() + + if name in {"dzdx", "drzdx"}: + self._eqs[name] = [e.T for e in self._eqs[name]] + + if self._simplify: + dec = log_execution_time(f"simplifying {name}", logger) + if isinstance(self._eqs[name], list): + self._eqs[name] = [ + dec(_parallel_applyfunc)(sub_eq, self._simplify) + for sub_eq in self._eqs[name] + ] + else: + self._eqs[name] = dec(_parallel_applyfunc)( + self._eqs[name], self._simplify + ) + + def sym_names(self) -> list[str]: + """ + Returns a list of names of generated symbolic variables - def get_event(self) -> sp.Symbol: + :return: + list of names """ - Get the symbolic identifier of the corresponding event. + return list(self._syms.keys()) - :return: symbolic identifier + def _derivative(self, eq: str, var: str, name: str = None) -> None: """ - return self._event + Creates a new symbolic variable according to a derivative + :param eq: + name of the symbolic variable that defines the formula -class Sigma(ModelQuantity): - """ - A Standard Deviation Sigma rescales the distance between simulations - and measurements when computing residuals or objective functions, - abbreviated by ``sigma{y,z}``. - """ + :param var: + name of the symbolic variable that defines the identifiers + with respect to which the derivatives are to be computed - def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): + :param name: + name of resulting symbolic variable, default is ``d{eq}d{var}`` + """ + if not name: + name = f"d{eq}d{var}" + + ignore_chainrule = { + ("xdot", "p"): "w", # has generic implementation in c++ code + ("xdot", "x"): "w", # has generic implementation in c++ code + ("w", "w"): "tcl", # dtcldw = 0 + ("w", "x"): "tcl", # dtcldx = 0 + } + # automatically detect chainrule + chainvars = [ + cv + for cv in ["w", "tcl"] + if var_in_function_signature(eq, cv, self.is_ode()) + and cv not in self._lock_total_derivative + and var != cv + and min(self.sym(cv).shape) + and ( + (eq, var) not in ignore_chainrule + or ignore_chainrule[(eq, var)] != cv + ) + ] + if len(chainvars): + self._lock_total_derivative += chainvars + self._total_derivative(name, eq, chainvars, var) + for cv in chainvars: + self._lock_total_derivative.remove(cv) + return + + # partial derivative + sym_eq = self.eq(eq).transpose() if eq == "Jy" else self.eq(eq) + + sym_var = self.sym(var) + + derivative = smart_jacobian(sym_eq, sym_var) + + self._eqs[name] = derivative + + # compute recursion depth based on nilpotency of jacobian. computing + # nilpotency can be done more efficiently on numerical sparsity pattern + if name == "dwdw": + nonzeros = np.asarray( + derivative.applyfunc(lambda x: int(not x.is_zero)) + ).astype(np.int64) + recursion = nonzeros.copy() + if max(recursion.shape): + while recursion.max(): + recursion = recursion.dot(nonzeros) + self._w_recursion_depth += 1 + if self._w_recursion_depth > len(sym_eq): + raise RuntimeError( + "dwdw is not nilpotent. Something, somewhere went " + "terribly wrong. Please file a bug report at " + "https://github.com/AMICI-dev/AMICI/issues and " + "attach this model." + ) + + if name == "dydw" and not smart_is_zero_matrix(derivative): + dwdw = self.eq("dwdw") + # h(k) = d{eq}dw*dwdw^k* (k=1) + h = smart_multiply(derivative, dwdw) + while not smart_is_zero_matrix(h): + self._eqs[name] += h + # h(k+1) = d{eq}dw*dwdw^(k+1) = h(k)*dwdw + h = smart_multiply(h, dwdw) + + def _total_derivative( + self, + name: str, + eq: str, + chainvars: list[str], + var: str, + dydx_name: str = None, + dxdz_name: str = None, + ) -> None: """ - Create a new Standard Deviation instance. + Creates a new symbolic variable according to a total derivative + using the chain rule - :param identifier: - unique identifier of the Standard Deviation + :param name: + name of resulting symbolic variable + + :param eq: + name of the symbolic variable that defines the formula + + :param chainvars: + names of the symbolic variable that define the + identifiers with respect to which the chain rules are applied + + :param var: + name of the symbolic variable that defines the identifiers + with respect to which the derivatives are to be computed + + :param dydx_name: + defines the name of the symbolic variable that + defines the derivative of the ``eq`` with respect to ``chainvar``, + default is ``d{eq}d{chainvar}`` + + :param dxdz_name: + defines the name of the symbolic variable that + defines the derivative of the ``chainvar`` with respect to ``var``, + default is d{chainvar}d{var} + """ + # compute total derivative according to chainrule + # Dydz = dydx*dxdz + dydz + + # initialize with partial derivative dydz without chain rule + self._eqs[name] = self.sym_or_eq(name, f"d{eq}d{var}") + if not isinstance(self._eqs[name], sp.Symbol): + # if not a Symbol, create a copy using sympy API + # NB deepcopy does not work safely, see sympy issue #7672 + self._eqs[name] = self._eqs[name].copy() + + for chainvar in chainvars: + if dydx_name is None: + dydx_name = f"d{eq}d{chainvar}" + if dxdz_name is None: + dxdz_name = f"d{chainvar}d{var}" + + dydx = self.sym_or_eq(name, dydx_name) + dxdz = self.sym_or_eq(name, dxdz_name) + # Save time for large models if one multiplicand is zero, + # which is not checked for by sympy + if not smart_is_zero_matrix(dydx) and not smart_is_zero_matrix( + dxdz + ): + dydx_times_dxdz = smart_multiply(dydx, dxdz) + if ( + dxdz.shape[1] == 1 + and self._eqs[name].shape[1] != dxdz.shape[1] + ): + for iz in range(self._eqs[name].shape[1]): + self._eqs[name][:, iz] += dydx_times_dxdz + else: + self._eqs[name] += dydx_times_dxdz + + def sym_or_eq(self, name: str, varname: str) -> sp.Matrix: + """ + Returns symbols or equations depending on whether a given + variable appears in the function signature or not. :param name: - individual name of the Standard Deviation (does not need to - be unique) + name of function for which the signature should be checked - :param value: - formula - """ - if self.__class__.__name__ == "Sigma": - raise RuntimeError( - "This class is meant to be sub-classed, not used directly." - ) - super().__init__(identifier, name, value) + :param varname: + name of the variable which should be contained in the + function signature + :return: + the variable symbols if the variable is part of the signature and + the variable equations otherwise. + """ + # dwdx and dwdp will be dynamically computed and their ordering + # within a column may differ from the initialization of symbols here, + # so those are not safe to use. Not removing them from signature as + # this would break backwards compatibility. + if var_in_function_signature( + name, varname, self.is_ode() + ) and varname not in [ + "dwdx", + "dwdp", + ]: + return self.sym(varname) + else: + return self.eq(varname) -class SigmaY(Sigma): - """ - Standard deviation for observables - """ + def _multiplication( + self, + name: str, + x: str, + y: str, + transpose_x: bool | None = False, + sign: int | None = 1, + ): + """ + Creates a new symbolic variable according to a multiplication + :param name: + name of resulting symbolic variable, default is ``d{eq}d{var}`` -class SigmaZ(Sigma): - """ - Standard deviation for event observables - """ + :param x: + name of the symbolic variable that defines the first factor + :param y: + name of the symbolic variable that defines the second factor -class Expression(ModelQuantity): - """ - An Expression is a recurring elements in symbolic formulas. Specifying - this may yield more compact expression which may lead to substantially - shorter model compilation times, but may also reduce model simulation time. - Abbreviated by ``w``. - """ + :param transpose_x: + indicates whether the first factor should be + transposed before multiplication - def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): + :param sign: + defines the sign of the product, should be +1 or -1 """ - Create a new Expression instance. - - :param identifier: - unique identifier of the Expression + if sign not in [-1, 1]: + raise TypeError(f"sign must be +1 or -1, was {sign}") - :param name: - individual name of the Expression (does not need to be unique) - - :param value: - formula - """ - super().__init__(identifier, name, value) + variables = { + varname: self.sym(varname) + if var_in_function_signature(name, varname, self.is_ode()) + else self.eq(varname) + for varname in [x, y] + } + xx = variables[x].transpose() if transpose_x else variables[x] + yy = variables[y] -class Parameter(ModelQuantity): - """ - A Parameter is a free variable in the model with respect to which - sensitivities may be computed, abbreviated by ``p``. - """ + self._eqs[name] = sign * smart_multiply(xx, yy) - def __init__( - self, identifier: sp.Symbol, name: str, value: numbers.Number - ): + def _equation_from_components( + self, name: str, components: list[ModelQuantity] + ) -> None: """ - Create a new Expression instance. - - :param identifier: - unique identifier of the Parameter + Generates the formulas of a symbolic variable from the attributes :param name: - individual name of the Parameter (does not need to be - unique) + name of resulting symbolic variable - :param value: - numeric value + :param component: + name of the attribute """ - super().__init__(identifier, name, value) + self._eqs[name] = sp.Matrix([comp.get_val() for comp in components]) + def get_conservation_laws(self) -> list[tuple[sp.Symbol, sp.Expr]]: + """Returns a list of states with conservation law set -class Constant(ModelQuantity): - """ - A Constant is a fixed variable in the model with respect to which - sensitivities cannot be computed, abbreviated by ``k``. - """ - - def __init__( - self, identifier: sp.Symbol, name: str, value: numbers.Number - ): + :return: + list of state identifiers """ - Create a new Expression instance. + return [ + (state.get_id(), state.get_x_rdata()) + for state in self.states() + if state.has_conservation_law() + ] - :param identifier: - unique identifier of the Constant + def _generate_value(self, name: str) -> None: + """ + Generates the numeric values of a symbolic variable from value + prototypes :param name: - individual name of the Constant (does not need to be unique) - - :param value: - numeric value + name of resulting symbolic variable """ - super().__init__(identifier, name, value) + if name in self._value_prototype: + components = self._value_prototype[name]() + else: + raise ValueError(f"No values for {name}") + self._vals[name] = [comp.get_val() for comp in components] -class LogLikelihood(ModelQuantity): - """ - A LogLikelihood defines the distance between measurements and - experiments for a particular observable. The final LogLikelihood value - in the simulation will be the sum of all specified LogLikelihood - instances evaluated at all timepoints, abbreviated by ``Jy``. - """ - - def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): + def _generate_name(self, name: str) -> None: """ - Create a new Expression instance. - - :param identifier: - unique identifier of the LogLikelihood + Generates the names of a symbolic variable from variable prototypes or + equation prototypes :param name: - individual name of the LogLikelihood (does not need to be - unique) - - :param value: - formula + name of resulting symbolic variable """ - if self.__class__.__name__ == "LogLikelihood": - raise RuntimeError( - "This class is meant to be sub-classed, not used directly." - ) - super().__init__(identifier, name, value) - - -class LogLikelihoodY(LogLikelihood): - """ - Loglikelihood for observables - """ + if name in self._variable_prototype: + components = self._variable_prototype[name]() + elif name in self._equation_prototype: + components = self._equation_prototype[name]() + else: + raise ValueError(f"No names for {name}") + self._names[name] = [comp.get_name() for comp in components] -class LogLikelihoodZ(LogLikelihood): - """ - Loglikelihood for event observables - """ + def state_has_fixed_parameter_initial_condition(self, ix: int) -> bool: + """ + Checks whether the state at specified index has a fixed parameter + initial condition + :param ix: + state index -class LogLikelihoodRZ(LogLikelihood): - """ - Loglikelihood for event observables regularization - """ + :return: + boolean indicating if any of the initial condition free + variables is contained in the model constants + """ + ic = self.states()[ix].get_val() + if not isinstance(ic, sp.Basic): + return False + return any( + fp in (c.get_id() for c in self._constants) + for fp in ic.free_symbols + ) + def state_has_conservation_law(self, ix: int) -> bool: + """ + Checks whether the state at specified index has a conservation + law set -class Event(ModelQuantity): - """ - An Event defines either a SBML event or a root of the argument of a - Heaviside function. The Heaviside functions will be tracked via the - vector ``h`` during simulation and are needed to inform the solver - about a discontinuity in either the right-hand side or the states - themselves, causing a reinitialization of the solver. - """ + :param ix: + state index - def __init__( - self, - identifier: sp.Symbol, - name: str, - value: sp.Expr, - state_update: Union[sp.Expr, None], - initial_value: Optional[bool] = True, - ): + :return: + boolean indicating if conservation_law is not None """ - Create a new Event instance. + return self.states()[ix].has_conservation_law() - :param identifier: - unique identifier of the Event + def get_solver_indices(self) -> dict[int, int]: + """ + Returns a mapping that maps rdata species indices to solver indices - :param name: - individual name of the Event (does not need to be unique) + :return: + dictionary mapping rdata species indices to solver indices + """ + solver_index = {} + ix_solver = 0 + for ix in range(len(self.states())): + if self.state_has_conservation_law(ix): + continue + solver_index[ix] = ix_solver + ix_solver += 1 + return solver_index - :param value: - formula for the root / trigger function + def state_is_constant(self, ix: int) -> bool: + """ + Checks whether the temporal derivative of the state is zero - :param state_update: - formula for the bolus function (None for Heaviside functions, - zero vector for events without bolus) + :param ix: + state index - :param initial_value: - initial boolean value of the trigger function at t0. If set to - `False`, events may trigger at ``t==t0``, otherwise not. + :return: + boolean indicating if constant over time """ - super().__init__(identifier, name, value) - # add the Event specific components - self._state_update = state_update - self._initial_value = initial_value + state = self.states()[ix] + if isinstance(state, AlgebraicState): + return False - # expression(s) for the timepoint(s) at which the event triggers - self._t_root = sp.solve(self.get_val(), amici_time_symbol) + return state.get_dt().is_zero - def get_initial_value(self) -> bool: + def conservation_law_has_multispecies(self, tcl: ConservationLaw) -> bool: """ - Return the initial value for the root function. + Checks whether a conservation law has multiple species or it just + defines one constant species + + :param tcl: + conservation law :return: - initial value formula + boolean indicating if conservation_law is not None """ - return self._initial_value + state_set = set(self.sym("x_rdata")) + n_species = len(state_set.intersection(tcl.get_val().free_symbols)) + return n_species > 1 - def __eq__(self, other): - """ - Check equality of events at the level of trigger/root functions, as we - need to collect unique root functions for ``roots.cpp`` + def _expr_is_time_dependent(self, expr: sp.Expr) -> bool: + """Determine whether an expression is time-dependent. + + :param expr: + The expression. + + :returns: + Whether the expression is time-dependent. """ - return self.get_val() == other.get_val() and ( - self.get_initial_value() == other.get_initial_value() - ) + # `expr.free_symbols` will be different to `self._states.keys()`, so + # it's easier to compare as `str`. + expr_syms = {str(sym) for sym in expr.free_symbols} - def triggers_at_fixed_timepoint(self) -> bool: - """Check whether the event triggers at a (single) fixed time-point.""" - if len(self._t_root) != 1: - return False - return self._t_root[0].is_Number + # Check if the time variable is in the expression. + if "t" in expr_syms: + return True - def get_trigger_time(self) -> sp.Float: - """Get the time at which the event triggers. + # Check if any time-dependent states are in the expression. + state_syms = [str(sym) for sym in self.states()] + return any( + not self.state_is_constant(state_syms.index(state)) + for state in expr_syms.intersection(state_syms) + ) - Only for events that trigger at a single fixed time-point. - """ - if not self.triggers_at_fixed_timepoint(): - raise NotImplementedError( - "This event does not trigger at a fixed timepoint." + def _get_unique_root( + self, + root_found: sp.Expr, + roots: list[Event], + ) -> sp.Symbol | None: + """ + Collects roots of Heaviside functions and events and stores them in + the roots list. It checks for redundancy to not store symbolically + equivalent root functions more than once. + + :param root_found: + equation of the root function + :param roots: + list of already known root functions with identifier + + :returns: + unique identifier for root, or ``None`` if the root is not + time-dependent + """ + if not self._expr_is_time_dependent(root_found): + return None + + for root in roots: + if sp.simplify(root_found - root.get_val()).is_zero: + return root.get_id() + + # create an event for a new root function + root_symstr = f"Heaviside_{len(roots)}" + roots.append( + Event( + identifier=sp.Symbol(root_symstr), + name=root_symstr, + value=root_found, + state_update=None, + ) + ) + return roots[-1].get_id() + + def _collect_heaviside_roots( + self, + args: Sequence[sp.Expr], + ) -> list[sp.Expr]: + """ + Recursively checks an expression for the occurrence of Heaviside + functions and return all roots found + + :param args: + args attribute of the expanded expression + + :returns: + root functions that were extracted from Heaviside function + arguments + """ + root_funs = [] + for arg in args: + if arg.func == sp.Heaviside: + root_funs.append(arg.args[0]) + elif arg.has(sp.Heaviside): + root_funs.extend(self._collect_heaviside_roots(arg.args)) + + if not root_funs: + return [] + + # substitute 'w' expressions into root expressions now, to avoid + # rewriting 'root.cpp' and 'stau.cpp' headers + # to include 'w.h' + w_sorted = toposort_symbols( + dict( + zip( + [expr.get_id() for expr in self._expressions], + [expr.get_val() for expr in self._expressions], + ) ) - return self._t_root[0] + ) + root_funs = [r.subs(w_sorted) for r in root_funs] + + return root_funs + + def _process_heavisides( + self, + dxdt: sp.Expr, + roots: list[Event], + ) -> sp.Expr: + """ + Parses the RHS of a state variable, checks for Heaviside functions, + collects unique roots functions that can be tracked by SUNDIALS and + replaces Heaviside Functions by amici helper variables that will be + updated based on SUNDIALS root tracking. + + :param dxdt: + right-hand side of state variable + :param roots: + list of known root functions with identifier + + :returns: + dxdt with Heaviside functions replaced by amici helper variables + """ + # track all the old Heaviside expressions in tmp_roots_old + # replace them later by the new expressions + heavisides = [] + # run through the expression tree and get the roots + tmp_roots_old = self._collect_heaviside_roots(dxdt.args) + for tmp_old in unique_preserve_order(tmp_roots_old): + # we want unique identifiers for the roots + tmp_new = self._get_unique_root(tmp_old, roots) + # `tmp_new` is None if the root is not time-dependent. + if tmp_new is None: + continue + # For Heavisides, we need to add the negative function as well + self._get_unique_root(sp.sympify(-tmp_old), roots) + heavisides.append((sp.Heaviside(tmp_old), tmp_new)) + + if heavisides: + # only apply subs if necessary + for heaviside_sympy, heaviside_amici in heavisides: + dxdt = dxdt.subs(heaviside_sympy, heaviside_amici) + + return dxdt diff --git a/python/sdist/amici/de_model_components.py b/python/sdist/amici/de_model_components.py new file mode 100644 index 0000000000..eeeabb35db --- /dev/null +++ b/python/sdist/amici/de_model_components.py @@ -0,0 +1,754 @@ +"""Objects for AMICI's internal differential equation model representation""" +import abc +import numbers +from typing import Optional, SupportsFloat, Union + +import sympy as sp + +from .import_utils import ( + RESERVED_SYMBOLS, + ObservableTransformation, + amici_time_symbol, + cast_to_sym, + generate_measurement_symbol, + generate_regularization_symbol, +) +from .constants import SymbolId + +__all__ = [ + "ConservationLaw", + "Constant", + "Event", + "Expression", + "LogLikelihoodY", + "LogLikelihoodZ", + "LogLikelihoodRZ", + "ModelQuantity", + "Observable", + "Parameter", + "SigmaY", + "SigmaZ", + "DifferentialState", + "EventObservable", + "AlgebraicState", + "AlgebraicEquation", + "State", +] + + +class ModelQuantity: + """ + Base class for model components + """ + + def __init__( + self, + identifier: sp.Symbol, + name: str, + value: Union[SupportsFloat, numbers.Number, sp.Expr], + ): + """ + Create a new ModelQuantity instance. + + :param identifier: + unique identifier of the quantity + + :param name: + individual name of the quantity (does not need to be unique) + + :param value: + either formula, numeric value or initial value + """ + + if not isinstance(identifier, sp.Symbol): + raise TypeError( + f"identifier must be sympy.Symbol, was " f"{type(identifier)}" + ) + + if str(identifier) in RESERVED_SYMBOLS or ( + hasattr(identifier, "name") and identifier.name in RESERVED_SYMBOLS + ): + raise ValueError( + f'Cannot add model quantity with name "{name}", ' + f"please rename." + ) + self._identifier: sp.Symbol = identifier + + if not isinstance(name, str): + raise TypeError(f"name must be str, was {type(name)}") + + self._name: str = name + + self._value: sp.Expr = cast_to_sym(value, "value") + + def __repr__(self) -> str: + """ + Representation of the ModelQuantity object + + :return: + string representation of the ModelQuantity + """ + return str(self._identifier) + + def get_id(self) -> sp.Symbol: + """ + ModelQuantity identifier + + :return: + identifier of the ModelQuantity + """ + return self._identifier + + def get_name(self) -> str: + """ + ModelQuantity name + + :return: + name of the ModelQuantity + """ + return self._name + + def get_val(self) -> sp.Expr: + """ + ModelQuantity value + + :return: + value of the ModelQuantity + """ + return self._value + + def set_val(self, val: sp.Expr): + """ + Set ModelQuantity value + + :return: + value of the ModelQuantity + """ + self._value = cast_to_sym(val, "value") + + +class ConservationLaw(ModelQuantity): + """ + A conservation law defines the absolute the total amount of a + (weighted) sum of states + + """ + + def __init__( + self, + identifier: sp.Symbol, + name: str, + value: sp.Expr, + coefficients: dict[sp.Symbol, sp.Expr], + state_id: sp.Symbol, + ): + """ + Create a new ConservationLaw instance. + + :param identifier: + unique identifier of the ConservationLaw + + :param name: + individual name of the ConservationLaw (does not need to be + unique) + + :param value: formula (sum of states) + + :param coefficients: + coefficients of the states in the sum + + :param state_id: + identifier of the state that this conservation law replaces + """ + self._state_expr: sp.Symbol = identifier - (value - state_id) + self._coefficients: dict[sp.Symbol, sp.Expr] = coefficients + self._ncoeff: sp.Expr = coefficients[state_id] + super().__init__(identifier, name, value) + + def get_ncoeff(self, state_id) -> Union[sp.Expr, int, float]: + """ + Computes the normalized coefficient a_i/a_j where i is the index of + the provided state_id and j is the index of the state that is + replaced by this conservation law. This can be used to compute both + dtotal_cl/dx_rdata (=ncoeff) and dx_rdata/dx_solver (=-ncoeff). + + :param state_id: + identifier of the state + + :return: normalized coefficent of the state + """ + return self._coefficients.get(state_id, 0.0) / self._ncoeff + + def get_x_rdata(self): + """ + Returns the expression that allows computation of x_rdata for the state + that this conservation law replaces. + + :return: x_rdata expression + """ + return self._state_expr + + +class AlgebraicEquation(ModelQuantity): + """ + An AlgebraicEquation defines an algebraic equation. + """ + + def __init__(self, identifier: str, value: sp.Expr): + """ + Create a new AlgebraicEquation instance. + + :param value: + Formula of the algebraic equation, the solution is given by + ``formula == 0`` + """ + super().__init__(sp.Symbol(identifier), identifier, value) + + def get_free_symbols(self): + return self._value.free_symbols + + def __repr__(self): + return str(self._value) + + +class State(ModelQuantity): + """ + Base class for differential and algebraic model states + """ + + _conservation_law: Optional[ConservationLaw] = None + + def get_x_rdata(self): + """ + Returns the expression that allows computation of x_rdata for this + state, accounting for conservation laws. + + :return: x_rdata expression + """ + if self._conservation_law is None: + return self.get_id() + else: + return self._conservation_law.get_x_rdata() + + def get_dx_rdata_dx_solver(self, state_id): + """ + Returns the expression that allows computation of + ``dx_rdata_dx_solver`` for this state, accounting for conservation + laws. + + :return: dx_rdata_dx_solver expression + """ + if self._conservation_law is None: + return sp.Integer(self._identifier == state_id) + else: + return -self._conservation_law.get_ncoeff(state_id) + + @abc.abstractmethod + def has_conservation_law(self): + """ + Checks whether this state has a conservation law assigned. + + :return: True if assigned, False otherwise + """ + ... + + +class AlgebraicState(State): + """ + An AlgebraicState defines an entity that is algebraically determined + """ + + def __init__(self, identifier: sp.Symbol, name: str, init: sp.Expr): + """ + Create a new AlgebraicState instance. + + :param identifier: + unique identifier of the AlgebraicState + + :param name: + individual name of the AlgebraicState (does not need to be unique) + + :param init: + initial value of the AlgebraicState + """ + super().__init__(identifier, name, init) + + def has_conservation_law(self): + """ + Checks whether this state has a conservation law assigned. + + :return: True if assigned, False otherwise + """ + return False + + def get_free_symbols(self): + return self._value.free_symbols + + def get_x_rdata(self): + return self._identifier + + +class DifferentialState(State): + """ + A State variable defines an entity that evolves with time according to + the provided time derivative, abbreviated by ``x``. + + :ivar _conservation_law: + algebraic formula that allows computation of this + state according to a conservation law + + :ivar _dt: + algebraic formula that defines the temporal derivative of this state + + """ + + def __init__( + self, identifier: sp.Symbol, name: str, init: sp.Expr, dt: sp.Expr + ): + """ + Create a new State instance. Extends :meth:`ModelQuantity.__init__` + by ``dt`` + + :param identifier: + unique identifier of the state + + :param name: + individual name of the state (does not need to be unique) + + :param init: + initial value + + :param dt: + time derivative + """ + super().__init__(identifier, name, init) + self._dt = cast_to_sym(dt, "dt") + self._conservation_law: Union[ConservationLaw, None] = None + + def set_conservation_law(self, law: ConservationLaw) -> None: + """ + Sets the conservation law of a state. + + If a conservation law is set, the respective state will be replaced by + an algebraic formula according to the respective conservation law. + + :param law: + linear sum of states that if added to this state remain + constant over time + """ + if not isinstance(law, ConservationLaw): + raise TypeError( + f"conservation law must have type ConservationLaw" + f", was {type(law)}" + ) + + self._conservation_law = law + + def set_dt(self, dt: sp.Expr) -> None: + """ + Sets the time derivative + + :param dt: + time derivative + """ + self._dt = cast_to_sym(dt, "dt") + + def get_dt(self) -> sp.Expr: + """ + Gets the time derivative + + :return: + time derivative + """ + return self._dt + + def get_free_symbols(self) -> set[sp.Basic]: + """ + Gets the set of free symbols in time derivative and initial conditions + + :return: + free symbols + """ + return self._dt.free_symbols.union(self._value.free_symbols) + + def has_conservation_law(self): + """ + Checks whether this state has a conservation law assigned. + + :return: True if assigned, False otherwise + """ + return self._conservation_law is not None + + +class Observable(ModelQuantity): + """ + An Observable links model simulations to experimental measurements, + abbreviated by ``y``. + + :ivar _measurement_symbol: + sympy symbol used in the objective function to represent + measurements to this observable + + :ivar trafo: + observable transformation, only applies when evaluating objective + function or residuals + """ + + _measurement_symbol: Union[sp.Symbol, None] = None + + def __init__( + self, + identifier: sp.Symbol, + name: str, + value: sp.Expr, + measurement_symbol: Optional[sp.Symbol] = None, + transformation: Optional[ + ObservableTransformation + ] = ObservableTransformation.LIN, + ): + """ + Create a new Observable instance. + + :param identifier: + unique identifier of the Observable + + :param name: + individual name of the Observable (does not need to be unique) + + :param value: + formula + + :param transformation: + observable transformation, only applies when evaluating objective + function or residuals + """ + super().__init__(identifier, name, value) + self._measurement_symbol = measurement_symbol + self._regularization_symbol = None + self.trafo = transformation + + def get_measurement_symbol(self) -> sp.Symbol: + if self._measurement_symbol is None: + self._measurement_symbol = generate_measurement_symbol( + self.get_id() + ) + + return self._measurement_symbol + + def get_regularization_symbol(self) -> sp.Symbol: + if self._regularization_symbol is None: + self._regularization_symbol = generate_regularization_symbol( + self.get_id() + ) + + return self._regularization_symbol + + +class EventObservable(Observable): + """ + An Event Observable links model simulations to event related experimental + measurements, abbreviated by ``z``. + + :ivar _event: + symbolic event identifier + """ + + def __init__( + self, + identifier: sp.Symbol, + name: str, + value: sp.Expr, + event: sp.Symbol, + measurement_symbol: Optional[sp.Symbol] = None, + transformation: Optional[ObservableTransformation] = "lin", + ): + """ + Create a new EventObservable instance. + + :param identifier: + See :py:meth:`Observable.__init__`. + + :param name: + See :py:meth:`Observable.__init__`. + + :param value: + See :py:meth:`Observable.__init__`. + + :param transformation: + See :py:meth:`Observable.__init__`. + + :param event: + Symbolic identifier of the corresponding event. + """ + super().__init__( + identifier, name, value, measurement_symbol, transformation + ) + self._event: sp.Symbol = event + + def get_event(self) -> sp.Symbol: + """ + Get the symbolic identifier of the corresponding event. + + :return: symbolic identifier + """ + return self._event + + +class Sigma(ModelQuantity): + """ + A Standard Deviation Sigma rescales the distance between simulations + and measurements when computing residuals or objective functions, + abbreviated by ``sigma{y,z}``. + """ + + def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): + """ + Create a new Standard Deviation instance. + + :param identifier: + unique identifier of the Standard Deviation + + :param name: + individual name of the Standard Deviation (does not need to + be unique) + + :param value: + formula + """ + if self.__class__.__name__ == "Sigma": + raise RuntimeError( + "This class is meant to be sub-classed, not used directly." + ) + super().__init__(identifier, name, value) + + +class SigmaY(Sigma): + """ + Standard deviation for observables + """ + + +class SigmaZ(Sigma): + """ + Standard deviation for event observables + """ + + +class Expression(ModelQuantity): + """ + An Expression is a recurring elements in symbolic formulas. Specifying + this may yield more compact expression which may lead to substantially + shorter model compilation times, but may also reduce model simulation time. + Abbreviated by ``w``. + """ + + def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): + """ + Create a new Expression instance. + + :param identifier: + unique identifier of the Expression + + :param name: + individual name of the Expression (does not need to be unique) + + :param value: + formula + """ + super().__init__(identifier, name, value) + + +class Parameter(ModelQuantity): + """ + A Parameter is a free variable in the model with respect to which + sensitivities may be computed, abbreviated by ``p``. + """ + + def __init__( + self, identifier: sp.Symbol, name: str, value: numbers.Number + ): + """ + Create a new Expression instance. + + :param identifier: + unique identifier of the Parameter + + :param name: + individual name of the Parameter (does not need to be + unique) + + :param value: + numeric value + """ + super().__init__(identifier, name, value) + + +class Constant(ModelQuantity): + """ + A Constant is a fixed variable in the model with respect to which + sensitivities cannot be computed, abbreviated by ``k``. + """ + + def __init__( + self, identifier: sp.Symbol, name: str, value: numbers.Number + ): + """ + Create a new Expression instance. + + :param identifier: + unique identifier of the Constant + + :param name: + individual name of the Constant (does not need to be unique) + + :param value: + numeric value + """ + super().__init__(identifier, name, value) + + +class LogLikelihood(ModelQuantity): + """ + A LogLikelihood defines the distance between measurements and + experiments for a particular observable. The final LogLikelihood value + in the simulation will be the sum of all specified LogLikelihood + instances evaluated at all timepoints, abbreviated by ``Jy``. + """ + + def __init__(self, identifier: sp.Symbol, name: str, value: sp.Expr): + """ + Create a new Expression instance. + + :param identifier: + unique identifier of the LogLikelihood + + :param name: + individual name of the LogLikelihood (does not need to be + unique) + + :param value: + formula + """ + if self.__class__.__name__ == "LogLikelihood": + raise RuntimeError( + "This class is meant to be sub-classed, not used directly." + ) + super().__init__(identifier, name, value) + + +class LogLikelihoodY(LogLikelihood): + """ + Loglikelihood for observables + """ + + +class LogLikelihoodZ(LogLikelihood): + """ + Loglikelihood for event observables + """ + + +class LogLikelihoodRZ(LogLikelihood): + """ + Loglikelihood for event observables regularization + """ + + +class Event(ModelQuantity): + """ + An Event defines either a SBML event or a root of the argument of a + Heaviside function. The Heaviside functions will be tracked via the + vector ``h`` during simulation and are needed to inform the solver + about a discontinuity in either the right-hand side or the states + themselves, causing a reinitialization of the solver. + """ + + def __init__( + self, + identifier: sp.Symbol, + name: str, + value: sp.Expr, + state_update: Union[sp.Expr, None], + initial_value: Optional[bool] = True, + ): + """ + Create a new Event instance. + + :param identifier: + unique identifier of the Event + + :param name: + individual name of the Event (does not need to be unique) + + :param value: + formula for the root / trigger function + + :param state_update: + formula for the bolus function (None for Heaviside functions, + zero vector for events without bolus) + + :param initial_value: + initial boolean value of the trigger function at t0. If set to + `False`, events may trigger at ``t==t0``, otherwise not. + """ + super().__init__(identifier, name, value) + # add the Event specific components + self._state_update = state_update + self._initial_value = initial_value + + # expression(s) for the timepoint(s) at which the event triggers + self._t_root = sp.solve(self.get_val(), amici_time_symbol) + + def get_initial_value(self) -> bool: + """ + Return the initial value for the root function. + + :return: + initial value formula + """ + return self._initial_value + + def __eq__(self, other): + """ + Check equality of events at the level of trigger/root functions, as we + need to collect unique root functions for ``roots.cpp`` + """ + return self.get_val() == other.get_val() and ( + self.get_initial_value() == other.get_initial_value() + ) + + def triggers_at_fixed_timepoint(self) -> bool: + """Check whether the event triggers at a (single) fixed time-point.""" + if len(self._t_root) != 1: + return False + return self._t_root[0].is_Number + + def get_trigger_time(self) -> sp.Float: + """Get the time at which the event triggers. + + Only for events that trigger at a single fixed time-point. + """ + if not self.triggers_at_fixed_timepoint(): + raise NotImplementedError( + "This event does not trigger at a fixed timepoint." + ) + return self._t_root[0] + + +# defines the type of some attributes in DEModel +symbol_to_type = { + SymbolId.SPECIES: DifferentialState, + SymbolId.ALGEBRAIC_STATE: AlgebraicState, + SymbolId.ALGEBRAIC_EQUATION: AlgebraicEquation, + SymbolId.PARAMETER: Parameter, + SymbolId.FIXED_PARAMETER: Constant, + SymbolId.OBSERVABLE: Observable, + SymbolId.EVENT_OBSERVABLE: EventObservable, + SymbolId.SIGMAY: SigmaY, + SymbolId.SIGMAZ: SigmaZ, + SymbolId.LLHY: LogLikelihoodY, + SymbolId.LLHZ: LogLikelihoodZ, + SymbolId.LLHRZ: LogLikelihoodRZ, + SymbolId.EXPRESSION: Expression, + SymbolId.EVENT: Event, +} diff --git a/python/sdist/amici/import_utils.py b/python/sdist/amici/import_utils.py index 63a160c1de..029c2cc6de 100644 --- a/python/sdist/amici/import_utils.py +++ b/python/sdist/amici/import_utils.py @@ -748,3 +748,10 @@ def unique_preserve_order(seq: Sequence) -> list: sbml_time_symbol = symbol_with_assumptions("time") amici_time_symbol = symbol_with_assumptions("t") + + +def _default_simplify(x): + """Default simplification applied in DEModel""" + # We need this as a free function instead of a lambda to have it picklable + # for parallel simplification + return sp.powsimp(x, deep=True) diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/numpy.py index 6e2966ba4b..c1aef949c6 100644 --- a/python/sdist/amici/numpy.py +++ b/python/sdist/amici/numpy.py @@ -9,7 +9,7 @@ import itertools from typing import Literal, Union from collections.abc import Iterator - +from numbers import Number import amici import numpy as np import sympy as sp @@ -238,6 +238,8 @@ class ReturnDataView(SwigPtrView): "numnonlinsolvconvfailsB", "cpu_timeB", "cpu_time_total", + "messages", + "t_last", ] def __init__(self, rdata: Union[ReturnDataPtr, ReturnData]): @@ -440,7 +442,11 @@ def _field_as_numpy( attr = getattr(data, field) if field_dim := field_dimensions.get(field, None): return None if len(attr) == 0 else np.array(attr).reshape(field_dim) - return float(attr) + + if isinstance(attr, Number): + return float(attr) + + return attr def _entity_type_from_id( diff --git a/python/sdist/amici/pandas.py b/python/sdist/amici/pandas.py index 745cbfb767..b776d2d5ef 100644 --- a/python/sdist/amici/pandas.py +++ b/python/sdist/amici/pandas.py @@ -410,6 +410,20 @@ def _fill_conditions_dict( ] else: datadict[par + "_presim"] = np.nan + + for i_par, par in enumerate( + _get_names_or_ids(model, "Parameter", by_id=by_id) + ): + if len(edata.parameters): + datadict[par] = edata.parameters[i_par] + else: + datadict[par] = model.getParameters()[i_par] + + if len(edata.pscale): + datadict[par + "_scale"] = edata.pscale[i_par] + else: + datadict[par + "_scale"] = model.getParameterScale()[i_par] + return datadict @@ -438,6 +452,11 @@ def _get_extended_observable_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "Observable", by_id=by_id) + [ name + "_std" @@ -471,6 +490,11 @@ def _get_observable_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "Observable", by_id=by_id) ) @@ -500,6 +524,11 @@ def _get_state_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "State", by_id=by_id) ) @@ -528,6 +557,11 @@ def _get_expression_cols(model: AmiciModel, by_id: bool) -> list[str]: name + "_presim" for name in _get_names_or_ids(model, "FixedParameter", by_id=by_id) ] + + _get_names_or_ids(model, "Parameter", by_id=by_id) + + [ + name + "_scale" + for name in _get_names_or_ids(model, "Parameter", by_id=by_id) + ] + _get_names_or_ids(model, "Expression", by_id=by_id) ) @@ -641,10 +675,11 @@ def constructEdataFromDataFrame( Model instance. :param condition: - pd.Series with FixedParameter Names/Ids as columns. + pd.Series with (Fixed)Parameter Names/Ids as columns. Preequilibration conditions may be specified by appending '_preeq' as suffix. Presimulation conditions may be specified by - appending '_presim' as suffix. + appending '_presim' as suffix. Parameter scales may be specified by + appending '_scale' as suffix. :param by_id: Indicate whether in the arguments, column headers are based on ids or @@ -681,6 +716,20 @@ def constructEdataFromDataFrame( .values ) + # fill in parameters + edata.parameters = ( + condition[_get_names_or_ids(model, "Parameter", by_id=by_id)] + .astype(float) + .values + ) + + edata.pscale = amici.parameterScalingFromIntVector( + [ + amici.ParameterScaling(condition[par + "_scale"].astype(int)) + for par in list(_get_names_or_ids(model, "Parameter", by_id=by_id)) + ] + ) + # fill in preequilibration parameters if any( [overwrite_preeq[key] != condition[key] for key in overwrite_preeq] @@ -767,6 +816,10 @@ def getEdataFromDataFrame( condition_parameters.append(par + "_preeq") if par + "_presim" in df.columns: condition_parameters.append(par + "_presim") + # parameters & scales + for par in _get_names_or_ids(model, "Parameter", by_id=by_id): + condition_parameters.append(par) + condition_parameters.append(par + "_scale") # presimulation time if "t_presim" in df.columns: condition_parameters.append("t_presim") diff --git a/python/sdist/amici/petab/petab_import.py b/python/sdist/amici/petab/petab_import.py index 902bf837ef..cb896b39e3 100644 --- a/python/sdist/amici/petab/petab_import.py +++ b/python/sdist/amici/petab/petab_import.py @@ -10,6 +10,7 @@ import shutil from pathlib import Path from typing import Union +from warnings import warn import amici import petab diff --git a/python/sdist/amici/petab/sbml_import.py b/python/sdist/amici/petab/sbml_import.py index 6388d6f8b0..e349683505 100644 --- a/python/sdist/amici/petab/sbml_import.py +++ b/python/sdist/amici/petab/sbml_import.py @@ -518,14 +518,26 @@ def _get_fixed_parameters_sbml( petab_problem, non_estimated_parameters_as_constants ) - # exclude targets of rules or initial assignments + # exclude targets of rules or initial assignments that are not numbers sbml_model = petab_problem.model.sbml_model + parser_settings = libsbml.L3ParserSettings() + parser_settings.setModel(sbml_model) + parser_settings.setParseUnits(libsbml.L3P_NO_UNITS) + for fixed_parameter in fixed_parameters.copy(): # check global parameters - if sbml_model.getInitialAssignmentBySymbol( - fixed_parameter - ) or sbml_model.getRuleByVariable(fixed_parameter): + if sbml_model.getRuleByVariable(fixed_parameter): fixed_parameters.remove(fixed_parameter) + continue + if ia := sbml_model.getInitialAssignmentBySymbol(fixed_parameter): + sym_math = sp.sympify( + libsbml.formulaToL3StringWithSettings( + ia.getMath(), parser_settings + ) + ) + if not sym_math.is_Number: + fixed_parameters.remove(fixed_parameter) + continue return list(sorted(fixed_parameters)) diff --git a/python/sdist/amici/pysb_import.py b/python/sdist/amici/pysb_import.py index 4f843033f1..94aad595d9 100644 --- a/python/sdist/amici/pysb_import.py +++ b/python/sdist/amici/pysb_import.py @@ -27,21 +27,21 @@ from .de_export import ( Constant, DEExporter, - DEModel, DifferentialState, Expression, LogLikelihoodY, Observable, Parameter, SigmaY, - _default_simplify, ) +from .de_model import DEModel from .import_utils import ( _get_str_symbol_identifiers, _parse_special_functions, generate_measurement_symbol, noise_distribution_to_cost_function, noise_distribution_to_observable_transformation, + _default_simplify, ) from .logging import get_logger, log_execution_time, set_log_level @@ -178,6 +178,10 @@ def pysb2amici( compiler=compiler, generate_sensitivity_code=generate_sensitivity_code, ) + # Sympy code optimizations are incompatible with PySB objects, as + # `pysb.Observable` comes with its own `.match` which overrides + # `sympy.Basic.match()`, breaking `sympy.codegen.rewriting.optimize`. + exporter._code_printer._fpoptimizer = None exporter.generate_model_code() if compile: @@ -241,10 +245,6 @@ def ode_model_from_pysb_importer( simplify=simplify, cache_simplify=cache_simplify, ) - # Sympy code optimizations are incompatible with PySB objects, as - # `pysb.Observable` comes with its own `.match` which overrides - # `sympy.Basic.match()`, breaking `sympy.codegen.rewriting.optimize`. - ode._code_printer._fpoptimizer = None if constant_parameters is None: constant_parameters = [] diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 8d36ad7b81..8f7f67b02f 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -27,13 +27,13 @@ from sympy.logic.boolalg import BooleanFalse, BooleanTrue from . import has_clibs +from .de_model import DEModel from .constants import SymbolId from .de_export import ( DEExporter, - DEModel, - _default_simplify, - smart_is_zero_matrix, ) +from .de_model_components import symbol_to_type, Expression +from .sympy_utils import smart_is_zero_matrix, smart_multiply from .import_utils import ( RESERVED_SYMBOLS, _check_unsupported_functions, @@ -50,10 +50,13 @@ smart_subs_dict, symbol_with_assumptions, toposort_symbols, + _default_simplify, + generate_flux_symbol, ) from .logging import get_logger, log_execution_time, set_log_level from .sbml_utils import SBMLException, _parse_logical_operators from .splines import AbstractSpline +from sympy.matrices.dense import MutableDenseMatrix SymbolicFormula = dict[sp.Symbol, sp.Expr] @@ -180,22 +183,15 @@ def __init__( self.species_assignment_rules: SymbolicFormula = {} self.parameter_assignment_rules: SymbolicFormula = {} self.initial_assignments: SymbolicFormula = {} - self.splines = [] + self.splines: list[AbstractSpline] = [] self._reset_symbols() - # http://sbml.org/Software/libSBML/5.18.0/docs/python-api/classlibsbml_1_1_l3_parser_settings.html#abcfedd34efd3cae2081ba8f42ea43f52 + # https://sbml.org/software/libsbml/5.18.0/docs/formatted/python-api/classlibsbml_1_1_l3_parser_settings.html#ab30d7ed52ca24cbb842d0a7fed7f4bfd # all defaults except disable unit parsing - self.sbml_parser_settings = sbml.L3ParserSettings( - self.sbml, - sbml.L3P_PARSE_LOG_AS_LOG10, - sbml.L3P_EXPAND_UNARY_MINUS, - sbml.L3P_NO_UNITS, - sbml.L3P_AVOGADRO_IS_CSYMBOL, - sbml.L3P_COMPARE_BUILTINS_CASE_INSENSITIVE, - None, - sbml.L3P_MODULO_IS_PIECEWISE, - ) + self.sbml_parser_settings = sbml.L3ParserSettings() + self.sbml_parser_settings.setModel(self.sbml) + self.sbml_parser_settings.setParseUnits(sbml.L3P_NO_UNITS) self._discard_annotations: bool = discard_annotations @@ -534,9 +530,96 @@ def _build_ode_model( simplify=simplify, cache_simplify=cache_simplify, ) - ode_model.import_from_sbml_importer( - self, compute_cls=compute_conservation_laws + + ode_model._has_quadratic_nllh = all( + llh["dist"] + in ["normal", "lin-normal", "log-normal", "log10-normal"] + for llh in self.symbols[SymbolId.LLHY].values() + ) + + # add splines as expressions to the model + # saved for later substituting into the fluxes + spline_subs = {} + for ispl, spl in enumerate(self.splines): + spline_expr = spl.ode_model_symbol(self) + spline_subs[spl.sbml_id] = spline_expr + ode_model.add_spline(spl, spline_expr) + + # assemble fluxes and add them as expressions to the model + assert len(self.flux_ids) == len(self.flux_vector) + fluxes = [ + generate_flux_symbol(ir, name=flux_id) + for ir, flux_id in enumerate(self.flux_ids) + ] + + # create dynamics without respecting conservation laws first + dxdt = smart_multiply( + self.stoichiometric_matrix, MutableDenseMatrix(fluxes) ) + # correct time derivatives for compartment changes + for ix, ((species_id, species), formula) in enumerate( + zip(self.symbols[SymbolId.SPECIES].items(), dxdt) + ): + # rate rules and amount species don't need to be updated + if "dt" in species: + continue + if species["amount"]: + species["dt"] = formula + else: + species["dt"] = self._transform_dxdt_to_concentration( + species_id, formula + ) + + # create all basic components of the DE model and add them. + for symbol_name in self.symbols: + # transform dict of lists into a list of dicts + args = ["name", "identifier"] + + if symbol_name == SymbolId.SPECIES: + args += ["dt", "init"] + elif symbol_name == SymbolId.ALGEBRAIC_STATE: + args += ["init"] + else: + args += ["value"] + + if symbol_name == SymbolId.EVENT: + args += ["state_update", "initial_value"] + elif symbol_name == SymbolId.OBSERVABLE: + args += ["transformation"] + elif symbol_name == SymbolId.EVENT_OBSERVABLE: + args += ["event"] + + comp_kwargs = [ + { + "identifier": var_id, + **{k: v for k, v in var.items() if k in args}, + } + for var_id, var in self.symbols[symbol_name].items() + ] + + for comp_kwarg in comp_kwargs: + ode_model.add_component( + symbol_to_type[symbol_name](**comp_kwarg) + ) + + # add fluxes as expressions, this needs to happen after base + # expressions from symbols have been parsed + for flux_id, flux in zip(fluxes, self.flux_vector): + # replace splines inside fluxes + flux = flux.subs(spline_subs) + ode_model.add_component( + Expression(identifier=flux_id, name=str(flux_id), value=flux) + ) + + if compute_conservation_laws: + self._process_conservation_laws(ode_model) + + # fill in 'self._sym' based on prototypes and components in ode_model + ode_model.generate_basic_variables() + + # substitute SBML-rateOf constructs + ode_model._process_sbml_rate_of() + return ode_model @log_execution_time("importing SBML", logger) @@ -550,7 +633,7 @@ def _process_sbml( :param constant_parameters: SBML Ids identifying constant parameters - :param hardcode_parameters: + :param hardcode_symbols: Parameter IDs to be replaced by their values in the generated model. """ if not self._discard_annotations: @@ -722,7 +805,7 @@ def _gather_base_locals( "INF": sp.oo, "NaN": sp.nan, "rem": sp.Mod, - "time": symbol_with_assumptions("time"), + "time": sbml_time_symbol, # SBML L3 explicitly defines this value, which is not equal # to the most recent SI definition. "avogadro": sp.Float(6.02214179e23), @@ -1051,15 +1134,28 @@ def _process_parameters( "Parameter does not exist." % parameter ) + # parameter ID => initial assignment sympy expression + par_id_to_ia = { + par.getId(): ia.subs( + { + BooleanTrue(): sp.Float(1.0), + BooleanFalse(): sp.Float(0.0), + } + ).evalf() + for par in self.sbml.getListOfParameters() + if (ia := self._get_element_initial_assignment(par.getId())) + is not None + } + fixed_parameters = [ parameter for parameter in self.sbml.getListOfParameters() if parameter.getId() in constant_parameters ] for parameter in fixed_parameters: + ia_math = par_id_to_ia.get(parameter.getId()) if ( - self._get_element_initial_assignment(parameter.getId()) - is not None + (ia_math is not None and not ia_math.is_Number) or self.is_assignment_rule_target(parameter) or self.is_rate_rule_target(parameter) ): @@ -1074,7 +1170,10 @@ def _process_parameters( parameter for parameter in self.sbml.getListOfParameters() if parameter.getId() not in constant_parameters - and self._get_element_initial_assignment(parameter.getId()) is None + and ( + (ia_math := par_id_to_ia.get(parameter.getId())) is None + or ia_math.is_Number + ) and not self.is_assignment_rule_target(parameter) and parameter.getId() not in hardcode_symbols ] @@ -1091,17 +1190,19 @@ def _process_parameters( for par in settings["var"]: self.symbols[partype][_get_identifier_symbol(par)] = { "name": par.getName() if par.isSetName() else par.getId(), - "value": sp.Float(par.getValue()), + "value": par_id_to_ia.get( + par.getId(), sp.Float(par.getValue()) + ), } # Parameters that need to be turned into expressions - # so far, this concerns parameters with initial assignments containing rateOf(.) - # (those have been skipped above) + # so far, this concerns parameters with symbolic initial assignments + # (those have been skipped above) that are not rate rule targets for par in self.sbml.getListOfParameters(): if ( - ia := self._get_element_initial_assignment(par.getId()) - ) is not None and ia.find( - sp.core.function.UndefinedFunction("rateOf") + (ia := par_id_to_ia.get(par.getId())) is not None + and not ia.is_Number + and not self.is_rate_rule_target(par) ): self.symbols[SymbolId.EXPRESSION][ _get_identifier_symbol(par) @@ -1877,7 +1978,11 @@ def _process_initial_assignments(self): for ia in self.sbml.getListOfInitialAssignments(): identifier = _get_identifier_symbol(ia) if identifier in itt.chain( - self.symbols[SymbolId.SPECIES], self.compartments + self.symbols[SymbolId.SPECIES], + self.compartments, + self.symbols[SymbolId.EXPRESSION], + self.symbols[SymbolId.PARAMETER], + self.symbols[SymbolId.FIXED_PARAMETER], ): continue @@ -1951,20 +2056,18 @@ def _make_initial( if "init" in species: sym_math = smart_subs(sym_math, species_id, species["init"]) - sym_math = smart_subs( - sym_math, self._local_symbols["time"], sp.Float(0) - ) + sym_math = smart_subs(sym_math, sbml_time_symbol, sp.Float(0)) sym_math = _dummy_to_rateof(sym_math, rateof_to_dummy) return sym_math - def process_conservation_laws(self, ode_model) -> None: + def _process_conservation_laws(self, ode_model: DEModel) -> None: """ Find conservation laws in reactions and species. :param ode_model: - ODEModel object with basic definitions + :class:`DEModel` object with basic definitions """ conservation_laws = [] @@ -2511,6 +2614,74 @@ def is_rate_rule_target(self, element: sbml.SBase) -> bool: a = self.sbml.getRateRuleByVariable(element.getId()) return a is not None and self._sympy_from_sbml_math(a) is not None + def _transform_dxdt_to_concentration( + self, species_id: sp.Symbol, dxdt: sp.Expr + ) -> sp.Expr: + """ + Produces the appropriate expression for the first derivative of a + species with respect to time, for species that reside in + compartments with a constant volume, or a volume that is defined by + an assignment or rate rule. + + :param species_id: + The identifier of the species (generated in "sbml_import.py"). + + :param dxdt: + The element-wise product of the row in the stoichiometric + matrix that corresponds to the species (row x_index) and the + flux (kinetic laws) vector. Ignored in the case of rate rules. + """ + # The derivation of the below return expressions can be found in + # the documentation. They are found by rearranging + # $\frac{d}{dt} (vx) = Sw$ for $\frac{dx}{dt}$, where $v$ is the + # vector of species compartment volumes, $x$ is the vector of + # species concentrations, $S$ is the stoichiometric matrix, and $w$ + # is the flux vector. The conditional below handles the cases of + # species in (i) compartments with a rate rule, (ii) compartments + # with an assignment rule, and (iii) compartments with a constant + # volume, respectively. + species = self.symbols[SymbolId.SPECIES][species_id] + + comp = species["compartment"] + if comp in self.symbols[SymbolId.SPECIES]: + dv_dt = self.symbols[SymbolId.SPECIES][comp]["dt"] + xdot = (dxdt - dv_dt * species_id) / comp + return xdot + elif comp in self.compartment_assignment_rules: + v = self.compartment_assignment_rules[comp] + + # we need to flatten out assignments in the compartment in + # order to ensure that we catch all species dependencies + v = smart_subs_dict(v, self.symbols[SymbolId.EXPRESSION], "value") + dv_dt = v.diff(amici_time_symbol) + # we may end up with a time derivative of the compartment + # volume due to parameter rate rules + comp_rate_vars = [ + p + for p in v.free_symbols + if p in self.symbols[SymbolId.SPECIES] + ] + for var in comp_rate_vars: + dv_dt += ( + v.diff(var) * self.symbols[SymbolId.SPECIES][var]["dt"] + ) + dv_dx = v.diff(species_id) + xdot = (dxdt - dv_dt * species_id) / (dv_dx * species_id + v) + return xdot + elif comp in self.symbols[SymbolId.ALGEBRAIC_STATE]: + raise SBMLException( + f"Species {species_id} is in a compartment {comp} that is" + f" defined by an algebraic equation. This is not" + f" supported." + ) + else: + v = self.compartments[comp] + + if v == 1.0: + return dxdt + + return dxdt / v + def _check_lib_sbml_errors( sbml_doc: sbml.SBMLDocument, show_warnings: bool = False diff --git a/python/sdist/amici/splines.py b/python/sdist/amici/splines.py index d55a78137b..ea0cd0e06d 100644 --- a/python/sdist/amici/splines.py +++ b/python/sdist/amici/splines.py @@ -52,6 +52,7 @@ pretty_xml, sbml_mathml, ) +from .constants import SymbolId logger = get_logger(__name__, logging.WARNING) @@ -569,8 +570,6 @@ def check_if_valid(self, importer: sbml_import.SbmlImporter) -> None: # the AMICI spline implementation. # If found, they should be checked for here # until (if at all) they are accounted for. - from .de_export import SymbolId - fixed_parameters: list[sp.Symbol] = list( importer.symbols[SymbolId.FIXED_PARAMETER].keys() ) @@ -1345,8 +1344,6 @@ def _from_annotation( def parameters(self, importer: sbml_import.SbmlImporter) -> set[sp.Symbol]: """Returns the SBML parameters used by this spline""" - from .de_export import SymbolId - return self._parameters().intersection( set(importer.symbols[SymbolId.PARAMETER].keys()) ) @@ -1659,7 +1656,6 @@ def check_if_valid(self, importer: sbml_import.SbmlImporter) -> None: for spline grid points, values, ... contain species symbols. """ # TODO this is very much a draft - from .de_export import SymbolId species: list[sp.Symbol] = list(importer.symbols[SymbolId.SPECIES]) for d in self.derivatives_at_nodes: diff --git a/python/sdist/amici/swig.py b/python/sdist/amici/swig.py index 902145ff3e..fbc486c301 100644 --- a/python/sdist/amici/swig.py +++ b/python/sdist/amici/swig.py @@ -15,6 +15,7 @@ class TypeHintFixer(ast.NodeTransformer): "ptrdiff_t": ast.Name("int"), "size_t": ast.Name("int"), "bool": ast.Name("bool"), + "boolean": ast.Name("bool"), "std::unique_ptr< amici::Solver >": ast.Constant("Solver"), "amici::InternalSensitivityMethod": ast.Constant( "InternalSensitivityMethod" @@ -40,8 +41,10 @@ class TypeHintFixer(ast.NodeTransformer): "SteadyStateSensitivityMode" ), "amici::realtype": ast.Name("float"), - "DoubleVector": ast.Constant("Sequence[float]"), + "DoubleVector": ast.Name("Sequence[float]"), + "BoolVector": ast.Name("Sequence[bool]"), "IntVector": ast.Name("Sequence[int]"), + "StringVector": ast.Name("Sequence[str]"), "std::string": ast.Name("str"), "std::string const &": ast.Name("str"), "std::unique_ptr< amici::ExpData >": ast.Constant("ExpData"), @@ -53,8 +56,10 @@ class TypeHintFixer(ast.NodeTransformer): } def visit_FunctionDef(self, node): + self._annotation_from_docstring(node) + # Has a return type annotation? - if node.returns: + if node.returns and isinstance(node.returns, ast.Constant): node.returns = self._new_annot(node.returns.value) # Has arguments? @@ -103,6 +108,53 @@ def _new_annot(self, old_annot: str): return ast.Constant(old_annot) + def _annotation_from_docstring(self, node: ast.FunctionDef): + """Add annotations based on docstring. + + If any argument or return type of the function is not annotated, but + the corresponding docstring contains a type hint (``:rtype:`` or + ``:type:``), the type hint is used as the annotation. + + Swig sometimes generates ``:type solver: :py:class:`Solver`` instead of + ``:type solver: Solver``. Those need special treatment. + """ + docstring = ast.get_docstring(node, clean=False) + if not docstring or "*Overload 1:*" in docstring: + # skip overloaded methods + return + + docstring = docstring.split("\n") + lines_to_remove = set() + + for line_no, line in enumerate(docstring): + if ( + match := re.match( + r"\s*:rtype:\s*(?::py:class:`)?(\w+)`?\s+$", line + ) + ) and not match.group(1).startswith(":"): + node.returns = ast.Constant(match.group(1)) + lines_to_remove.add(line_no) + + if ( + match := re.match( + r"\s*:type\s*(\w+):\W*(?::py:class:`)?(\w+)`?\s+$", line + ) + ) and not match.group(1).startswith(":"): + for arg in node.args.args: + if arg.arg == match.group(1): + arg.annotation = ast.Constant(match.group(2)) + lines_to_remove.add(line_no) + + if lines_to_remove: + # Update docstring with type annotations removed + assert isinstance(node.body[0].value, ast.Constant) + new_docstring = "\n".join( + line + for line_no, line in enumerate(docstring) + if line_no not in lines_to_remove + ) + node.body[0].value = ast.Str(new_docstring) + def fix_typehints(infilename, outfilename): """Change SWIG-generated C++ typehints to Python typehints""" diff --git a/python/sdist/amici/sympy_utils.py b/python/sdist/amici/sympy_utils.py new file mode 100644 index 0000000000..bc20c49dc4 --- /dev/null +++ b/python/sdist/amici/sympy_utils.py @@ -0,0 +1,195 @@ +"""Functionality for working with sympy objects.""" +import os +from itertools import starmap +from typing import Union, Any, Callable +import contextlib +import sympy as sp +import logging +from .logging import log_execution_time, get_logger + + +logger = get_logger(__name__, logging.ERROR) + + +def _custom_pow_eval_derivative(self, s): + """ + Custom Pow derivative that removes a removable singularity for + ``self.base == 0`` and ``self.base.diff(s) == 0``. This function is + intended to be monkeypatched into :py:method:`sympy.Pow._eval_derivative`. + + :param self: + sp.Pow class + + :param s: + variable with respect to which the derivative will be computed + """ + dbase = self.base.diff(s) + dexp = self.exp.diff(s) + part1 = sp.Pow(self.base, self.exp - 1) * self.exp * dbase + part2 = self * dexp * sp.log(self.base) + if self.base.is_nonzero or dbase.is_nonzero or part2.is_zero: + # first piece never applies or is zero anyway + return part1 + part2 + + return part1 + sp.Piecewise( + (self.base, sp.And(sp.Eq(self.base, 0), sp.Eq(dbase, 0))), + (part2, True), + ) + + +@contextlib.contextmanager +def _monkeypatched(obj: object, name: str, patch: Any): + """ + Temporarily monkeypatches an object. + + :param obj: + object to be patched + + :param name: + name of the attribute to be patched + + :param patch: + patched value + """ + pre_patched_value = getattr(obj, name) + setattr(obj, name, patch) + try: + yield object + finally: + setattr(obj, name, pre_patched_value) + + +@log_execution_time("running smart_jacobian", logger) +def smart_jacobian( + eq: sp.MutableDenseMatrix, sym_var: sp.MutableDenseMatrix +) -> sp.MutableSparseMatrix: + """ + Wrapper around symbolic jacobian with some additional checks that reduce + computation time for large matrices + + :param eq: + equation + :param sym_var: + differentiation variable + :return: + jacobian of eq wrt sym_var + """ + nrow = eq.shape[0] + ncol = sym_var.shape[0] + if ( + not min(eq.shape) + or not min(sym_var.shape) + or smart_is_zero_matrix(eq) + or smart_is_zero_matrix(sym_var) + ): + return sp.MutableSparseMatrix(nrow, ncol, dict()) + + # preprocess sparsity pattern + elements = ( + (i, j, a, b) + for i, a in enumerate(eq) + for j, b in enumerate(sym_var) + if a.has(b) + ) + + if (n_procs := int(os.environ.get("AMICI_IMPORT_NPROCS", 1))) == 1: + # serial + return sp.MutableSparseMatrix( + nrow, ncol, dict(starmap(_jacobian_element, elements)) + ) + + # parallel + from multiprocessing import get_context + + # "spawn" should avoid potential deadlocks occurring with fork + # see e.g. https://stackoverflow.com/a/66113051 + ctx = get_context("spawn") + with ctx.Pool(n_procs) as p: + mapped = p.starmap(_jacobian_element, elements) + return sp.MutableSparseMatrix(nrow, ncol, dict(mapped)) + + +@log_execution_time("running smart_multiply", logger) +def smart_multiply( + x: Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix], + y: sp.MutableDenseMatrix, +) -> Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix]: + """ + Wrapper around symbolic multiplication with some additional checks that + reduce computation time for large matrices + + :param x: + educt 1 + :param y: + educt 2 + :return: + product + """ + if ( + not x.shape[0] + or not y.shape[1] + or smart_is_zero_matrix(x) + or smart_is_zero_matrix(y) + ): + return sp.zeros(x.shape[0], y.shape[1]) + return x.multiply(y) + + +def smart_is_zero_matrix( + x: Union[sp.MutableDenseMatrix, sp.MutableSparseMatrix], +) -> bool: + """A faster implementation of sympy's is_zero_matrix + + Avoids repeated indexer type checks and double iteration to distinguish + False/None. Found to be about 100x faster for large matrices. + + :param x: Matrix to check + """ + + if isinstance(x, sp.MutableDenseMatrix): + return all(xx.is_zero is True for xx in x.flat()) + + if isinstance(x, list): + return all(smart_is_zero_matrix(xx) for xx in x) + + return x.nnz() == 0 + + +def _jacobian_element(i, j, eq_i, sym_var_j): + """Compute a single element of a jacobian""" + return (i, j), eq_i.diff(sym_var_j) + + +def _parallel_applyfunc(obj: sp.Matrix, func: Callable) -> sp.Matrix: + """Parallel implementation of sympy's Matrix.applyfunc""" + if (n_procs := int(os.environ.get("AMICI_IMPORT_NPROCS", 1))) == 1: + # serial + return obj.applyfunc(func) + + # parallel + from multiprocessing import get_context + from pickle import PicklingError + + from sympy.matrices.dense import DenseMatrix + + # "spawn" should avoid potential deadlocks occurring with fork + # see e.g. https://stackoverflow.com/a/66113051 + ctx = get_context("spawn") + with ctx.Pool(n_procs) as p: + try: + if isinstance(obj, DenseMatrix): + return obj._new(obj.rows, obj.cols, p.map(func, obj)) + elif isinstance(obj, sp.SparseMatrix): + dok = obj.todok() + mapped = p.map(func, dok.values()) + dok = {k: v for k, v in zip(dok.keys(), mapped) if v != 0} + return obj._new(obj.rows, obj.cols, dok) + else: + raise ValueError(f"Unsupported matrix type {type(obj)}") + except PicklingError as e: + raise ValueError( + f"Couldn't pickle {func}. This is likely because the argument " + "was not a module-level function. Either rewrite the argument " + "to a module-level function or disable parallelization by " + "setting `AMICI_IMPORT_NPROCS=1`." + ) from e diff --git a/python/sdist/setup.cfg b/python/sdist/setup.cfg index 009d622a6b..d34d42f98f 100644 --- a/python/sdist/setup.cfg +++ b/python/sdist/setup.cfg @@ -47,7 +47,7 @@ zip_safe = False # Don't include any URLs here - they are not supported by PyPI: # HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/ # Invalid value for requires_dist. Error: Can't have direct dependency: ... -petab = petab>=0.2.1 +petab = petab>=0.2.9 pysb = pysb>=1.13.1 test = benchmark_models_petab @ git+https://github.com/Benchmarking-Initiative/Benchmark-Models-PEtab.git@master#subdirectory=src/python @@ -62,6 +62,7 @@ test = # unsupported x86_64 / x86_64h antimony!=2.14; platform_system=='Darwin' and platform_machine in 'x86_64h' scipy + pooch vis = matplotlib seaborn diff --git a/python/sdist/setup.py b/python/sdist/setup.py index ed65127f7a..0da5ac9878 100755 --- a/python/sdist/setup.py +++ b/python/sdist/setup.py @@ -50,9 +50,15 @@ def get_extensions(): source_dir="amici/ThirdParty/SuiteSparse/SuiteSparse_config", cmake_configure_options=[ *global_cmake_configure_options, - "-DBLA_VENDOR=All", - "-DENABLE_CUDA=FALSE", - "-DNFORTRAN=TRUE", + "-DCMAKE_POSITION_INDEPENDENT_CODE=ON", + # Building SuiteSparse_config does not require a BLAS + # we just set BLAS_LIBRARIES to skip the search, + # the value is not used + # "-DBLA_VENDOR=All", + "-DBLAS_LIBRARIES=dummy", + "-DSUITESPARSE_USE_64BIT_BLAS=ON", + "-DSUITESPARSE_USE_CUDA=OFF", + "-DSUITESPARSE_USE_FORTRAN=OFF", ], ) # SuiteSparse AMD @@ -62,7 +68,7 @@ def get_extensions(): source_dir="amici/ThirdParty/SuiteSparse/AMD", cmake_configure_options=[ *global_cmake_configure_options, - "-DNFORTRAN=TRUE", + "-DSUITESPARSE_USE_FORTRAN=OFF", ], ) # SuiteSparse BTF @@ -72,7 +78,7 @@ def get_extensions(): source_dir="amici/ThirdParty/SuiteSparse/BTF", cmake_configure_options=[ *global_cmake_configure_options, - "-DNFORTRAN=TRUE", + "-DSUITESPARSE_USE_FORTRAN=OFF", ], ) # SuiteSparse COLAMD @@ -82,7 +88,7 @@ def get_extensions(): source_dir="amici/ThirdParty/SuiteSparse/COLAMD", cmake_configure_options=[ *global_cmake_configure_options, - "-DNFORTRAN=TRUE", + "-DSUITESPARSE_USE_FORTRAN=OFF", ], ) # SuiteSparse KLU @@ -92,9 +98,9 @@ def get_extensions(): source_dir="amici/ThirdParty/SuiteSparse/KLU", cmake_configure_options=[ *global_cmake_configure_options, - "-DNCHOLMOD=ON", - "-DENABLE_CUDA=FALSE", - "-DNFORTRAN=TRUE", + "-DKLU_USE_CHOLMOD=OFF", + "-DSUITESPARSE_USE_CUDA=OFF", + "-DSUITESPARSE_USE_FORTRAN=OFF", ], ) # SUNDIALS @@ -120,7 +126,7 @@ def get_extensions(): # be replaced by the actual path by `AmiciBuildCMakeExtension` # before being passed to CMake. "-DKLU_LIBRARY_DIR='${build_dir}/amici/lib'", - "-DKLU_INCLUDE_DIR='${build_dir}/amici/include'", + "-DKLU_INCLUDE_DIR='${build_dir}/amici/include/suitesparse'", ], ) # AMICI diff --git a/python/tests/test_conserved_quantities_demartino.py b/python/tests/test_conserved_quantities_demartino.py index 339743cc4e..ca40946db3 100644 --- a/python/tests/test_conserved_quantities_demartino.py +++ b/python/tests/test_conserved_quantities_demartino.py @@ -155,15 +155,15 @@ def data_demartino2014(): """Get tests from DeMartino2014 Suppl. Material""" import gzip - import io - import urllib.request + import pooch # stoichiometric matrix - response = urllib.request.urlopen( - r"https://github.com/AMICI-dev/AMICI/files/11430971/DeMartinoDe2014_test-ecoli.dat.gz", - timeout=10, + data = gzip.GzipFile( + pooch.retrieve( + "https://github.com/AMICI-dev/AMICI/files/11430971/DeMartinoDe2014_test-ecoli.dat.gz", + known_hash="md5:899873f8f1c413d13c3f8e94c1496b7e", + ) ) - data = gzip.GzipFile(fileobj=io.BytesIO(response.read())) S = [ int(item) for sl in [ @@ -174,14 +174,13 @@ def data_demartino2014(): ] # metabolite / row names - response = urllib.request.urlopen( - r"https://github.com/AMICI-dev/AMICI/files/11430970/test-ecoli-met.txt", - timeout=10, - ) - row_names = [ - entry.decode("ascii").strip() for entry in io.BytesIO(response.read()) - ] - + with open( + pooch.retrieve( + "https://github.com/AMICI-dev/AMICI/files/11430970/test-ecoli-met.txt", + known_hash="md5:d71e711a3655311390b38d00dcd6aa7f", + ) + ) as f: + row_names = [entry.strip() for entry in f.readlines()] return S, row_names diff --git a/python/tests/test_de_model.py b/python/tests/test_de_model.py index 8bd750443a..07c8328ed1 100644 --- a/python/tests/test_de_model.py +++ b/python/tests/test_de_model.py @@ -1,5 +1,5 @@ import sympy as sp -from amici.de_model import Event +from amici.de_model_components import Event from amici.import_utils import amici_time_symbol from amici.testing import skip_on_valgrind diff --git a/python/tests/test_hdf5.py b/python/tests/test_hdf5.py index 232f22be8c..ee9d5a3e3b 100644 --- a/python/tests/test_hdf5.py +++ b/python/tests/test_hdf5.py @@ -24,6 +24,8 @@ def _modify_solver_attrs(solver): elif attr == "setMaxTime": # default value is the maximum, must not add to that cval = random.random() + elif attr == "setConstraints": + cval = [1.0, 1.0] elif isinstance(val, int): cval = val + 1 else: diff --git a/python/tests/test_misc.py b/python/tests/test_misc.py index 24bba79888..b68e96f1a0 100644 --- a/python/tests/test_misc.py +++ b/python/tests/test_misc.py @@ -7,11 +7,7 @@ import amici import pytest import sympy as sp -from amici.de_export import ( - _custom_pow_eval_derivative, - _monkeypatched, - smart_subs_dict, -) +from amici.import_utils import smart_subs_dict from amici.testing import skip_on_valgrind @@ -108,25 +104,6 @@ def test_smart_subs_dict(): assert sp.simplify(result_reverse - expected_reverse).is_zero -@skip_on_valgrind -def test_monkeypatch(): - t = sp.Symbol("t") - n = sp.Symbol("n") - vals = [(t, 0), (n, 1)] - - # check that the removable singularity still exists - assert (t**n).diff(t).subs(vals) is sp.nan - - # check that we can monkeypatch it out - with _monkeypatched( - sp.Pow, "_eval_derivative", _custom_pow_eval_derivative - ): - assert (t**n).diff(t).subs(vals) is not sp.nan - - # check that the monkeypatch is transient - assert (t**n).diff(t).subs(vals) is sp.nan - - @skip_on_valgrind def test_get_default_argument(): # no default diff --git a/python/tests/test_ode_export.py b/python/tests/test_ode_export.py index f34d78892d..6dc4d85f05 100644 --- a/python/tests/test_ode_export.py +++ b/python/tests/test_ode_export.py @@ -1,14 +1,13 @@ """Miscellaneous AMICI Python interface tests""" import sympy as sp -from amici.cxxcodeprinter import AmiciCxxCodePrinter +from amici.cxxcodeprinter import csc_matrix from amici.testing import skip_on_valgrind @skip_on_valgrind def test_csc_matrix(): """Test sparse CSC matrix creation""" - printer = AmiciCxxCodePrinter() matrix = sp.Matrix([[1, 0], [2, 3]]) ( symbol_col_ptrs, @@ -16,7 +15,7 @@ def test_csc_matrix(): sparse_list, symbol_list, sparse_matrix, - ) = printer.csc_matrix( + ) = csc_matrix( matrix, rownames=[sp.Symbol("a1"), sp.Symbol("a2")], colnames=[sp.Symbol("b1"), sp.Symbol("b2")], @@ -32,7 +31,6 @@ def test_csc_matrix(): @skip_on_valgrind def test_csc_matrix_empty(): """Test sparse CSC matrix creation for empty matrix""" - printer = AmiciCxxCodePrinter() matrix = sp.Matrix() ( symbol_col_ptrs, @@ -40,7 +38,7 @@ def test_csc_matrix_empty(): sparse_list, symbol_list, sparse_matrix, - ) = printer.csc_matrix(matrix, rownames=[], colnames=[]) + ) = csc_matrix(matrix, rownames=[], colnames=[]) assert symbol_col_ptrs == [] assert symbol_row_vals == [] @@ -52,7 +50,6 @@ def test_csc_matrix_empty(): @skip_on_valgrind def test_csc_matrix_vector(): """Test sparse CSC matrix creation from matrix slice""" - printer = AmiciCxxCodePrinter() matrix = sp.Matrix([[1, 0], [2, 3]]) ( symbol_col_ptrs, @@ -60,7 +57,7 @@ def test_csc_matrix_vector(): sparse_list, symbol_list, sparse_matrix, - ) = printer.csc_matrix( + ) = csc_matrix( matrix[:, 0], colnames=[sp.Symbol("b")], rownames=[sp.Symbol("a1"), sp.Symbol("a2")], @@ -79,7 +76,7 @@ def test_csc_matrix_vector(): sparse_list, symbol_list, sparse_matrix, - ) = printer.csc_matrix( + ) = csc_matrix( matrix[:, 1], colnames=[sp.Symbol("b")], rownames=[sp.Symbol("a1"), sp.Symbol("a2")], @@ -95,7 +92,7 @@ def test_csc_matrix_vector(): @skip_on_valgrind def test_match_deriv(): - from amici.de_export import DERIVATIVE_PATTERN as pat + from amici.de_model import DERIVATIVE_PATTERN as pat def check(str, out1, out2): match = pat.match(str) diff --git a/python/tests/test_petab_import.py b/python/tests/test_petab_import.py index 7a476f272d..fca319e11f 100644 --- a/python/tests/test_petab_import.py +++ b/python/tests/test_petab_import.py @@ -36,8 +36,30 @@ def simple_sbml_model(): return document, model +@pytest.fixture() +def get_fixed_parameters_model(): + """Create test SBML model for test_get_fixed_parameters""" + ant_model = """ + p1 = 1 + p2 = 2 + p3 = 3 + p4 = 4 + p5 = 5 + p6 = 3^2 + p7 = p6 + p8 = 8 + p8' = 1 + p9 := p8 + """ + from amici.antimony_import import antimony2sbml + + sbml_str = antimony2sbml(ant_model) + sbml_doc = libsbml.SBMLReader().readSBMLFromString(sbml_str) + return sbml_doc, sbml_doc.getModel() + + @skip_on_valgrind -def test_get_fixed_parameters(simple_sbml_model): +def test_get_fixed_parameters(get_fixed_parameters_model): """Check for correct identification of fixed parameters: p1: fixed (via condition table) @@ -45,13 +67,18 @@ def test_get_fixed_parameters(simple_sbml_model): p3: fixed (via parameter table `estimate=0`) p4: not fixed (via parameter table `estimate=1`) p5: fixed (implicitly, because not listed as estimated) + p6: fixed (implicitly, because not listed as estimated + initial assignment is a number) + p7: not fixed (initial assignment is not a number) + p8: not fixed (rate rule target) + p9: not fixed (assignment rule target) """ from amici.petab.sbml_import import ( _get_fixed_parameters_sbml as get_fixed_parameters, ) from petab.models.sbml_model import SbmlModel - sbml_doc, sbml_model = simple_sbml_model + sbml_doc, sbml_model = get_fixed_parameters_model condition_df = petab.get_condition_df( pd.DataFrame( { @@ -77,13 +104,14 @@ def test_get_fixed_parameters(simple_sbml_model): "p1", "p3", "p5", + "p6", } assert set( get_fixed_parameters( petab_problem, non_estimated_parameters_as_constants=False ) - ) == {"p1", "p5"} + ) == {"p1", "p5", "p6"} @skip_on_valgrind diff --git a/python/tests/test_preequilibration.py b/python/tests/test_preequilibration.py index be447b0c54..d003507199 100644 --- a/python/tests/test_preequilibration.py +++ b/python/tests/test_preequilibration.py @@ -608,8 +608,6 @@ def test_simulation_errors(preeq_fixture): ) assert rdata._swigptr.messages[1].severity == amici.LogSeverity_error assert rdata._swigptr.messages[1].identifier == "OTHER" - assert rdata._swigptr.messages[2].severity == amici.LogSeverity_debug - assert rdata._swigptr.messages[2].identifier == "BACKTRACE" # too long simulations solver.setMaxSteps(int(1e4)) @@ -632,8 +630,6 @@ def test_simulation_errors(preeq_fixture): ) assert rdata._swigptr.messages[2].severity == amici.LogSeverity_error assert rdata._swigptr.messages[2].identifier == "OTHER" - assert rdata._swigptr.messages[3].severity == amici.LogSeverity_debug - assert rdata._swigptr.messages[3].identifier == "BACKTRACE" def test_get_model_for_preeq(preeq_fixture): diff --git a/python/tests/test_sbml_import.py b/python/tests/test_sbml_import.py index aa343dfcc3..aaab5688cc 100644 --- a/python/tests/test_sbml_import.py +++ b/python/tests/test_sbml_import.py @@ -3,7 +3,6 @@ import re from numbers import Number from pathlib import Path -from urllib.request import urlopen import amici import libsbml @@ -369,7 +368,7 @@ def test_solver_reuse(model_steadystate_module): assert rdata1.status == amici.AMICI_SUCCESS for attr in rdata1: - if "time" in attr: + if "time" in attr or attr == "messages": continue val1 = getattr(rdata1, attr) @@ -543,13 +542,13 @@ def test_sympy_exp_monkeypatch(): monkeypatching sympy.Pow._eval_derivative in order to be able to compute non-nan sensitivities """ - url = ( - "https://www.ebi.ac.uk/biomodels/model/download/BIOMD0000000529.2?" - "filename=BIOMD0000000529_url.xml" - ) - importer = amici.SbmlImporter( - urlopen(url, timeout=20).read().decode("utf-8"), from_file=False + import pooch + + model_file = pooch.retrieve( + url="https://www.ebi.ac.uk/biomodels/model/download/BIOMD0000000529.2?filename=BIOMD0000000529_url.xml", + known_hash="md5:c6e0b298397485b93d7acfab80b21fd4", ) + importer = amici.SbmlImporter(model_file) module_name = "BIOMD0000000529" with TemporaryDirectory() as outdir: @@ -723,3 +722,53 @@ def test_hardcode_parameters(simple_sbml_model): constant_parameters=["p1"], hardcode_symbols=["p1"], ) + + +def test_constraints(): + """Test non-negativity constraint handling.""" + from amici.antimony_import import antimony2amici + from amici import Constraint + + ant_model = """ + model test_non_negative_species + species A = 10 + species B = 0 + # R1: A => B; k1f * sqrt(A) + R1: A => B; k1f * max(0, A) + k1f = 1e10 + end + """ + module_name = "test_non_negative_species" + with TemporaryDirectory(prefix=module_name) as outdir: + antimony2amici( + ant_model, + model_name=module_name, + output_dir=outdir, + compute_conservation_laws=False, + ) + model_module = amici.import_model_module( + module_name=module_name, module_path=outdir + ) + amici_model = model_module.getModel() + amici_model.setTimepoints(np.linspace(0, 100, 200)) + amici_solver = amici_model.getSolver() + rdata = amici.runAmiciSimulation(amici_model, amici_solver) + assert rdata.status == amici.AMICI_SUCCESS + # should be non-negative in theory, but is expected to become negative + # in practice + assert np.any(rdata.x < 0) + + amici_solver.setRelativeTolerance(1e-14) + amici_solver.setConstraints( + [Constraint.non_negative, Constraint.non_negative] + ) + rdata = amici.runAmiciSimulation(amici_model, amici_solver) + assert rdata.status == amici.AMICI_SUCCESS + assert np.all(rdata.x >= 0) + assert np.all( + np.sum(rdata.x, axis=1) - np.sum(rdata.x[0]) + < max( + np.sum(rdata.x[0]) * amici_solver.getRelativeTolerance(), + amici_solver.getAbsoluteTolerance(), + ) + ) diff --git a/python/tests/test_sympy_utils.py b/python/tests/test_sympy_utils.py new file mode 100644 index 0000000000..da89741352 --- /dev/null +++ b/python/tests/test_sympy_utils.py @@ -0,0 +1,24 @@ +"""Tests related to the sympy_utils module.""" + +from amici.sympy_utils import _custom_pow_eval_derivative, _monkeypatched +import sympy as sp +from amici.testing import skip_on_valgrind + + +@skip_on_valgrind +def test_monkeypatch(): + t = sp.Symbol("t") + n = sp.Symbol("n") + vals = [(t, 0), (n, 1)] + + # check that the removable singularity still exists + assert (t**n).diff(t).subs(vals) is sp.nan + + # check that we can monkeypatch it out + with _monkeypatched( + sp.Pow, "_eval_derivative", _custom_pow_eval_derivative + ): + assert (t**n).diff(t).subs(vals) is not sp.nan + + # check that the monkeypatch is transient + assert (t**n).diff(t).subs(vals) is sp.nan diff --git a/scripts/buildAmici.sh b/scripts/buildAmici.sh index 507a391621..80b724c8c3 100755 --- a/scripts/buildAmici.sh +++ b/scripts/buildAmici.sh @@ -25,7 +25,28 @@ else fi # required for build swig interface -pip show numpy > /dev/null || python3 -m pip install numpy +venv_dir="${amici_path}/venv" +set +e +mkdir -p "${venv_dir}" +python3 -m venv "${venv_dir}" --clear +# in case this fails (usually due to missing ensurepip, try getting pip +# manually +if [[ $? ]]; then + set -e + python3 -m venv "${venv_dir}" --clear --without-pip + source "${venv_dir}/bin/activate" + get_pip=${amici_path}/get-pip.py + curl "https://bootstrap.pypa.io/get-pip.py" -o "${get_pip}" + python3 "${get_pip}" + rm "${get_pip}" +else + set -e + source "${venv_dir}/bin/activate" +fi + +# set python executable for cmake +export PYTHON_EXECUTABLE="${amici_path}/venv/bin/python" +python3 -m pip install numpy ${cmake} \ -Wdev -DAMICI_CXX_OPTIONS="-Wall;-Wextra${extra_cxx_flags}" \ diff --git a/scripts/buildSuiteSparse.sh b/scripts/buildSuiteSparse.sh index e916530de6..93341810f8 100755 --- a/scripts/buildSuiteSparse.sh +++ b/scripts/buildSuiteSparse.sh @@ -8,7 +8,14 @@ script_path=$(dirname "$BASH_SOURCE") amici_path=$(cd "$script_path/.." && pwd) suitesparse_root="${amici_path}/ThirdParty/SuiteSparse" -export CMAKE_OPTIONS="-DBLA_VENDOR=All -DENABLE_CUDA=FALSE -DNFORTRAN=TRUE -DNCHOLMOD=TRUE" -for subdir in SuiteSparse_config BTF AMD COLAMD KLU - do cd "${suitesparse_root}/${subdir}" && make local install +for subdir in SuiteSparse_config BTF AMD COLAMD KLU; do + export CMAKE_OPTIONS="-DSUITESPARSE_USE_CUDA=OFF -DSUITESPARSE_USE_FORTRAN=OFF" + + if [ $subdir = "SuiteSparse_config" ]; then + export CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBLA_VENDOR=All -DSUITESPARSE_USE_64BIT_BLAS=ON -DBLAS_LIBRARIES=dummy" + elif [ $subdir = "KLU" ]; then + export CMAKE_OPTIONS="$CMAKE_OPTIONS -DKLU_USE_CHOLMOD=OFF" + fi + + cd "${suitesparse_root}/${subdir}" && make local install done diff --git a/scripts/buildSundials.sh b/scripts/buildSundials.sh index c898a17d05..f3410ef31a 100755 --- a/scripts/buildSundials.sh +++ b/scripts/buildSundials.sh @@ -48,7 +48,7 @@ ${cmake} -DCMAKE_INSTALL_PREFIX="${sundials_build_path}" \ -DEXAMPLES_INSTALL=OFF \ -DENABLE_KLU=ON \ -DKLU_LIBRARY_DIR="${suitesparse_root}/lib" \ - -DKLU_INCLUDE_DIR="${suitesparse_root}/include" \ + -DKLU_INCLUDE_DIR="${suitesparse_root}/include/suitesparse" \ ${SuperLUMT} \ .. diff --git a/scripts/installAmiciArchive.sh b/scripts/installAmiciArchive.sh index 25de4f9f93..f427a91256 100755 --- a/scripts/installAmiciArchive.sh +++ b/scripts/installAmiciArchive.sh @@ -18,18 +18,18 @@ rm -f ${AMICI_PATH}/python/sdist/amici/amici_without_hdf5.py # test install from archive set +e -python3 -m venv ${AMICI_PATH}/build/venvArchive --clear +python3 -m venv ${AMICI_PATH}/venvArchive --clear # in case this fails (usually due to missing ensurepip, try getting pip # manually if [[ $? ]]; then set -e - python3 -m venv ${AMICI_PATH}/build/venvArchive --clear --without-pip - source ${AMICI_PATH}/build/venvArchive/bin/activate + python3 -m venv ${AMICI_PATH}/venvArchive --clear --without-pip + source ${AMICI_PATH}/venvArchive/bin/activate curl https://bootstrap.pypa.io/get-pip.py -o ${AMICI_PATH}/build/get-pip.py python ${AMICI_PATH}/build/get-pip.py else set -e - source ${AMICI_PATH}/build/venvArchive/bin/activate + source ${AMICI_PATH}/venvArchive/bin/activate fi pip install $(ls -t ${AMICI_PATH}/build/python/amici-*.tar.gz | head -1) diff --git a/scripts/installAmiciSource.sh b/scripts/installAmiciSource.sh index bbb4bf4a83..c074c89d46 100755 --- a/scripts/installAmiciSource.sh +++ b/scripts/installAmiciSource.sh @@ -5,12 +5,12 @@ set -e SCRIPT_PATH=$(dirname $BASH_SOURCE) AMICI_PATH=$(cd "$SCRIPT_PATH/.." && pwd) -venv_dir="${AMICI_PATH}/build/venv" # Disabled until cmake package is made compatible with updated setup.py #make python-wheel #pip3 install --user --prefix= `ls -t ${AMICI_PATH}/build/python/amici-*.whl | head -1` # test install from setup.py +venv_dir="${AMICI_PATH}/venv" set +e mkdir -p "${venv_dir}" python3 -m venv "${venv_dir}" --clear @@ -20,7 +20,7 @@ if [[ $? ]]; then set -e python3 -m venv "${venv_dir}" --clear --without-pip source "${venv_dir}/bin/activate" - get_pip=${AMICI_PATH}/build/get-pip.py + get_pip=${AMICI_PATH}/get-pip.py curl "https://bootstrap.pypa.io/get-pip.py" -o "${get_pip}" python3 "${get_pip}" rm "${get_pip}" @@ -29,6 +29,9 @@ else source "${venv_dir}/bin/activate" fi +# set python executable for cmake +export PYTHON_EXECUTABLE="${AMICI_PATH}/venv/bin/python" + python -m pip install --upgrade pip wheel python -m pip install --upgrade pip setuptools cmake_build_extension numpy python -m pip install git+https://github.com/FFroehlich/pysb@fix_pattern_matching # pin to PR for SPM with compartments diff --git a/scripts/run-SBMLTestsuite.sh b/scripts/run-SBMLTestsuite.sh index 97c2033751..a3dcee1681 100755 --- a/scripts/run-SBMLTestsuite.sh +++ b/scripts/run-SBMLTestsuite.sh @@ -9,7 +9,7 @@ if [[ ! -d "tests/sbml-test-suite" ]]; then mv -f ./sbml-test-suite ./tests/sbml-test-suite fi -source build/venv/bin/activate +source venv/bin/activate pip show pytest-xdist > /dev/null 2>&1 || pip install pytest-xdist pip install coverage pytest-cov diff --git a/scripts/run-codecov.sh b/scripts/run-codecov.sh index 42d76f7a0e..f5f253b5c9 100755 --- a/scripts/run-codecov.sh +++ b/scripts/run-codecov.sh @@ -4,7 +4,7 @@ script_path=$(dirname $BASH_SOURCE) amici_path=$(cd "$script_path"/.. && pwd) -source "${amici_path}"/build/venv/bin/activate +source "${amici_path}"/venv/bin/activate pip install coverage pytest pytest-cov if [[ -z "${BNGPATH}" ]]; then diff --git a/scripts/run-python-tests.sh b/scripts/run-python-tests.sh index d58a1c8dec..0fed628fce 100755 --- a/scripts/run-python-tests.sh +++ b/scripts/run-python-tests.sh @@ -12,7 +12,7 @@ if [[ -z "${BNGPATH}" ]]; then fi cd "${amici_path}"/python/tests -source "${amici_path}"/build/venv/bin/activate +source "${amici_path}"/venv/bin/activate # PEtab tests are run separately pytest \ diff --git a/scripts/run-valgrind-py.sh b/scripts/run-valgrind-py.sh index c2a6239ad4..9621c24d31 100755 --- a/scripts/run-valgrind-py.sh +++ b/scripts/run-valgrind-py.sh @@ -15,7 +15,7 @@ if [ $# -eq 0 ] then # No arguments supplied, run all tests cd "${amici_path}"/python/tests - source "${amici_path}"/build/venv/bin/activate + source "${amici_path}"/venv/bin/activate command=(python -m pytest -vv --ignore-glob=*petab* -W 'ignore:Signature ') # ^ ignores the following warning that occurs only under valgrind, # e.g. `valgrind python -c "import h5py"`: diff --git a/scripts/runNotebook.sh b/scripts/runNotebook.sh index bf1ef8d5e0..ee62b59cfc 100755 --- a/scripts/runNotebook.sh +++ b/scripts/runNotebook.sh @@ -25,7 +25,7 @@ if [ $# -eq 0 ]; then exit 1 fi -source ${AMICI_PATH}/build/venv/bin/activate +source ${AMICI_PATH}/venv/bin/activate pip3 show nbconvert || pip3 install --upgrade nbconvert pip3 show ipykernel || (pip3 install --upgrade ipykernel && python3 -m ipykernel install --user --name amici --display-name "Python (amici)") diff --git a/src/abstract_model.cpp b/src/abstract_model.cpp index 041d06b361..dfa0780535 100644 --- a/src/abstract_model.cpp +++ b/src/abstract_model.cpp @@ -437,10 +437,11 @@ void AbstractModel::fdJrzdsigma( ); } -void AbstractModel:: - fw(realtype* /*w*/, realtype const /*t*/, realtype const* /*x*/, - realtype const* /*p*/, realtype const* /*k*/, realtype const* /*h*/, - realtype const* /*tcl*/, realtype const* /*spl*/) { +void AbstractModel::fw( + realtype* /*w*/, realtype const /*t*/, realtype const* /*x*/, + realtype const* /*p*/, realtype const* /*k*/, realtype const* /*h*/, + realtype const* /*tcl*/, realtype const* /*spl*/, bool /*include_static*/ +) { throw AmiException( "Requested functionality is not supported as %s is " "not implemented for this model!", @@ -452,7 +453,7 @@ void AbstractModel::fdwdp( realtype* /*dwdp*/, realtype const /*t*/, realtype const* /*x*/, realtype const* /*p*/, realtype const* /*k*/, realtype const* /*h*/, realtype const* /*w*/, realtype const* /*tcl*/, realtype const* /*stcl*/, - realtype const* /*spl*/, realtype const* /*sspl*/ + realtype const* /*spl*/, realtype const* /*sspl*/, bool /*include_static*/ ) { throw AmiException( "Requested functionality is not supported as %s is " @@ -477,23 +478,11 @@ void AbstractModel::fdwdp_rowvals(SUNMatrixWrapper& /*dwdp*/) { ); } -void AbstractModel::fdwdp( - realtype* /*dwdp*/, realtype const /*t*/, realtype const* /*x*/, - realtype const* /*p*/, realtype const* /*k*/, realtype const* /*h*/, - realtype const* /*w*/, realtype const* /*tcl*/, realtype const* /*stcl*/, - realtype const* /*spl*/, realtype const* /*sspl*/, int const /*ip*/ -) { - throw AmiException( - "Requested functionality is not supported as %s is " - "not implemented for this model!", - __func__ - ); -} - void AbstractModel::fdwdx( realtype* /*dwdx*/, realtype const /*t*/, realtype const* /*x*/, realtype const* /*p*/, realtype const* /*k*/, realtype const* /*h*/, - realtype const* /*w*/, realtype const* /*tcl*/, realtype const* /*spl*/ + realtype const* /*w*/, realtype const* /*tcl*/, realtype const* /*spl*/, + bool /*include_static*/ ) { throw AmiException( "Requested functionality is not supported as %s is " @@ -521,7 +510,7 @@ void AbstractModel::fdwdx_rowvals(SUNMatrixWrapper& /*dwdx*/) { void AbstractModel::fdwdw( realtype* /*dwdw*/, realtype /*t*/, realtype const* /*x*/, realtype const* /*p*/, realtype const* /*k*/, realtype const* /*h*/, - realtype const* /*w*/, realtype const* /*tcl*/ + realtype const* /*w*/, realtype const* /*tcl*/, bool /*include_static*/ ) { throw AmiException( "Requested functionality is not supported as %s " diff --git a/src/amici.cpp b/src/amici.cpp index 6e85dde857..2f60a8e12a 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -69,6 +69,7 @@ std::map simulation_status_to_str_map = { {AMICI_MAX_TIME_EXCEEDED, "AMICI_MAX_TIME_EXCEEDED"}, {AMICI_SUCCESS, "AMICI_SUCCESS"}, {AMICI_NOT_RUN, "AMICI_NOT_RUN"}, + {AMICI_LSETUP_FAIL, "AMICI_LSETUP_FAIL"}, }; std::unique_ptr runAmiciSimulation( @@ -205,11 +206,27 @@ std::unique_ptr runAmiciSimulation( LogSeverity::error, "OTHER", "AMICI simulation failed: %s", ex.what() ); +#ifndef NDEBUG logger.log( LogSeverity::debug, "BACKTRACE", "The previous error occurred at:\n%s", ex.getBacktrace() ); +#endif + } catch (std::exception const& ex) { + rdata->status = AMICI_ERROR; + if (rethrow) + throw; + logger.log( + LogSeverity::error, "OTHER", "AMICI simulation failed: %s", + ex.what() + ); + } + try { + rdata->processSimulationObjects( + preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, + posteq.get(), model, solver, edata + ); } catch (std::exception const& ex) { rdata->status = AMICI_ERROR; if (rethrow) @@ -220,10 +237,7 @@ std::unique_ptr runAmiciSimulation( ); } - rdata->processSimulationObjects( - preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, posteq.get(), - model, solver, edata - ); + rdata->t_last = solver.gett(); rdata->cpu_time_total = cpu_timer.elapsed_milliseconds(); diff --git a/src/forwardproblem.cpp b/src/forwardproblem.cpp index b4bcd9740f..ef4585f9e9 100644 --- a/src/forwardproblem.cpp +++ b/src/forwardproblem.cpp @@ -416,7 +416,10 @@ void ForwardProblem::getAdjointUpdates(Model& model, ExpData const& edata) { } } -SimulationState ForwardProblem::getSimulationState() const { +SimulationState ForwardProblem::getSimulationState() { + if (std::isfinite(solver->gett())) { + solver->writeSolution(&t_, x_, dx_, sx_, dx_); + } auto state = SimulationState(); state.t = t_; state.x = x_; diff --git a/src/hdf5.cpp b/src/hdf5.cpp index e459eee138..0454b634f1 100644 --- a/src/hdf5.cpp +++ b/src/hdf5.cpp @@ -532,6 +532,10 @@ void writeReturnDataDiagnosis( &rdata.cpu_time_total, 1 ); + H5LTset_attribute_double( + file.getId(), hdf5Location.c_str(), "t_last", &rdata.t_last, 1 + ); + if (!rdata.J.empty()) createAndWriteDouble2DDataset( file, hdf5Location + "/J", rdata.J, rdata.nx, rdata.nx @@ -802,6 +806,11 @@ void writeSolverSettingsToHDF5( file.getId(), hdf5Location.c_str(), "maxtime", &dbuffer, 1 ); + dbuffer = solver.getMaxStepSize(); + H5LTset_attribute_double( + file.getId(), hdf5Location.c_str(), "max_step_size", &dbuffer, 1 + ); + ibuffer = gsl::narrow(solver.getMaxSteps()); H5LTset_attribute_int( file.getId(), hdf5Location.c_str(), "maxsteps", &ibuffer, 1 @@ -895,6 +904,20 @@ void writeSolverSettingsToHDF5( file.getId(), hdf5Location.c_str(), "check_sensi_steadystate_conv", &ibuffer, 1 ); + + ibuffer = static_cast(solver.getMaxNonlinIters()); + H5LTset_attribute_int( + file.getId(), hdf5Location.c_str(), "max_nonlin_iters", &ibuffer, 1 + ); + + ibuffer = static_cast(solver.getMaxConvFails()); + H5LTset_attribute_int( + file.getId(), hdf5Location.c_str(), "max_conv_fails", &ibuffer, 1 + ); + + createAndWriteDouble1DDataset( + file, hdf5Location + "/constraints", solver.getConstraints() + ); } void readSolverSettingsFromHDF5( @@ -990,6 +1013,12 @@ void readSolverSettingsFromHDF5( ); } + if (attributeExists(file, datasetPath, "max_step_size")) { + solver.setMaxStepSize( + getDoubleScalarAttribute(file, datasetPath, "max_step_size") + ); + } + if (attributeExists(file, datasetPath, "maxsteps")) { solver.setMaxSteps(getIntScalarAttribute(file, datasetPath, "maxsteps") ); @@ -1106,6 +1135,24 @@ void readSolverSettingsFromHDF5( file, datasetPath, "check_sensi_steadystate_conv" )); } + + if (attributeExists(file, datasetPath, "max_nonlin_iters")) { + solver.setMaxNonlinIters( + getIntScalarAttribute(file, datasetPath, "max_nonlin_iters") + ); + } + + if (attributeExists(file, datasetPath, "max_conv_fails")) { + solver.setMaxConvFails( + getIntScalarAttribute(file, datasetPath, "max_conv_fails") + ); + } + + if (locationExists(file, datasetPath + "/constraints")) { + solver.setConstraints( + getDoubleDataset1D(file, datasetPath + "/constraints") + ); + } } void readSolverSettingsFromHDF5( diff --git a/src/model.cpp b/src/model.cpp index 2485867a4c..cefdf1ac97 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -323,6 +323,31 @@ void Model::initialize( if (ne) initEvents(x, dx, roots_found); + + // evaluate static expressions once + auto x_pos = computeX_pos(x); + fw(t0(), x_pos, true); + fdwdw(t0(), x_pos, true); + fdwdx(t0(), x_pos, true); + if (computeSensitivities) { + fdwdp(t0(), x_pos, true); + } +} + +void Model::reinitialize( + realtype t, AmiVector& x, AmiVectorArray& sx, bool computeSensitivities +) { + fx0_fixedParameters(x); + + // re-evaluate static expressions once + auto x_pos = computeX_pos(x); + fw(t, x_pos, true); + fdwdw(t, x_pos, true); + fdwdx(t, x_pos, true); + if (computeSensitivities) { + fsx0_fixedParameters(sx, x); + fdwdp(t, x_pos, true); + } } void Model::initializeB( @@ -347,7 +372,7 @@ void Model::initializeStates(AmiVector& x) { std::copy(x0_solver.cbegin(), x0_solver.cend(), x.data()); } - checkFinite(x.getVector(), ModelQuantity::x0); + checkFinite(x.getVector(), ModelQuantity::x0, t0()); } void Model::initializeSplines() { @@ -858,11 +883,11 @@ void Model::setStateIsNonNegative(std::vector const& nonNegative) { // in case of conservation laws return; } - if (state_is_non_negative_.size() != gsl::narrow(nx_rdata)) { + if (nonNegative.size() != gsl::narrow(nx_rdata)) { throw AmiException( "Dimension of input stateIsNonNegative (%u) does " "not agree with number of state variables (%d)", - state_is_non_negative_.size(), nx_rdata + nonNegative.size(), nx_rdata ); } state_is_non_negative_ = nonNegative; @@ -1048,7 +1073,7 @@ void Model::requireSensitivitiesForAllParameters() { void Model::getExpression( gsl::span w, realtype const t, AmiVector const& x ) { - fw(t, computeX_pos(x)); + fw(t, computeX_pos(x), false); writeSlice(derived_state_.w_, w); } @@ -1457,7 +1482,7 @@ void Model::addStateEventUpdate( ); if (always_check_finite_) { - checkFinite(derived_state_.deltax_, ModelQuantity::deltax); + checkFinite(derived_state_.deltax_, ModelQuantity::deltax, t); } // update @@ -1469,7 +1494,7 @@ void Model::addStateSensitivityEventUpdate( AmiVector const& xdot, AmiVector const& xdot_old, std::vector const& stau ) { - fw(t, x_old.data()); + fw(t, x_old.data(), false); for (int ip = 0; ip < nplist(); ip++) { @@ -1511,7 +1536,7 @@ void Model::addAdjointStateEventUpdate( ); if (always_check_finite_) { - checkFinite(derived_state_.deltaxB_, ModelQuantity::deltaxB); + checkFinite(derived_state_.deltaxB_, ModelQuantity::deltaxB, t); } // apply update @@ -1557,7 +1582,7 @@ void Model::updateHeavisideB(int const* rootsfound) { } int Model::checkFinite( - gsl::span array, ModelQuantity model_quantity + gsl::span array, ModelQuantity model_quantity, realtype t ) const { auto it = std::find_if(array.begin(), array.end(), [](realtype x) { return !std::isfinite(x); @@ -1629,23 +1654,27 @@ int Model::checkFinite( gsl_ExpectsDebug(false); model_quantity_str = std::to_string(static_cast(model_quantity)); } - if (logger) + if (logger) { + auto t_msg = std::isfinite(t) + ? std::string(" at t=" + std::to_string(t) + " ") + : std::string(); + logger->log( LogSeverity::warning, msg_id, - "AMICI encountered a %s value for %s[%i] (%s)", + "AMICI encountered a %s value for %s[%i] (%s)%s", non_finite_type.c_str(), model_quantity_str.c_str(), - gsl::narrow(flat_index), element_id.c_str() + gsl::narrow(flat_index), element_id.c_str(), t_msg.c_str() ); - + } // check upstream, without infinite recursion if (model_quantity != ModelQuantity::k && model_quantity != ModelQuantity::p && model_quantity != ModelQuantity::ts) { - checkFinite(state_.fixedParameters, ModelQuantity::k); - checkFinite(state_.unscaledParameters, ModelQuantity::p); - checkFinite(simulation_parameters_.ts_, ModelQuantity::ts); + checkFinite(state_.fixedParameters, ModelQuantity::k, t); + checkFinite(state_.unscaledParameters, ModelQuantity::p, t); + checkFinite(simulation_parameters_.ts_, ModelQuantity::ts, t); if (!always_check_finite_ && model_quantity != ModelQuantity::w) { // don't check twice if always_check_finite_ is true - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(derived_state_.w_, ModelQuantity::w, t); } } return AMICI_RECOVERABLE_ERROR; @@ -1653,7 +1682,7 @@ int Model::checkFinite( int Model::checkFinite( gsl::span array, ModelQuantity model_quantity, - size_t num_cols + size_t num_cols, realtype t ) const { auto it = std::find_if(array.begin(), array.end(), [](realtype x) { return !std::isfinite(x); @@ -1743,19 +1772,25 @@ int Model::checkFinite( model_quantity_str = std::to_string(static_cast(model_quantity)); } - if (logger) + if (logger) { + auto t_msg = std::isfinite(t) + ? std::string(" at t=" + std::to_string(t) + " ") + : std::string(); + logger->log( LogSeverity::warning, msg_id, - "AMICI encountered a %s value for %s[%i] (%s, %s)", + "AMICI encountered a %s value for %s[%i] (%s, %s)%s", non_finite_type.c_str(), model_quantity_str.c_str(), - gsl::narrow(flat_index), row_id.c_str(), col_id.c_str() + gsl::narrow(flat_index), row_id.c_str(), col_id.c_str(), + t_msg.c_str() ); + } // check upstream - checkFinite(state_.fixedParameters, ModelQuantity::k); - checkFinite(state_.unscaledParameters, ModelQuantity::p); - checkFinite(simulation_parameters_.ts_, ModelQuantity::ts); - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(state_.fixedParameters, ModelQuantity::k, t); + checkFinite(state_.unscaledParameters, ModelQuantity::p, t); + checkFinite(simulation_parameters_.ts_, ModelQuantity::ts, t); + checkFinite(derived_state_.w_, ModelQuantity::w, t); return AMICI_RECOVERABLE_ERROR; } @@ -1843,10 +1878,10 @@ int Model::checkFinite(SUNMatrix m, ModelQuantity model_quantity, realtype t) ); // check upstream - checkFinite(state_.fixedParameters, ModelQuantity::k); - checkFinite(state_.unscaledParameters, ModelQuantity::p); - checkFinite(simulation_parameters_.ts_, ModelQuantity::ts); - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(state_.fixedParameters, ModelQuantity::k, t); + checkFinite(state_.unscaledParameters, ModelQuantity::p, t); + checkFinite(simulation_parameters_.ts_, ModelQuantity::ts, t); + checkFinite(derived_state_.w_, ModelQuantity::w, t); return AMICI_RECOVERABLE_ERROR; } @@ -1870,7 +1905,7 @@ void Model::fx0(AmiVector& x) { state_.unscaledParameters.data(), state_.fixedParameters.data() ); - checkFinite(derived_state_.x_rdata_, ModelQuantity::x0_rdata); + checkFinite(derived_state_.x_rdata_, ModelQuantity::x0_rdata, t0()); } void Model::fx0_fixedParameters(AmiVector& x) { @@ -1957,7 +1992,10 @@ void Model::fx_rdata(AmiVector& x_rdata, AmiVector const& x) { state_.unscaledParameters.data(), state_.fixedParameters.data() ); if (always_check_finite_) - checkFinite(x_rdata.getVector(), ModelQuantity::x_rdata); + checkFinite( + x_rdata.getVector(), ModelQuantity::x_rdata, + std::numeric_limits::quiet_NaN() + ); } void Model::fsx_rdata( @@ -2040,14 +2078,14 @@ void Model::fy(realtype const t, AmiVector const& x) { derived_state_.y_.assign(ny, 0.0); - fw(t, x_pos); + fw(t, x_pos, false); fy(derived_state_.y_.data(), t, x_pos, state_.unscaledParameters.data(), state_.fixedParameters.data(), state_.h.data(), derived_state_.w_.data()); if (always_check_finite_) { checkFinite( - gsl::make_span(derived_state_.y_.data(), ny), ModelQuantity::y + gsl::make_span(derived_state_.y_.data(), ny), ModelQuantity::y, t ); } } @@ -2059,8 +2097,8 @@ void Model::fdydp(realtype const t, AmiVector const& x) { auto x_pos = computeX_pos(x); derived_state_.dydp_.assign(ny * nplist(), 0.0); - fw(t, x_pos); - fdwdp(t, x_pos); + fw(t, x_pos, false); + fdwdp(t, x_pos, false); /* get dydp slice (ny) for current time and parameter */ for (int ip = 0; ip < nplist(); ip++) @@ -2094,8 +2132,8 @@ void Model::fdydx(realtype const t, AmiVector const& x) { derived_state_.dydx_.assign(ny * nx_solver, 0.0); - fw(t, x_pos); - fdwdx(t, x_pos); + fw(t, x_pos, false); + fdwdx(t, x_pos, false); fdydx( derived_state_.dydx_.data(), t, x_pos, state_.unscaledParameters.data(), state_.fixedParameters.data(), state_.h.data(), @@ -2249,7 +2287,7 @@ void Model::fdJydy(int const it, AmiVector const& x, ExpData const& edata) { auto tmp_sparse = SUNMatrixWrapper(tmp_dense, 0.0, CSC_MAT); auto ret = SUNMatScaleAdd( - 1.0, derived_state_.dJydy_.at(iyt).get(), tmp_sparse.get() + 1.0, derived_state_.dJydy_.at(iyt), tmp_sparse ); if (ret != SUNMAT_SUCCESS) { throw AmiException( @@ -2840,38 +2878,42 @@ void Model::fsspl(realtype const t) { } } -void Model::fw(realtype const t, realtype const* x) { - std::fill(derived_state_.w_.begin(), derived_state_.w_.end(), 0.0); +void Model::fw(realtype const t, realtype const* x, bool include_static) { + if (include_static) { + std::fill(derived_state_.w_.begin(), derived_state_.w_.end(), 0.0); + } fspl(t); fw(derived_state_.w_.data(), t, x, state_.unscaledParameters.data(), state_.fixedParameters.data(), state_.h.data(), state_.total_cl.data(), - state_.spl_.data()); + state_.spl_.data(), include_static); if (always_check_finite_) { - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(derived_state_.w_, ModelQuantity::w, t); } } -void Model::fdwdp(realtype const t, realtype const* x) { +void Model::fdwdp(realtype const t, realtype const* x, bool include_static) { if (!nw) return; - fw(t, x); + fw(t, x, include_static); derived_state_.dwdp_.zero(); if (pythonGenerated) { - if (!dwdp_hierarchical_.at(0).capacity()) + if (!ndwdp) return; fsspl(t); - fdwdw(t, x); - dwdp_hierarchical_.at(0).zero(); - fdwdp_colptrs(dwdp_hierarchical_.at(0)); - fdwdp_rowvals(dwdp_hierarchical_.at(0)); + fdwdw(t, x, include_static); + if (include_static) { + dwdp_hierarchical_.at(0).zero(); + fdwdp_colptrs(dwdp_hierarchical_.at(0)); + fdwdp_rowvals(dwdp_hierarchical_.at(0)); + } fdwdp( dwdp_hierarchical_.at(0).data(), t, x, state_.unscaledParameters.data(), state_.fixedParameters.data(), state_.h.data(), derived_state_.w_.data(), state_.total_cl.data(), state_.stotal_cl.data(), state_.spl_.data(), - derived_state_.sspl_.data() + derived_state_.sspl_.data(), include_static ); for (int irecursion = 1; irecursion <= w_recursion_depth_; @@ -2897,29 +2939,33 @@ void Model::fdwdp(realtype const t, realtype const* x) { } if (always_check_finite_) { - checkFinite(derived_state_.dwdp_.get(), ModelQuantity::dwdp, t); + checkFinite(derived_state_.dwdp_, ModelQuantity::dwdp, t); } } -void Model::fdwdx(realtype const t, realtype const* x) { +void Model::fdwdx(realtype const t, realtype const* x, bool include_static) { if (!nw) return; - fw(t, x); + fw(t, x, include_static); derived_state_.dwdx_.zero(); if (pythonGenerated) { if (!dwdx_hierarchical_.at(0).capacity()) return; - fdwdw(t, x); - dwdx_hierarchical_.at(0).zero(); - fdwdx_colptrs(dwdx_hierarchical_.at(0)); - fdwdx_rowvals(dwdx_hierarchical_.at(0)); + + fdwdw(t, x, include_static); + + if (include_static) { + dwdx_hierarchical_.at(0).zero(); + fdwdx_colptrs(dwdx_hierarchical_.at(0)); + fdwdx_rowvals(dwdx_hierarchical_.at(0)); + } fdwdx( dwdx_hierarchical_.at(0).data(), t, x, state_.unscaledParameters.data(), state_.fixedParameters.data(), state_.h.data(), derived_state_.w_.data(), state_.total_cl.data(), - state_.spl_.data() + state_.spl_.data(), include_static ); for (int irecursion = 1; irecursion <= w_recursion_depth_; @@ -2943,24 +2989,28 @@ void Model::fdwdx(realtype const t, realtype const* x) { } if (always_check_finite_) { - checkFinite(derived_state_.dwdx_.get(), ModelQuantity::dwdx, t); + checkFinite(derived_state_.dwdx_, ModelQuantity::dwdx, t); } } -void Model::fdwdw(realtype const t, realtype const* x) { - if (!nw || !dwdw_.capacity()) +void Model::fdwdw(realtype const t, realtype const* x, bool include_static) { + if (!ndwdw) return; - dwdw_.zero(); - fdwdw_colptrs(dwdw_); - fdwdw_rowvals(dwdw_); + + if (include_static) { + dwdw_.zero(); + fdwdw_colptrs(dwdw_); + fdwdw_rowvals(dwdw_); + } + fdwdw( dwdw_.data(), t, x, state_.unscaledParameters.data(), state_.fixedParameters.data(), state_.h.data(), - derived_state_.w_.data(), state_.total_cl.data() + derived_state_.w_.data(), state_.total_cl.data(), include_static ); if (always_check_finite_) { - checkFinite(dwdw_.get(), ModelQuantity::dwdw, t); + checkFinite(dwdw_, ModelQuantity::dwdw, t); } } diff --git a/src/model_dae.cpp b/src/model_dae.cpp index 3b2e74e0e1..22025e1181 100644 --- a/src/model_dae.cpp +++ b/src/model_dae.cpp @@ -14,7 +14,7 @@ void Model_DAE::fJ( realtype t, realtype cj, const_N_Vector x, const_N_Vector dx, const_N_Vector /*xdot*/, SUNMatrix J ) { - fJSparse(t, cj, x, dx, derived_state_.J_.get()); + fJSparse(t, cj, x, dx, derived_state_.J_); derived_state_.J_.refresh(); auto JDense = SUNMatrixWrapper(J); derived_state_.J_.to_dense(JDense); @@ -31,7 +31,7 @@ void Model_DAE::fJSparse( realtype t, realtype cj, const_N_Vector x, const_N_Vector dx, SUNMatrix J ) { auto x_pos = computeX_pos(x); - fdwdx(t, N_VGetArrayPointerConst(x_pos)); + fdwdx(t, N_VGetArrayPointerConst(x_pos), false); if (pythonGenerated) { auto JSparse = SUNMatrixWrapper(J); // python generated @@ -88,7 +88,7 @@ void Model_DAE::fJv( N_Vector Jv, realtype cj ) { N_VConst(0.0, Jv); - fJSparse(t, cj, x, dx, derived_state_.J_.get()); + fJSparse(t, cj, x, dx, derived_state_.J_); derived_state_.J_.refresh(); derived_state_.J_.multiply(Jv, v); } @@ -122,7 +122,7 @@ void Model_DAE::fxdot( realtype t, const_N_Vector x, const_N_Vector dx, N_Vector xdot ) { auto x_pos = computeX_pos(x); - fw(t, N_VGetArrayPointerConst(x)); + fw(t, N_VGetArrayPointerConst(x), false); N_VConst(0.0, xdot); fxdot( N_VGetArrayPointer(xdot), t, N_VGetArrayPointerConst(x_pos), @@ -135,10 +135,11 @@ void Model_DAE::fJDiag( realtype const t, AmiVector& JDiag, realtype const /*cj*/, AmiVector const& x, AmiVector const& dx ) { - fJSparse(t, 0.0, x.getNVector(), dx.getNVector(), derived_state_.J_.get()); + fJSparse(t, 0.0, x.getNVector(), dx.getNVector(), derived_state_.J_); derived_state_.J_.refresh(); derived_state_.J_.to_diag(JDiag.getNVector()); - if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag) != AMICI_SUCCESS) + if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag, t) + != AMICI_SUCCESS) throw AmiException("Evaluation of fJDiag failed!"); } @@ -171,7 +172,7 @@ void Model_DAE::fdxdotdp( ); } else { // matlab generated - fdwdp(t, N_VGetArrayPointerConst(x_pos)); + fdwdp(t, N_VGetArrayPointerConst(x_pos), false); for (int ip = 0; ip < nplist(); ip++) { N_VConst(0.0, derived_state_.dxdotdp.getNVector(ip)); @@ -355,7 +356,7 @@ void Model_DAE::fJB( realtype t, realtype cj, const_N_Vector x, const_N_Vector dx, const_N_Vector /*xB*/, const_N_Vector /*dxB*/, SUNMatrix JB ) { - fJSparse(t, cj, x, dx, derived_state_.J_.get()); + fJSparse(t, cj, x, dx, derived_state_.J_); derived_state_.J_.refresh(); auto JBDense = SUNMatrixWrapper(JB); derived_state_.J_.transpose(JBDense, -1.0, nxtrue_solver); @@ -376,7 +377,7 @@ void Model_DAE::fJSparseB( realtype t, realtype cj, const_N_Vector x, const_N_Vector dx, const_N_Vector /*xB*/, const_N_Vector /*dxB*/, SUNMatrix JB ) { - fJSparse(t, cj, x, dx, derived_state_.J_.get()); + fJSparse(t, cj, x, dx, derived_state_.J_); derived_state_.J_.refresh(); auto JSparseB = SUNMatrixWrapper(JB); derived_state_.J_.transpose(JSparseB, -1.0, nxtrue_solver); @@ -387,7 +388,7 @@ void Model_DAE::fJvB( const_N_Vector dxB, const_N_Vector vB, N_Vector JvB, realtype cj ) { N_VConst(0.0, JvB); - fJSparseB(t, cj, x, dx, xB, dxB, derived_state_.JB_.get()); + fJSparseB(t, cj, x, dx, xB, dxB, derived_state_.JB_); derived_state_.JB_.refresh(); derived_state_.JB_.multiply(JvB, vB); } @@ -397,7 +398,7 @@ void Model_DAE::fxBdot( const_N_Vector dxB, N_Vector xBdot ) { N_VConst(0.0, xBdot); - fJSparseB(t, 1.0, x, dx, xB, dxB, derived_state_.JB_.get()); + fJSparseB(t, 1.0, x, dx, xB, dxB, derived_state_.JB_); derived_state_.JB_.refresh(); fM(t, x); derived_state_.JB_.multiply(xBdot, xB); @@ -454,7 +455,7 @@ void Model_DAE::fqBdot_ss( void Model_DAE::fJSparseB_ss(SUNMatrix JB) { /* Just pass the model Jacobian on to JB */ - SUNMatCopy(derived_state_.JB_.get(), JB); + SUNMatCopy(derived_state_.JB_, JB); derived_state_.JB_.refresh(); } @@ -465,7 +466,7 @@ void Model_DAE::writeSteadystateJB( /* Get backward Jacobian */ fJSparseB( t, cj, x.getNVector(), dx.getNVector(), xB.getNVector(), - dxB.getNVector(), derived_state_.JB_.get() + dxB.getNVector(), derived_state_.JB_ ); derived_state_.JB_.refresh(); /* Switch sign, as we integrate forward in time, not backward */ @@ -491,7 +492,7 @@ void Model_DAE::fsxdot( // the same for all remaining fM(t, x); fdxdotdp(t, x, dx); - fJSparse(t, 0.0, x, dx, derived_state_.J_.get()); + fJSparse(t, 0.0, x, dx, derived_state_.J_); derived_state_.J_.refresh(); } diff --git a/src/model_ode.cpp b/src/model_ode.cpp index 52275008e3..787df210ef 100644 --- a/src/model_ode.cpp +++ b/src/model_ode.cpp @@ -14,7 +14,7 @@ void Model_ODE::fJ( void Model_ODE::fJ( realtype t, const_N_Vector x, const_N_Vector /*xdot*/, SUNMatrix J ) { - fJSparse(t, x, derived_state_.J_.get()); + fJSparse(t, x, derived_state_.J_); derived_state_.J_.refresh(); auto JDense = SUNMatrixWrapper(J); derived_state_.J_.to_dense(JDense); @@ -29,7 +29,7 @@ void Model_ODE::fJSparse( void Model_ODE::fJSparse(realtype t, const_N_Vector x, SUNMatrix J) { auto x_pos = computeX_pos(x); - fdwdx(t, N_VGetArrayPointerConst(x_pos)); + fdwdx(t, N_VGetArrayPointerConst(x_pos), false); if (pythonGenerated) { auto JSparse = SUNMatrixWrapper(J); // python generated @@ -77,7 +77,7 @@ void Model_ODE::fJv( const_N_Vector v, N_Vector Jv, realtype t, const_N_Vector x ) { N_VConst(0.0, Jv); - fJSparse(t, x, derived_state_.J_.get()); + fJSparse(t, x, derived_state_.J_); derived_state_.J_.refresh(); derived_state_.J_.multiply(Jv, v); } @@ -122,7 +122,8 @@ void Model_ODE::fJDiag( AmiVector const& x, AmiVector const& /*dx*/ ) { fJDiag(t, JDiag.getNVector(), x.getNVector()); - if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag) != AMICI_SUCCESS) + if (checkFinite(JDiag.getVector(), ModelQuantity::JDiag, t) + != AMICI_SUCCESS) throw AmiException("Evaluation of fJDiag failed!"); } @@ -143,7 +144,7 @@ void Model_ODE::fdxdotdw(realtype const t, const_N_Vector x) { void Model_ODE::fdxdotdp(realtype const t, const_N_Vector x) { auto x_pos = computeX_pos(x); - fdwdp(t, N_VGetArrayPointerConst(x_pos)); + fdwdp(t, N_VGetArrayPointerConst(x_pos), false); if (pythonGenerated) { // python generated @@ -355,7 +356,7 @@ void Model_ODE::fJB( realtype t, const_N_Vector x, const_N_Vector /*xB*/, const_N_Vector /*xBdot*/, SUNMatrix JB ) { - fJSparse(t, x, derived_state_.J_.get()); + fJSparse(t, x, derived_state_.J_); derived_state_.J_.refresh(); auto JDenseB = SUNMatrixWrapper(JB); derived_state_.J_.transpose(JDenseB, -1.0, nxtrue_solver); @@ -373,14 +374,14 @@ void Model_ODE::fJSparseB( realtype t, const_N_Vector x, const_N_Vector /*xB*/, const_N_Vector /*xBdot*/, SUNMatrix JB ) { - fJSparse(t, x, derived_state_.J_.get()); + fJSparse(t, x, derived_state_.J_); derived_state_.J_.refresh(); auto JSparseB = SUNMatrixWrapper(JB); derived_state_.J_.transpose(JSparseB, -1.0, nxtrue_solver); } void Model_ODE::fJDiag(realtype t, N_Vector JDiag, const_N_Vector x) { - fJSparse(t, x, derived_state_.J_.get()); + fJSparse(t, x, derived_state_.J_); derived_state_.J_.refresh(); derived_state_.J_.to_diag(JDiag); } @@ -390,14 +391,14 @@ void Model_ODE::fJvB( const_N_Vector xB ) { N_VConst(0.0, JvB); - fJSparseB(t, x, xB, nullptr, derived_state_.JB_.get()); + fJSparseB(t, x, xB, nullptr, derived_state_.JB_); derived_state_.JB_.refresh(); derived_state_.JB_.multiply(JvB, vB); } void Model_ODE::fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot) { N_VConst(0.0, xBdot); - fJSparseB(t, x, xB, nullptr, derived_state_.JB_.get()); + fJSparseB(t, x, xB, nullptr, derived_state_.JB_); derived_state_.JB_.refresh(); derived_state_.JB_.multiply(xBdot, xB); } @@ -456,7 +457,7 @@ void Model_ODE::fqBdot_ss(realtype /*t*/, N_Vector xB, N_Vector qBdot) const { void Model_ODE::fJSparseB_ss(SUNMatrix JB) { /* Just copy the model Jacobian */ - SUNMatCopy(derived_state_.JB_.get(), JB); + SUNMatCopy(derived_state_.JB_, JB); derived_state_.JB_.refresh(); } @@ -468,7 +469,7 @@ void Model_ODE::writeSteadystateJB( /* Get backward Jacobian */ fJSparseB( t, x.getNVector(), xB.getNVector(), xBdot.getNVector(), - derived_state_.JB_.get() + derived_state_.JB_ ); derived_state_.JB_.refresh(); /* Switch sign, as we integrate forward in time, not backward */ @@ -492,7 +493,7 @@ void Model_ODE::fsxdot( // we only need to call this for the first parameter index will be // the same for all remaining fdxdotdp(t, x); - fJSparse(t, x, derived_state_.J_.get()); + fJSparse(t, x, derived_state_.J_); derived_state_.J_.refresh(); } if (pythonGenerated) { diff --git a/src/newton_solver.cpp b/src/newton_solver.cpp index 8c3fcca5f4..c14b05c7f2 100644 --- a/src/newton_solver.cpp +++ b/src/newton_solver.cpp @@ -108,7 +108,7 @@ void NewtonSolver::computeNewtonSensis( NewtonSolverDense::NewtonSolverDense(Model const& model) : NewtonSolver(model) , Jtmp_(model.nx_solver, model.nx_solver) - , linsol_(SUNLinSol_Dense(x_.getNVector(), Jtmp_.get())) { + , linsol_(SUNLinSol_Dense(x_.getNVector(), Jtmp_)) { auto status = SUNLinSolInitialize_Dense(linsol_); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSolInitialize_Dense"); @@ -117,9 +117,9 @@ NewtonSolverDense::NewtonSolverDense(Model const& model) void NewtonSolverDense::prepareLinearSystem( Model& model, SimulationState const& state ) { - model.fJ(state.t, 0.0, state.x, state.dx, xdot_, Jtmp_.get()); + model.fJ(state.t, 0.0, state.x, state.dx, xdot_, Jtmp_); Jtmp_.refresh(); - auto status = SUNLinSolSetup_Dense(linsol_, Jtmp_.get()); + auto status = SUNLinSolSetup_Dense(linsol_, Jtmp_); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSolSetup_Dense"); } @@ -127,16 +127,16 @@ void NewtonSolverDense::prepareLinearSystem( void NewtonSolverDense::prepareLinearSystemB( Model& model, SimulationState const& state ) { - model.fJB(state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_.get()); + model.fJB(state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_); Jtmp_.refresh(); - auto status = SUNLinSolSetup_Dense(linsol_, Jtmp_.get()); + auto status = SUNLinSolSetup_Dense(linsol_, Jtmp_); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSolSetup_Dense"); } void NewtonSolverDense::solveLinearSystem(AmiVector& rhs) { auto status = SUNLinSolSolve_Dense( - linsol_, Jtmp_.get(), rhs.getNVector(), rhs.getNVector(), 0.0 + linsol_, Jtmp_, rhs.getNVector(), rhs.getNVector(), 0.0 ); Jtmp_.refresh(); // last argument is tolerance and does not have any influence on result @@ -167,7 +167,7 @@ NewtonSolverDense::~NewtonSolverDense() { NewtonSolverSparse::NewtonSolverSparse(Model const& model) : NewtonSolver(model) , Jtmp_(model.nx_solver, model.nx_solver, model.nnz, CSC_MAT) - , linsol_(SUNKLU(x_.getNVector(), Jtmp_.get())) { + , linsol_(SUNKLU(x_.getNVector(), Jtmp_)) { auto status = SUNLinSolInitialize_KLU(linsol_); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSolInitialize_KLU"); @@ -177,9 +177,9 @@ void NewtonSolverSparse::prepareLinearSystem( Model& model, SimulationState const& state ) { /* Get sparse Jacobian */ - model.fJSparse(state.t, 0.0, state.x, state.dx, xdot_, Jtmp_.get()); + model.fJSparse(state.t, 0.0, state.x, state.dx, xdot_, Jtmp_); Jtmp_.refresh(); - auto status = SUNLinSolSetup_KLU(linsol_, Jtmp_.get()); + auto status = SUNLinSolSetup_KLU(linsol_, Jtmp_); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSolSetup_KLU"); } @@ -188,11 +188,9 @@ void NewtonSolverSparse::prepareLinearSystemB( Model& model, SimulationState const& state ) { /* Get sparse Jacobian */ - model.fJSparseB( - state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_.get() - ); + model.fJSparseB(state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_); Jtmp_.refresh(); - auto status = SUNLinSolSetup_KLU(linsol_, Jtmp_.get()); + auto status = SUNLinSolSetup_KLU(linsol_, Jtmp_); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSolSetup_KLU"); } @@ -200,7 +198,7 @@ void NewtonSolverSparse::prepareLinearSystemB( void NewtonSolverSparse::solveLinearSystem(AmiVector& rhs) { /* Pass pointer to the linear solver */ auto status = SUNLinSolSolve_KLU( - linsol_, Jtmp_.get(), rhs.getNVector(), rhs.getNVector(), 0.0 + linsol_, Jtmp_, rhs.getNVector(), rhs.getNVector(), 0.0 ); // last argument is tolerance and does not have any influence on result @@ -211,7 +209,7 @@ void NewtonSolverSparse::solveLinearSystem(AmiVector& rhs) { void NewtonSolverSparse::reinitialize() { /* partial reinitialization, don't need to reallocate Jtmp_ */ auto status = SUNLinSol_KLUReInit( - linsol_, Jtmp_.get(), Jtmp_.capacity(), SUNKLU_REINIT_PARTIAL + linsol_, Jtmp_, Jtmp_.capacity(), SUNKLU_REINIT_PARTIAL ); if (status != SUNLS_SUCCESS) throw NewtonFailure(status, "SUNLinSol_KLUReInit"); diff --git a/src/solver.cpp b/src/solver.cpp index 1a74e8b44b..6fc1132c4d 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -44,6 +44,9 @@ Solver::Solver(Solver const& other) , rdata_mode_(other.rdata_mode_) , newton_step_steadystate_conv_(other.newton_step_steadystate_conv_) , check_sensi_steadystate_conv_(other.check_sensi_steadystate_conv_) + , max_nonlin_iters_(other.max_nonlin_iters_) + , max_conv_fails_(other.max_conv_fails_) + , max_step_size_(other.max_step_size_) , maxstepsB_(other.maxstepsB_) , sensi_(other.sensi_) {} @@ -191,8 +194,14 @@ void Solver::setup( if (model->nt() > 1) calcIC(model->getTimepoint(1)); + apply_max_nonlin_iters(); + apply_max_conv_fails(); + apply_max_step_size(); + cpu_time_ = 0.0; cpu_timeB_ = 0.0; + + apply_constraints(); } void Solver::setupB( @@ -251,13 +260,14 @@ void Solver::setupSteadystate( } void Solver::updateAndReinitStatesAndSensitivities(Model* model) const { - model->fx0_fixedParameters(x_); - reInit(t_, x_, dx_); + model->reinitialize( + t_, x_, sx_, getSensitivityOrder() >= SensitivityOrder::first + ); - if (getSensitivityOrder() >= SensitivityOrder::first) { - model->fsx0_fixedParameters(sx_, x_); - if (getSensitivityMethod() == SensitivityMethod::forward) - sensReInit(sx_, sdx_); + reInit(t_, x_, dx_); + if (getSensitivityOrder() >= SensitivityOrder::first + && getSensitivityMethod() == SensitivityMethod::forward) { + sensReInit(sx_, sdx_); } } @@ -552,7 +562,9 @@ bool operator==(Solver const& a, Solver const& b) { == b.newton_step_steadystate_conv_) && (a.check_sensi_steadystate_conv_ == b.check_sensi_steadystate_conv_) - && (a.rdata_mode_ == b.rdata_mode_); + && (a.rdata_mode_ == b.rdata_mode_) + && (a.max_conv_fails_ == b.max_conv_fails_) + && (a.max_nonlin_iters_ == b.max_nonlin_iters_); } void Solver::applyTolerances() const { @@ -636,6 +648,15 @@ void Solver::applySensitivityTolerances() const { } } +void Solver::apply_constraints() const { + if (constraints_.getLength() != 0 + && gsl::narrow(constraints_.getLength()) != nx()) { + throw std::invalid_argument( + "Constraints must have the same size as the state vector." + ); + } +} + SensitivityMethod Solver::getSensitivityMethod() const { return sensi_meth_; } SensitivityMethod Solver::getSensitivityMethodPreequilibration() const { @@ -665,6 +686,47 @@ void Solver::checkSensitivityMethod( resetMutableMemory(nx(), nplist(), nquad()); } +void Solver::setMaxNonlinIters(int max_nonlin_iters) { + if (max_nonlin_iters < 0) + throw AmiException("max_nonlin_iters must be a non-negative number"); + + max_nonlin_iters_ = max_nonlin_iters; +} + +int Solver::getMaxNonlinIters() const { return max_nonlin_iters_; } + +void Solver::setMaxConvFails(int max_conv_fails) { + if (max_conv_fails < 0) + throw AmiException("max_conv_fails must be a non-negative number"); + + max_conv_fails_ = max_conv_fails; +} + +int Solver::getMaxConvFails() const { return max_conv_fails_; } + +void Solver::setConstraints(std::vector const& constraints) { + auto any_constraint + = std::any_of(constraints.begin(), constraints.end(), [](bool x) { + return x != 0.0; + }); + + if (!any_constraint) { + // all-0 must be converted to empty, otherwise sundials will fail + constraints_ = AmiVector(); + return; + } + + constraints_ = AmiVector(constraints); +} + +void Solver::setMaxStepSize(realtype max_step_size) { + if (max_step_size < 0) + throw AmiException("max_step_size must be non-negative."); + max_step_size_ = max_step_size; +} + +realtype Solver::getMaxStepSize() const { return max_step_size_; } + int Solver::getNewtonMaxSteps() const { return newton_maxsteps_; } void Solver::setNewtonMaxSteps(int const newton_maxsteps) { @@ -1150,6 +1212,8 @@ void Solver::resetMutableMemory(int const nx, int const nplist, int const nquad) sx_ = AmiVectorArray(nx, nplist); sdx_ = AmiVectorArray(nx, nplist); + dky_ = AmiVector(nx); + xB_ = AmiVector(nx); dxB_ = AmiVector(nx); xQB_ = AmiVector(nquad); diff --git a/src/solver_cvodes.cpp b/src/solver_cvodes.cpp index f5150a87c7..e5771ff391 100644 --- a/src/solver_cvodes.cpp +++ b/src/solver_cvodes.cpp @@ -257,6 +257,37 @@ void CVodeSolver::setSparseJacFn_ss() const { throw CvodeException(status, "CVodeSetJacFn"); } +void CVodeSolver::apply_max_nonlin_iters() const { + int status + = CVodeSetMaxNonlinIters(solver_memory_.get(), getMaxNonlinIters()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetMaxNonlinIters"); +} + +void CVodeSolver::apply_max_conv_fails() const { + int status = CVodeSetMaxConvFails(solver_memory_.get(), getMaxConvFails()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetMaxConvFails"); +} + +void CVodeSolver::apply_constraints() const { + Solver::apply_constraints(); + + int status = CVodeSetConstraints( + solver_memory_.get(), + constraints_.getLength() > 0 ? constraints_.getNVector() : nullptr + ); + if (status != CV_SUCCESS) { + throw CvodeException(status, "CVodeSetConstraints"); + } +} + +void CVodeSolver::apply_max_step_size() const { + int status = CVodeSetMaxStep(solver_memory_.get(), getMaxStepSize()); + if (status != CV_SUCCESS) + throw CvodeException(status, "CVodeSetMaxStep"); +} + Solver* CVodeSolver::clone() const { return new CVodeSolver(*this); } void CVodeSolver::allocateSolver() const { @@ -914,7 +945,7 @@ fJB(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, SUNMatrix JB, Expects(model); model->fJB(t, x, xB, xBdot, JB); - return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB); + return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB, t); } /** @@ -965,7 +996,7 @@ static int fJSparseB( Expects(model); model->fJSparseB(t, x, xB, xBdot, JB); - return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB); + return model->checkFinite(gsl::make_span(JB), ModelQuantity::JB, t); } /** @@ -1028,7 +1059,7 @@ fJv(N_Vector v, N_Vector Jv, realtype t, N_Vector x, N_Vector /*xdot*/, Expects(model); model->fJv(v, Jv, t, x); - return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv); + return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv, t); } /** @@ -1054,7 +1085,7 @@ static int fJvB( Expects(model); model->fJvB(vB, JvB, t, x, xB); - return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB); + return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB, t); } /** @@ -1081,7 +1112,7 @@ static int froot(realtype t, N_Vector x, realtype* root, void* user_data) { model->froot(t, x, gsl::make_span(root, model->ne_solver)); } return model->checkFinite( - gsl::make_span(root, model->ne_solver), ModelQuantity::root + gsl::make_span(root, model->ne_solver), ModelQuantity::root, t ); } @@ -1106,7 +1137,7 @@ static int fxdot(realtype t, N_Vector x, N_Vector xdot, void* user_data) { } if (t > 1e200 - && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot)) { + && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot, t)) { /* when t is large (typically ~1e300), CVODES may pass all NaN x to fxdot from which we typically cannot recover. To save time on normal execution, we do not always want to check finiteness @@ -1115,7 +1146,7 @@ static int fxdot(realtype t, N_Vector x, N_Vector xdot, void* user_data) { } model->fxdot(t, x, xdot); - return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot); + return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot, t); } /** @@ -1141,7 +1172,7 @@ fxBdot(realtype t, N_Vector x, N_Vector xB, N_Vector xBdot, void* user_data) { } model->fxBdot(t, x, xB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot); + return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot, t); } /** @@ -1161,7 +1192,7 @@ fqBdot(realtype t, N_Vector x, N_Vector xB, N_Vector qBdot, void* user_data) { Expects(model); model->fqBdot(t, x, xB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot); + return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot, t); } /** @@ -1180,7 +1211,9 @@ static int fxBdot_ss(realtype t, N_Vector xB, N_Vector xBdot, void* user_data) { Expects(model); model->fxBdot_ss(t, xB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot_ss); + return model->checkFinite( + gsl::make_span(xBdot), ModelQuantity::xBdot_ss, t + ); } /** @@ -1199,7 +1232,9 @@ static int fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot, void* user_data) { Expects(model); model->fqBdot_ss(t, xB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot_ss); + return model->checkFinite( + gsl::make_span(qBdot), ModelQuantity::qBdot_ss, t + ); } /** @@ -1215,8 +1250,8 @@ static int fqBdot_ss(realtype t, N_Vector xB, N_Vector qBdot, void* user_data) { * @return status flag indicating successful execution */ static int fJSparseB_ss( - realtype /*t*/, N_Vector /*x*/, N_Vector xBdot, SUNMatrix JB, - void* user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/ + realtype t, N_Vector /*x*/, N_Vector xBdot, SUNMatrix JB, void* user_data, + N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/ ) { auto typed_udata = static_cast(user_data); Expects(typed_udata); @@ -1225,7 +1260,7 @@ static int fJSparseB_ss( model->fJSparseB_ss(JB); return model->checkFinite( - gsl::make_span(xBdot), ModelQuantity::JSparseB_ss + gsl::make_span(xBdot), ModelQuantity::JSparseB_ss, t ); } @@ -1254,7 +1289,7 @@ static int fsxdot( Expects(model); model->fsxdot(t, x, ip, sx, sxdot); - return model->checkFinite(gsl::make_span(sxdot), ModelQuantity::sxdot); + return model->checkFinite(gsl::make_span(sxdot), ModelQuantity::sxdot, t); } bool operator==(CVodeSolver const& a, CVodeSolver const& b) { diff --git a/src/solver_idas.cpp b/src/solver_idas.cpp index dac085e98d..4f96c95f86 100644 --- a/src/solver_idas.cpp +++ b/src/solver_idas.cpp @@ -254,6 +254,37 @@ void IDASolver::setSparseJacFn_ss() const { throw IDAException(status, "IDASetJacFn"); } +void IDASolver::apply_max_nonlin_iters() const { + int status + = IDASetMaxNonlinIters(solver_memory_.get(), getMaxNonlinIters()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetMaxNonlinIters"); +} + +void IDASolver::apply_max_conv_fails() const { + int status = IDASetMaxConvFails(solver_memory_.get(), getMaxConvFails()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetMaxConvFails"); +} + +void IDASolver::apply_constraints() const { + Solver::apply_constraints(); + + int status = IDASetConstraints( + solver_memory_.get(), + constraints_.getLength() > 0 ? constraints_.getNVector() : nullptr + ); + if (status != IDA_SUCCESS) { + throw IDAException(status, "IDASetConstraints"); + } +} + +void IDASolver::apply_max_step_size() const { + int status = IDASetMaxStep(solver_memory_.get(), getMaxStepSize()); + if (status != IDA_SUCCESS) + throw IDAException(status, "IDASetMaxStep"); +} + Solver* IDASolver::clone() const { return new IDASolver(*this); } void IDASolver::allocateSolver() const { @@ -1052,7 +1083,7 @@ int fJv( Expects(model); model->fJv(t, x, dx, v, Jv, cj); - return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv); + return model->checkFinite(gsl::make_span(Jv), ModelQuantity::Jv, t); } /** @@ -1083,7 +1114,7 @@ int fJvB( Expects(model); model->fJvB(t, x, dx, xB, dxB, vB, JvB, cj); - return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB); + return model->checkFinite(gsl::make_span(JvB), ModelQuantity::JvB, t); } /** @@ -1105,7 +1136,7 @@ int froot( model->froot(t, x, dx, gsl::make_span(root, model->ne)); return model->checkFinite( - gsl::make_span(root, model->ne), ModelQuantity::root + gsl::make_span(root, model->ne), ModelQuantity::root, t ); } @@ -1131,7 +1162,7 @@ int fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot, void* user_data) { } if (t > 1e200 - && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot)) { + && !model->checkFinite(gsl::make_span(x), ModelQuantity::xdot, t)) { /* when t is large (typically ~1e300), CVODES may pass all NaN x to fxdot from which we typically cannot recover. To save time on normal execution, we do not always want to check finiteness @@ -1140,7 +1171,7 @@ int fxdot(realtype t, N_Vector x, N_Vector dx, N_Vector xdot, void* user_data) { } model->fxdot(t, x, dx, xdot); - return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot); + return model->checkFinite(gsl::make_span(xdot), ModelQuantity::xdot, t); } /** @@ -1170,7 +1201,7 @@ int fxBdot( } model->fxBdot(t, x, dx, xB, dxB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot); + return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot, t); } /** @@ -1195,7 +1226,7 @@ int fqBdot( Expects(model); model->fqBdot(t, x, dx, xB, dxB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot); + return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot, t); } /** @@ -1217,7 +1248,9 @@ static int fxBdot_ss( Expects(model); model->fxBdot_ss(t, xB, dxB, xBdot); - return model->checkFinite(gsl::make_span(xBdot), ModelQuantity::xBdot_ss); + return model->checkFinite( + gsl::make_span(xBdot), ModelQuantity::xBdot_ss, t + ); } /** @@ -1239,7 +1272,9 @@ static int fqBdot_ss( Expects(model); model->fqBdot_ss(t, xB, dxB, qBdot); - return model->checkFinite(gsl::make_span(qBdot), ModelQuantity::qBdot_ss); + return model->checkFinite( + gsl::make_span(qBdot), ModelQuantity::qBdot_ss, t + ); } /** @@ -1257,7 +1292,7 @@ static int fqBdot_ss( * @return status flag indicating successful execution */ static int fJSparseB_ss( - realtype /*t*/, realtype /*cj*/, N_Vector /*x*/, N_Vector /*dx*/, + realtype t, realtype /*cj*/, N_Vector /*x*/, N_Vector /*dx*/, N_Vector xBdot, SUNMatrix JB, void* user_data, N_Vector /*tmp1*/, N_Vector /*tmp2*/, N_Vector /*tmp3*/ ) { @@ -1268,7 +1303,7 @@ static int fJSparseB_ss( model->fJSparseB_ss(JB); return model->checkFinite( - gsl::make_span(xBdot), ModelQuantity::JSparseB_ss + gsl::make_span(xBdot), ModelQuantity::JSparseB_ss, t ); } @@ -1301,7 +1336,9 @@ int fsxdot( for (int ip = 0; ip < model->nplist(); ip++) { model->fsxdot(t, x, dx, ip, sx[ip], sdx[ip], sxdot[ip]); - if (model->checkFinite(gsl::make_span(sxdot[ip]), ModelQuantity::sxdot) + if (model->checkFinite( + gsl::make_span(sxdot[ip]), ModelQuantity::sxdot, t + ) != AMICI_SUCCESS) return AMICI_RECOVERABLE_ERROR; } diff --git a/src/sundials_linsol_wrapper.cpp b/src/sundials_linsol_wrapper.cpp index 765f2a1f91..5752ea03c3 100644 --- a/src/sundials_linsol_wrapper.cpp +++ b/src/sundials_linsol_wrapper.cpp @@ -161,7 +161,7 @@ SUNLinSolBand::SUNLinSolBand(N_Vector x, SUNMatrix A) SUNLinSolBand::SUNLinSolBand(AmiVector const& x, int ubw, int lbw) : A_(SUNMatrixWrapper(x.getLength(), ubw, lbw)) { - solver_ = SUNLinSol_Band(const_cast(x.getNVector()), A_.get()); + solver_ = SUNLinSol_Band(const_cast(x.getNVector()), A_); if (!solver_) throw AmiException("Failed to create solver."); } @@ -170,7 +170,7 @@ SUNMatrix SUNLinSolBand::getMatrix() const { return A_.get(); } SUNLinSolDense::SUNLinSolDense(AmiVector const& x) : A_(SUNMatrixWrapper(x.getLength(), x.getLength())) { - solver_ = SUNLinSol_Dense(const_cast(x.getNVector()), A_.get()); + solver_ = SUNLinSol_Dense(const_cast(x.getNVector()), A_); if (!solver_) throw AmiException("Failed to create solver."); } @@ -187,7 +187,7 @@ SUNLinSolKLU::SUNLinSolKLU( AmiVector const& x, int nnz, int sparsetype, StateOrdering ordering ) : A_(SUNMatrixWrapper(x.getLength(), x.getLength(), nnz, sparsetype)) { - solver_ = SUNLinSol_KLU(const_cast(x.getNVector()), A_.get()); + solver_ = SUNLinSol_KLU(const_cast(x.getNVector()), A_); if (!solver_) throw AmiException("Failed to create solver."); @@ -197,7 +197,7 @@ SUNLinSolKLU::SUNLinSolKLU( SUNMatrix SUNLinSolKLU::getMatrix() const { return A_.get(); } void SUNLinSolKLU::reInit(int nnz, int reinit_type) { - int status = SUNLinSol_KLUReInit(solver_, A_.get(), nnz, reinit_type); + int status = SUNLinSol_KLUReInit(solver_, A_, nnz, reinit_type); if (status != SUNLS_SUCCESS) throw AmiException("SUNLinSol_KLUReInit failed with %d", status); } diff --git a/src/vector.cpp b/src/vector.cpp index 78b66d7954..460b92c71c 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -53,7 +53,6 @@ void AmiVector::copy(AmiVector const& other) { getLength(), other.getLength() ); std::copy(other.vec_.begin(), other.vec_.end(), vec_.begin()); - synchroniseNVector(); } void AmiVector::synchroniseNVector() { diff --git a/swig/amici.i b/swig/amici.i index 3518b296fe..46a58f8365 100644 --- a/swig/amici.i +++ b/swig/amici.i @@ -235,6 +235,14 @@ def __repr__(self): %} }; +%extend amici::LogItem { +%pythoncode %{ +def __repr__(self): + return (f"{self.__class__.__name__}(severity={self.severity}, " + f"identifier={self.identifier!r}, message={self.message!r})") +%} +}; + // Convert integer values to enum class // defeats the purpose of enum class, but didn't find a better way to allow for @@ -319,6 +327,7 @@ SteadyStateStatus = enum('SteadyStateStatus') NewtonDampingFactorMode = enum('NewtonDampingFactorMode') FixedParameterContext = enum('FixedParameterContext') RDataReporting = enum('RDataReporting') +Constraint = enum('Constraint') %} %template(SteadyStateStatusVector) std::vector; diff --git a/swig/model.i b/swig/model.i index ee3286e1a4..fdb8ad9c85 100644 --- a/swig/model.i +++ b/swig/model.i @@ -37,6 +37,7 @@ using namespace amici; %ignore initializeB; %ignore initializeStateSensitivities; %ignore initializeStates; +%ignore reinitialize; %ignore ModelState; %ignore getModelState; %ignore setModelState; diff --git a/swig/std_unique_ptr.i b/swig/std_unique_ptr.i index c44513bcee..f73babfd9e 100644 --- a/swig/std_unique_ptr.i +++ b/swig/std_unique_ptr.i @@ -17,7 +17,7 @@ namespace std { pointer operator-> () const; pointer release (); - void reset (pointer __p=pointer()); + void reset (pointer __p=std::unique_ptr::pointer()); void swap (unique_ptr &__u); pointer get () const; operator bool () const; diff --git a/tests/cpp/testfunctions.cpp b/tests/cpp/testfunctions.cpp index 3e03eedfc4..8a8054f147 100644 --- a/tests/cpp/testfunctions.cpp +++ b/tests/cpp/testfunctions.cpp @@ -192,13 +192,6 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, // CHECK_EQUAL(AMICI_O2MODE_FULL, udata->o2mode); - if(hdf5::locationExists(file, resultPath + "/diagnosis/J")) { - expected = hdf5::getDoubleDataset2D(file, resultPath + "/diagnosis/J", m, n); - checkEqualArray(expected, rdata->J, atol, rtol, "J"); - } else { - ASSERT_TRUE(rdata->J.empty()); - } - if(hdf5::locationExists(file, resultPath + "/y")) { expected = hdf5::getDoubleDataset2D(file, resultPath + "/y", m, n); checkEqualArray(expected, rdata->y, atol, rtol, "y"); @@ -234,12 +227,22 @@ void verifyReturnData(std::string const& hdffile, std::string const& resultPath, ASSERT_TRUE(rdata->sigmaz.empty()); } - expected = hdf5::getDoubleDataset1D(file, resultPath + "/diagnosis/xdot"); - checkEqualArray(expected, rdata->xdot, atol, rtol, "xdot"); - expected = hdf5::getDoubleDataset1D(file, resultPath + "/x0"); checkEqualArray(expected, rdata->x0, atol, rtol, "x0"); + if(rdata->status == AMICI_SUCCESS) { + // for the failed cases, the stored results don't match + // since https://github.com/AMICI-dev/AMICI/pull/2349 + expected = hdf5::getDoubleDataset1D(file, resultPath + "/diagnosis/xdot"); + checkEqualArray(expected, rdata->xdot, atol, rtol, "xdot"); + + if(hdf5::locationExists(file, resultPath + "/diagnosis/J")) { + expected = hdf5::getDoubleDataset2D(file, resultPath + "/diagnosis/J", m, n); + checkEqualArray(expected, rdata->J, atol, rtol, "J"); + } else { + ASSERT_TRUE(rdata->J.empty()); + } + } if(rdata->sensi >= SensitivityOrder::first) { verifyReturnDataSensitivities(file, resultPath, rdata, model, atol, rtol); } else { diff --git a/tests/cpp/unittests/testMisc.cpp b/tests/cpp/unittests/testMisc.cpp index 1f464b3433..a722b567a7 100644 --- a/tests/cpp/unittests/testMisc.cpp +++ b/tests/cpp/unittests/testMisc.cpp @@ -681,7 +681,7 @@ TEST(UnravelIndex, UnravelIndexSunMatDense) A.set_data(2, 1, 5); for(int i = 0; i < 6; ++i) { - auto idx = unravel_index(i, A.get()); + auto idx = unravel_index(i, A); EXPECT_EQ(A.get_data(idx.first, idx.second), i); } } @@ -706,7 +706,7 @@ TEST(UnravelIndex, UnravelIndexSunMatSparse) D.set_data(2, 1, 0); D.set_data(3, 1, 0); - auto S = SUNSparseFromDenseMatrix(D.get(), 1e-15, CSC_MAT); + auto S = SUNSparseFromDenseMatrix(D, 1e-15, CSC_MAT); EXPECT_EQ(unravel_index(0, S), std::make_pair((sunindextype) 2, (sunindextype) 0)); EXPECT_EQ(unravel_index(1, S), std::make_pair((sunindextype) 3, (sunindextype) 0)); @@ -720,8 +720,8 @@ TEST(UnravelIndex, UnravelIndexSunMatSparseMissingIndices) { // Sparse matrix without any indices set SUNMatrixWrapper mat = SUNMatrixWrapper(2, 3, 2, CSC_MAT); - EXPECT_EQ(unravel_index(0, mat.get()), std::make_pair((sunindextype) -1, (sunindextype) -1)); - EXPECT_EQ(unravel_index(1, mat.get()), std::make_pair((sunindextype) -1, (sunindextype) -1)); + EXPECT_EQ(unravel_index(0, mat), std::make_pair((sunindextype) -1, (sunindextype) -1)); + EXPECT_EQ(unravel_index(1, mat), std::make_pair((sunindextype) -1, (sunindextype) -1)); } diff --git a/tests/testSBMLSuite.py b/tests/testSBMLSuite.py index cfad477ac4..2feb3ea7e8 100755 --- a/tests/testSBMLSuite.py +++ b/tests/testSBMLSuite.py @@ -130,10 +130,12 @@ def verify_results(settings, rdata, expected, wrapper, model, atol, rtol): # collect parameters for par in model.getParameterIds(): simulated[par] = rdata["ts"] * 0 + model.getParameterById(par) - # collect fluxes + # collect fluxes and other expressions for expr_idx, expr_id in enumerate(model.getExpressionIds()): if expr_id.startswith("flux_"): simulated[expr_id.removeprefix("flux_")] = rdata.w[:, expr_idx] + elif expr_id.removeprefix("amici_") not in simulated.columns: + simulated[expr_id] = rdata.w[:, expr_idx] # handle renamed reserved symbols simulated.rename( columns={c: c.replace("amici_", "") for c in simulated.columns}, diff --git a/version.txt b/version.txt index 2157409059..ca222b7cf3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.22.0 +0.23.0