From b355ab7c58eda8ecd3a6c9c396fe8a8a5147ea6a Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:52:40 +0100 Subject: [PATCH 01/46] GHA: only try to publish docker image if secrets are set (#2310) --- .github/workflows/deploy_protected.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) 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: From 16ec8b279f4bf9bf3bb0192170f0e5bd2dbd096c Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:56:15 +0100 Subject: [PATCH 02/46] Refactor DEExporter/DEModel/csc_matrix (#2311) * Refactor DEExporter/DEModel/csc_matrix Reduce unnecessary coupling: * `csc_matrix` as free function - removes the need for the codeprinter in DEModel * Move the codeprinter to `DEExporter` where it's actually needed * .. --- python/sdist/amici/cxxcodeprinter.py | 165 +++++++++++++-------------- python/sdist/amici/de_export.py | 54 +++++---- python/sdist/amici/pysb_import.py | 8 +- python/tests/test_ode_export.py | 13 +-- 4 files changed, 119 insertions(+), 121 deletions(-) diff --git a/python/sdist/amici/cxxcodeprinter.py b/python/sdist/amici/cxxcodeprinter.py index 3fe5b8cd17..032089393d 100644 --- a/python/sdist/amici/cxxcodeprinter.py +++ b/python/sdist/amici/cxxcodeprinter.py @@ -207,90 +207,6 @@ def format_line(symbol: sp.Symbol): 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 +276,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] == 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, + ) diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index f2badbea76..0a6813a6ca 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -44,7 +44,11 @@ splines, ) from .constants import SymbolId -from .cxxcodeprinter import AmiciCxxCodePrinter, get_switch_statement +from .cxxcodeprinter import ( + AmiciCxxCodePrinter, + get_switch_statement, + csc_matrix, +) from .de_model import * from .import_utils import ( ObservableTransformation, @@ -725,9 +729,6 @@ class DEModel: 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 """ @@ -869,10 +870,6 @@ def cached_simplify( 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 @@ -1882,7 +1879,7 @@ def _generate_sparse_symbol(self, name: str) -> None: sparse_list, symbol_list, sparse_matrix, - ) = self._code_printer.csc_matrix( + ) = csc_matrix( matrix[iy, :], rownames=rownames, colnames=colnames, @@ -1900,7 +1897,7 @@ def _generate_sparse_symbol(self, name: str) -> None: sparse_list, symbol_list, sparse_matrix, - ) = self._code_printer.csc_matrix( + ) = csc_matrix( matrix, rownames=rownames, colnames=colnames, @@ -2884,6 +2881,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 @@ -2950,10 +2950,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") ) @@ -3519,7 +3523,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 +3538,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 +3556,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 +3571,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 +3581,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 +3589,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 +3609,12 @@ 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( + 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 +3770,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( @@ -3961,7 +3965,7 @@ 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)) ) diff --git a/python/sdist/amici/pysb_import.py b/python/sdist/amici/pysb_import.py index 4f843033f1..c79a8c50f9 100644 --- a/python/sdist/amici/pysb_import.py +++ b/python/sdist/amici/pysb_import.py @@ -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/tests/test_ode_export.py b/python/tests/test_ode_export.py index f34d78892d..65af2935bb 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")], From 8271da178d915bf098767aa0c0bd7a0e814bd4f3 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:44:43 +0100 Subject: [PATCH 03/46] Don't eliminate parameters that are initial assignment targets (pt1) (#2304) Currently, parameters that are targets of initial assignments don't show up as parameters or expressions in the amici model. This is rather not what most users would expect. As a first step: treat all SBML parameters that are initial assignment targets and whose initial assignment evaluates to a number as amici parameters. Related to #2150. --- python/sdist/amici/sbml_import.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 8d36ad7b81..9d6b7229c5 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -1051,15 +1051,23 @@ def _process_parameters( "Parameter does not exist." % parameter ) + # parameter ID => initial assignment sympy expression + par_id_to_ia = { + par.getId(): ia + 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 +1082,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,16 +1102,16 @@ 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) for par in self.sbml.getListOfParameters(): - if ( - ia := self._get_element_initial_assignment(par.getId()) - ) is not None and ia.find( + if (ia := par_id_to_ia.get(par.getId())) is not None and ia.find( sp.core.function.UndefinedFunction("rateOf") ): self.symbols[SymbolId.EXPRESSION][ @@ -1877,7 +1888,10 @@ 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.PARAMETER], + self.symbols[SymbolId.FIXED_PARAMETER], ): continue From aeb5f3478ddb85372c3ae69268aafa6f2fdef91c Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:58:02 +0100 Subject: [PATCH 04/46] Refactor de_export.py, extract sympy_utils.py (#2307) No changes in functionality. Related to #2306. --- python/sdist/amici/de_export.py | 205 ++--------------------------- python/sdist/amici/import_utils.py | 7 + python/sdist/amici/pysb_import.py | 2 +- python/sdist/amici/sbml_import.py | 4 +- python/sdist/amici/sympy_utils.py | 196 +++++++++++++++++++++++++++ python/tests/test_misc.py | 21 --- python/tests/test_sympy_utils.py | 24 ++++ 7 files changed, 241 insertions(+), 218 deletions(-) create mode 100644 python/sdist/amici/sympy_utils.py create mode 100644 python/tests/test_sympy_utils.py diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index 0a6813a6ca..3f8696a86b 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -1,7 +1,7 @@ """ C++ Export ---------- -This module provides all necessary functionality specify an DE model and +This module provides all necessary functionality specify a 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 :py:func:`amici.pysb_import.pysb2amici`, @@ -18,12 +18,11 @@ import subprocess import sys from dataclasses import dataclass -from itertools import chain, starmap +from itertools import chain from pathlib import Path from string import Template from typing import ( TYPE_CHECKING, - Any, Callable, Literal, Optional, @@ -59,8 +58,17 @@ strip_pysb, toposort_symbols, unique_preserve_order, + _default_simplify, ) from .logging import get_logger, log_execution_time, set_log_level +from .sympy_utils import ( + _custom_pow_eval_derivative, + _monkeypatched, + smart_jacobian, + smart_multiply, + smart_is_zero_matrix, + _parallel_applyfunc, +) if TYPE_CHECKING: from . import sbml_import @@ -509,109 +517,6 @@ def var_in_function_signature(name: str, varname: str, ode: bool) -> bool: } -@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. @@ -4304,94 +4209,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/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/pysb_import.py b/python/sdist/amici/pysb_import.py index c79a8c50f9..05f9ed9b28 100644 --- a/python/sdist/amici/pysb_import.py +++ b/python/sdist/amici/pysb_import.py @@ -34,7 +34,6 @@ Observable, Parameter, SigmaY, - _default_simplify, ) from .import_utils import ( _get_str_symbol_identifiers, @@ -42,6 +41,7 @@ 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 diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 9d6b7229c5..8fc2ab9fd9 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -31,9 +31,8 @@ from .de_export import ( DEExporter, DEModel, - _default_simplify, - smart_is_zero_matrix, ) +from .sympy_utils import smart_is_zero_matrix from .import_utils import ( RESERVED_SYMBOLS, _check_unsupported_functions, @@ -50,6 +49,7 @@ smart_subs_dict, symbol_with_assumptions, toposort_symbols, + _default_simplify, ) from .logging import get_logger, log_execution_time, set_log_level from .sbml_utils import SBMLException, _parse_logical_operators diff --git a/python/sdist/amici/sympy_utils.py b/python/sdist/amici/sympy_utils.py new file mode 100644 index 0000000000..863fc57f14 --- /dev/null +++ b/python/sdist/amici/sympy_utils.py @@ -0,0 +1,196 @@ +"""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 amici.de_export import get_logger +from amici.logging import log_execution_time + + +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/tests/test_misc.py b/python/tests/test_misc.py index 24bba79888..1ddeb3f760 100644 --- a/python/tests/test_misc.py +++ b/python/tests/test_misc.py @@ -8,8 +8,6 @@ import pytest import sympy as sp from amici.de_export import ( - _custom_pow_eval_derivative, - _monkeypatched, smart_subs_dict, ) from amici.testing import skip_on_valgrind @@ -108,25 +106,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_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 From c9b08ac292b29c830e6d9142def464fd2f271863 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 13:58:27 +0100 Subject: [PATCH 05/46] Refactor de_export.py, extract template functions (#2314) Start moving functionality for amici model code generation to a private subpackage `amici._codegen`. More to follow. --- python/sdist/amici/_codegen/__init__.py | 0 python/sdist/amici/_codegen/template.py | 42 +++++++++++++++++++++++++ python/sdist/amici/de_export.py | 40 +---------------------- 3 files changed, 43 insertions(+), 39 deletions(-) create mode 100644 python/sdist/amici/_codegen/__init__.py create mode 100644 python/sdist/amici/_codegen/template.py 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/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/de_export.py b/python/sdist/amici/de_export.py index 3f8696a86b..513a7c0e63 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -20,7 +20,6 @@ from dataclasses import dataclass from itertools import chain from pathlib import Path -from string import Template from typing import ( TYPE_CHECKING, Callable, @@ -42,6 +41,7 @@ amiciSwigPath, splines, ) +from ._codegen.template import apply_template from .constants import SymbolId from .cxxcodeprinter import ( AmiciCxxCodePrinter, @@ -3995,44 +3995,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 From eda7ad0327310caa6de97011119073496bddde01 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:09:20 +0100 Subject: [PATCH 06/46] Refactor: smoother conversion from SUNMatrixWrapper to SUNMatrix (#2317) Adds an implicit conversion function to SUNMatrixWrapper make things more readable. --- include/amici/rdata.h | 2 +- include/amici/sundials_matrix_wrapper.h | 5 +++++ src/model.cpp | 8 ++++---- src/model_dae.cpp | 20 +++++++++---------- src/model_ode.cpp | 20 +++++++++---------- src/newton_solver.cpp | 26 ++++++++++++------------- src/sundials_linsol_wrapper.cpp | 8 ++++---- tests/cpp/unittests/testMisc.cpp | 8 ++++---- 8 files changed, 51 insertions(+), 46 deletions(-) diff --git a/include/amici/rdata.h b/include/amici/rdata.h index 1de02c99db..6357d24748 100644 --- a/include/amici/rdata.h +++ b/include/amici/rdata.h @@ -576,7 +576,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/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/src/model.cpp b/src/model.cpp index 2485867a4c..3478610bbe 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -2249,7 +2249,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( @@ -2897,7 +2897,7 @@ 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); } } @@ -2943,7 +2943,7 @@ 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); } } @@ -2960,7 +2960,7 @@ void Model::fdwdw(realtype const t, realtype const* x) { ); 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..a3a8aaea26 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); @@ -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); } @@ -135,7 +135,7 @@ 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) @@ -355,7 +355,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 +376,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 +387,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 +397,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 +454,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 +465,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 +491,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..257ef45289 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); @@ -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); } @@ -355,7 +355,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 +373,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 +390,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 +456,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 +468,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 +492,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..9f011bac1e 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"); } @@ -189,10 +189,10 @@ void NewtonSolverSparse::prepareLinearSystemB( ) { /* Get sparse Jacobian */ model.fJSparseB( - state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_.get() + 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 +200,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 +211,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/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<N_Vector>(x.getNVector()), A_.get()); + solver_ = SUNLinSol_Band(const_cast<N_Vector>(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<N_Vector>(x.getNVector()), A_.get()); + solver_ = SUNLinSol_Dense(const_cast<N_Vector>(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<N_Vector>(x.getNVector()), A_.get()); + solver_ = SUNLinSol_KLU(const_cast<N_Vector>(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/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)); } From bd915ad5d9f317e586260dc1868b9a7de66c239c Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:16:42 +0100 Subject: [PATCH 07/46] Cache remote files for tests (#2313) Cache remote files for tests locally via pooch, and cache the pooch cache for GitHub actions. Today, I had dozens of workflow failures due to rate-limiting or unavailability of biomodels. This is avoidable. --- .github/workflows/test_python_cplusplus.yml | 14 ++++++++++ python/sdist/setup.cfg | 1 + .../test_conserved_quantities_demartino.py | 27 +++++++++---------- python/tests/test_sbml_import.py | 13 +++++---- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test_python_cplusplus.yml b/.github/workflows/test_python_cplusplus.yml index fb90476eb8..58dd5480e5 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: @@ -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: diff --git a/python/sdist/setup.cfg b/python/sdist/setup.cfg index 009d622a6b..0d27a0918e 100644 --- a/python/sdist/setup.cfg +++ b/python/sdist/setup.cfg @@ -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/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_sbml_import.py b/python/tests/test_sbml_import.py index aa343dfcc3..74a51d020a 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 @@ -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: From 780d7670eeb3c6aa02241171e6376ec61a69bac5 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:56:22 +0100 Subject: [PATCH 08/46] CMake: update BLAS detection (#2318) * Search for 64bit BLAS if supported by CMake. * On apple, try accelerate if nothing else was specified. Use the new interface (https://developer.apple.com/documentation/accelerate/blas). Fixes #2286. --- CMakeLists.txt | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 032a9fb084..324426f2a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,9 +169,35 @@ if(${BLAS} STREQUAL "MKL" OR DEFINED ENV{MKLROOT}) -lmkl CACHE STRING "") endif() -elseif(NOT DEFINED ENV{BLAS_LIBS} AND NOT DEFINED ENV{BLAS_CFLAGS}) +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 - find_package(BLAS) + 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) + 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) + 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. From 4b1e73bfca29cbe6ba8a04fe921ab8aab981535a Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:45:58 +0100 Subject: [PATCH 09/46] Refactor de_export.py, extract model compilation (#2315) Move model compilation to a free function in a separate module. Easier to test and more reusable for recompilation after initial import. Related to #2306 --- python/sdist/amici/compile.py | 80 +++++++++++++++++++++++++++++++++ python/sdist/amici/de_export.py | 73 +++--------------------------- 2 files changed, 87 insertions(+), 66 deletions(-) create mode 100644 python/sdist/amici/compile.py 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/de_export.py b/python/sdist/amici/de_export.py index 513a7c0e63..37958edf97 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -15,8 +15,6 @@ import os import re import shutil -import subprocess -import sys from dataclasses import dataclass from itertools import chain from pathlib import Path @@ -61,6 +59,7 @@ _default_simplify, ) 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, @@ -2893,7 +2892,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: """ @@ -2950,69 +2954,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 From e679e51f6ad29b8a1b8b7f5f45a9a27c46ee3d93 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 26 Feb 2024 21:14:39 +0100 Subject: [PATCH 10/46] Upgrade to SuiteSparse 7.6 (#2316) * Upgrade to SuiteSparse 7.6 * Update build scripts Closes #2302 --- ThirdParty/SuiteSparse/.gitignore | 4 + ThirdParty/SuiteSparse/AMD/CMakeLists.txt | 257 ++- ThirdParty/SuiteSparse/AMD/Config/AMD.pc.in | 17 + .../SuiteSparse/AMD/Config/AMDConfig.cmake.in | 152 ++ ThirdParty/SuiteSparse/AMD/Config/amd.h.in | 24 +- .../SuiteSparse/AMD/Doc/AMD_UserGuide.tex | 18 +- ThirdParty/SuiteSparse/AMD/Doc/ChangeLog | 22 + .../SuiteSparse/AMD/Doc/amd_version.tex | 2 +- ThirdParty/SuiteSparse/AMD/Include/amd.h | 30 +- .../SuiteSparse/AMD/Include/amd_internal.h | 9 +- ThirdParty/SuiteSparse/AMD/Makefile | 34 +- ThirdParty/SuiteSparse/AMD/Source/amd_order.c | 17 +- .../SuiteSparse/AMD/Source/amd_version.c | 19 + .../AMD/cmake_modules/FindAMD.cmake | 129 -- ThirdParty/SuiteSparse/BTF/CMakeLists.txt | 208 ++- ThirdParty/SuiteSparse/BTF/Config/BTF.pc.in | 16 + .../SuiteSparse/BTF/Config/BTFConfig.cmake.in | 152 ++ ThirdParty/SuiteSparse/BTF/Config/btf.h.in | 29 +- ThirdParty/SuiteSparse/BTF/Doc/ChangeLog | 21 + ThirdParty/SuiteSparse/BTF/Include/btf.h | 35 +- .../SuiteSparse/BTF/Include/btf_internal.h | 2 +- ThirdParty/SuiteSparse/BTF/Makefile | 8 +- .../SuiteSparse/BTF/Source/btf_version.c | 19 + .../BTF/cmake_modules/FindBTF.cmake | 129 -- ThirdParty/SuiteSparse/CMakeLists.txt | 540 ++++++ ThirdParty/SuiteSparse/COLAMD/CMakeLists.txt | 222 ++- .../SuiteSparse/COLAMD/Config/COLAMD.pc.in | 17 + .../COLAMD/Config/COLAMDConfig.cmake.in | 152 ++ .../SuiteSparse/COLAMD/Config/colamd.h.in | 27 +- ThirdParty/SuiteSparse/COLAMD/Doc/ChangeLog | 25 + .../SuiteSparse/COLAMD/Include/colamd.h | 33 +- ThirdParty/SuiteSparse/COLAMD/Makefile | 20 +- ThirdParty/SuiteSparse/COLAMD/Source/colamd.c | 1 - .../COLAMD/Source/colamd_version.c | 19 + .../COLAMD/cmake_modules/FindCOLAMD.cmake | 129 -- ThirdParty/SuiteSparse/ChangeLog | 176 +- ThirdParty/SuiteSparse/KLU/CMakeLists.txt | 555 ++++-- ThirdParty/SuiteSparse/KLU/Config/KLU.pc.in | 17 + .../SuiteSparse/KLU/Config/KLUConfig.cmake.in | 193 ++ ThirdParty/SuiteSparse/KLU/Config/klu.h.in | 46 +- ThirdParty/SuiteSparse/KLU/Doc/ChangeLog | 30 + .../SuiteSparse/KLU/Doc/KLU_UserGuide.tex | 2 +- .../SuiteSparse/KLU/Doc/klu_version.tex | 2 +- ThirdParty/SuiteSparse/KLU/Include/klu.h | 52 +- .../SuiteSparse/KLU/Include/klu_internal.h | 2 +- .../SuiteSparse/KLU/Include/klu_version.h | 2 +- ThirdParty/SuiteSparse/KLU/Makefile | 10 +- .../SuiteSparse/KLU/Source/klu_version.c | 19 + .../KLU/cmake_modules/FindKLU.cmake | 129 -- .../KLU/cmake_modules/FindKLU_CHOLMOD.cmake | 137 -- ThirdParty/SuiteSparse/LICENSE.txt | 170 +- ThirdParty/SuiteSparse/README.md | 1545 +++++++++++------ .../SuiteSparse_config/CMakeLists.txt | 308 +++- .../SuiteSparse_config/Config/README.md.in | 1543 ++++++++++------ .../Config/SuiteSparse_config.h.in | 1006 ++++++++++- .../Config/SuiteSparse_config.pc.in | 16 + .../Config/SuiteSparse_configConfig.cmake.in | 171 ++ .../SuiteSparse/SuiteSparse_config/Makefile | 14 +- .../SuiteSparse/SuiteSparse_config/README.txt | 2 +- .../SuiteSparse_config/SuiteSparse_config.c | 9 +- .../SuiteSparse_config/SuiteSparse_config.h | 1012 ++++++++++- .../FindSuiteSparse_config.cmake | 141 -- .../cmake_modules/SuiteSparseBLAS.cmake | 65 +- .../cmake_modules/SuiteSparseBLAS64.cmake | 6 +- .../cmake_modules/SuiteSparseLAPACK.cmake | 15 +- .../cmake_modules/SuiteSparsePolicy.cmake | 318 ++-- .../cmake_modules/SuiteSparseReport.cmake | 29 +- .../cmake_modules/SuiteSparse__thread.cmake | 72 + .../cmake_modules/SuiteSparse_ssize_t.cmake | 32 - ThirdParty/SuiteSparse/build/.gitignore | 4 + ThirdParty/SuiteSparse/lib/.gitignore | 4 + cmake/AmiciConfig.cmake | 7 + python/sdist/setup.py | 26 +- scripts/buildSuiteSparse.sh | 13 +- scripts/buildSundials.sh | 2 +- 75 files changed, 7690 insertions(+), 2750 deletions(-) create mode 100644 ThirdParty/SuiteSparse/AMD/Config/AMD.pc.in create mode 100644 ThirdParty/SuiteSparse/AMD/Config/AMDConfig.cmake.in create mode 100644 ThirdParty/SuiteSparse/AMD/Source/amd_version.c delete mode 100644 ThirdParty/SuiteSparse/AMD/cmake_modules/FindAMD.cmake create mode 100644 ThirdParty/SuiteSparse/BTF/Config/BTF.pc.in create mode 100644 ThirdParty/SuiteSparse/BTF/Config/BTFConfig.cmake.in create mode 100644 ThirdParty/SuiteSparse/BTF/Source/btf_version.c delete mode 100644 ThirdParty/SuiteSparse/BTF/cmake_modules/FindBTF.cmake create mode 100644 ThirdParty/SuiteSparse/CMakeLists.txt create mode 100644 ThirdParty/SuiteSparse/COLAMD/Config/COLAMD.pc.in create mode 100644 ThirdParty/SuiteSparse/COLAMD/Config/COLAMDConfig.cmake.in create mode 100644 ThirdParty/SuiteSparse/COLAMD/Source/colamd_version.c delete mode 100644 ThirdParty/SuiteSparse/COLAMD/cmake_modules/FindCOLAMD.cmake create mode 100644 ThirdParty/SuiteSparse/KLU/Config/KLU.pc.in create mode 100644 ThirdParty/SuiteSparse/KLU/Config/KLUConfig.cmake.in create mode 100644 ThirdParty/SuiteSparse/KLU/Source/klu_version.c delete mode 100644 ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU.cmake delete mode 100644 ThirdParty/SuiteSparse/KLU/cmake_modules/FindKLU_CHOLMOD.cmake create mode 100644 ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_config.pc.in create mode 100644 ThirdParty/SuiteSparse/SuiteSparse_config/Config/SuiteSparse_configConfig.cmake.in delete mode 100644 ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/FindSuiteSparse_config.cmake create mode 100644 ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse__thread.cmake delete mode 100644 ThirdParty/SuiteSparse/SuiteSparse_config/cmake_modules/SuiteSparse_ssize_t.cmake create mode 100644 ThirdParty/SuiteSparse/build/.gitignore create mode 100644 ThirdParty/SuiteSparse/lib/.gitignore 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) +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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) + 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 + "$<TARGET_PROPERTY:SuiteSparse::SuiteSparseConfig,INTERFACE_INCLUDE_DIRECTORIES>" ) +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 $<TARGET_FILE_BASE_NAME:AMD> ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $<TARGET_FILE_BASE_NAME:AMD_static> ) + 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) +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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) 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 + "$<TARGET_PROPERTY:SuiteSparse::SuiteSparseConfig,INTERFACE_INCLUDE_DIRECTORIES>" ) +endif ( ) +if ( BUILD_STATIC_LIBS ) + target_include_directories ( BTF_static PUBLIC + "$<TARGET_PROPERTY:SuiteSparse::SuiteSparseConfig,INTERFACE_INCLUDE_DIRECTORIES>" ) 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 $<TARGET_FILE_BASE_NAME:BTF> ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $<TARGET_FILE_BASE_NAME:BTF_static> ) + 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) +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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) 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 + "$<TARGET_PROPERTY:SuiteSparse::SuiteSparseConfig,INTERFACE_INCLUDE_DIRECTORIES>" ) +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 $<TARGET_FILE_BASE_NAME:COLAMD> ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $<TARGET_FILE_BASE_NAME:COLAMD_static> ) + 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) +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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) + 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Include> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) 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 + "$<TARGET_PROPERTY:SuiteSparse::AMD,INTERFACE_INCLUDE_DIRECTORIES>" ) +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 + "$<TARGET_PROPERTY:SuiteSparse::COLAMD,INTERFACE_INCLUDE_DIRECTORIES>" ) +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 + "$<TARGET_PROPERTY:SuiteSparse::BTF,INTERFACE_INCLUDE_DIRECTORIES>" ) +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 $<TARGET_FILE_BASE_NAME:KLU> ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $<TARGET_FILE_BASE_NAME:KLU_static> ) + 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 $<TARGET_FILE_BASE_NAME:KLU_CHOLMOD> ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $<TARGET_FILE_BASE_NAME:KLU_CHOLMOD_static> ) + 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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) +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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> + $<INSTALL_INTERFACE:${SUITESPARSE_INCLUDEDIR}> ) 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 + "$<TARGET_PROPERTY:OpenMP::OpenMP_C,INTERFACE_INCLUDE_DIRECTORIES>" ) + endif ( ) + if ( BUILD_STATIC_LIBS ) + target_link_libraries ( SuiteSparseConfig_static PRIVATE OpenMP::OpenMP_C ) + target_include_directories ( SuiteSparseConfig_static SYSTEM AFTER INTERFACE + "$<TARGET_PROPERTY:OpenMP::OpenMP_C,INTERFACE_INCLUDE_DIRECTORIES>" ) + 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 $<TARGET_FILE_BASE_NAME:SuiteSparseConfig> ) + else ( ) + set ( SUITESPARSE_LIB_BASE_NAME $<TARGET_FILE_BASE_NAME:SuiteSparseConfig_static> ) + 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 + "$<TARGET_PROPERTY:OpenMP::OpenMP_C,INTERFACE_INCLUDE_DIRECTORIES>" ) + else ( ) + target_include_directories ( ${_suitesparse_config_aliased} SYSTEM AFTER INTERFACE + "$<TARGET_PROPERTY:OpenMP::OpenMP_C,INTERFACE_INCLUDE_DIRECTORIES>" ) + 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 + "$<TARGET_PROPERTY:OpenMP::OpenMP_C,INTERFACE_INCLUDE_DIRECTORIES>" ) + else ( ) + target_include_directories ( ${_suitesparse_config_aliased} SYSTEM AFTER INTERFACE + "$<TARGET_PROPERTY:OpenMP::OpenMP_C,INTERFACE_INCLUDE_DIRECTORIES>" ) + 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 <stdio.h> + __thread int x = 1 ; + int main (void) + { + x = 0 ; + return (x) ; + } +" ) + +set ( declspec_thread_src +" #include <stdio.h> + __declspec ( thread ) int x = 1 ; + int main (void) + { + x = 0 ; + return (x) ; + } +" ) + +set ( thread_local_src +" #include <stdio.h> + #include <threads.h> + _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 <sys/types.h> - 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 <sys/types.h> and ssize_t: OK" ) -else ( ) - set ( HAVE_SSIZE_T false ) - message ( STATUS "#include <sys/types.h> 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/cmake/AmiciConfig.cmake b/cmake/AmiciConfig.cmake index cb7d57d51a..ebef45d6e0 100644 --- a/cmake/AmiciConfig.cmake +++ b/cmake/AmiciConfig.cmake @@ -1,5 +1,12 @@ @PACKAGE_INIT@ +# TODO remove after cmake files for test models have been regenerated +# cmake >=3.27 +if(POLICY CMP0144) + cmake_policy(SET CMP0144 NEW) +endif(POLICY CMP0144) + + include(CMakeFindDependencyMacro) find_package(OpenMP) 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/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} \ .. From 5e386ee7bab32b4d53f8277e2ce8099f36e9f220 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 27 Feb 2024 09:00:43 +0100 Subject: [PATCH 11/46] Don't eliminate parameters that are initial assignment targets (pt2) (#2305) Currently, parameters that are targets of initial assignments don't show up as parameters or expressions in the amici model. This is rather not what most users would expect. Therefore, treat all SBML parameters that are initial assignment targets and whose initial assignment does not evaluate to a number (for those that do, see #2304) as amici expressions. Those static expressions will be handled more efficiently after #2303. Related to #2150. See also #2304. --- python/sdist/amici/sbml_import.py | 17 +++++++++-------- tests/testSBMLSuite.py | 4 +++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 8fc2ab9fd9..11ffb16599 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -722,7 +722,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), @@ -1108,11 +1108,13 @@ def _process_parameters( } # 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 := par_id_to_ia.get(par.getId())) is not None and ia.find( - sp.core.function.UndefinedFunction("rateOf") + if ( + (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) @@ -1890,6 +1892,7 @@ def _process_initial_assignments(self): if identifier in itt.chain( self.symbols[SymbolId.SPECIES], self.compartments, + self.symbols[SymbolId.EXPRESSION], self.symbols[SymbolId.PARAMETER], self.symbols[SymbolId.FIXED_PARAMETER], ): @@ -1965,9 +1968,7 @@ 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) 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}, From 6a1cc3c14aa2542474304a4fe4afbdb96492dd25 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:37:11 +0100 Subject: [PATCH 12/46] Refactor DEModel, remove SbmlImporter dependency (#2312) `SbmlImporter` should construct a `DEModel`, instead of `DEModel` importing an `SbmlImporter`. Will allow moving `DEModel` to a separate module. Closes #2308. --- python/sdist/amici/de_export.py | 296 +++++------------------------- python/sdist/amici/de_model.py | 20 ++ python/sdist/amici/sbml_import.py | 172 ++++++++++++++++- python/sdist/amici/splines.py | 6 +- 4 files changed, 237 insertions(+), 257 deletions(-) diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index 37958edf97..be5a70e5cc 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -1,13 +1,15 @@ """ C++ Export ---------- -This module provides all necessary functionality specify a 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`. """ +from __future__ import annotations import contextlib import copy import itertools @@ -22,8 +24,6 @@ TYPE_CHECKING, Callable, Literal, - Optional, - Union, ) from collections.abc import Sequence import numpy as np @@ -40,7 +40,6 @@ splines, ) from ._codegen.template import apply_template -from .constants import SymbolId from .cxxcodeprinter import ( AmiciCxxCodePrinter, get_switch_statement, @@ -51,7 +50,6 @@ ObservableTransformation, SBMLException, amici_time_symbol, - generate_flux_symbol, smart_subs_dict, strip_pysb, toposort_symbols, @@ -70,7 +68,7 @@ ) if TYPE_CHECKING: - from . import sbml_import + from .splines import AbstractSpline # Template for model simulation main.cpp file @@ -497,25 +495,6 @@ def var_in_function_signature(name: str, varname: str, ode: bool) -> bool: ) -# 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, -} - - class DEModel: """ Defines a Differential Equation as set of ModelQuantities. @@ -639,8 +618,8 @@ class DEModel: def __init__( self, - verbose: Optional[Union[bool, int]] = False, - simplify: Optional[Callable] = _default_simplify, + verbose: bool | int | None = False, + simplify: Callable | None = _default_simplify, cache_simplify: bool = False, ): """ @@ -672,7 +651,7 @@ def __init__( self._expressions: list[Expression] = [] self._conservation_laws: list[ConservationLaw] = [] self._events: list[Event] = [] - self._splines = [] + self._splines: list[AbstractSpline] = [] self._symboldim_funs: dict[str, Callable[[], int]] = { "sx": self.num_states_solver, "v": self.num_states_solver, @@ -683,19 +662,15 @@ def __init__( } self._eqs: dict[ str, - Union[ - sp.Matrix, - sp.SparseMatrix, - list[Union[sp.Matrix, sp.SparseMatrix]], - ], + (sp.Matrix | sp.SparseMatrix | list[sp.Matrix | sp.SparseMatrix]), ] = dict() - self._sparseeqs: dict[str, Union[sp.Matrix, list[sp.Matrix]]] = 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, 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._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, @@ -726,7 +701,7 @@ def __init__( "k": self.constants, } self._total_derivative_prototypes: dict[ - str, dict[str, Union[str, list[str]]] + str, dict[str, str | list[str]] ] = { "sroot": { "eq": "root", @@ -742,7 +717,7 @@ def __init__( def cached_simplify( expr: sp.Expr, - _simplified: dict[str, sp.Expr] = {}, + _simplified: dict[str, sp.Expr] = {}, # noqa B006 _simplify: Callable = simplify, ) -> sp.Expr: """Speed up expression simplification with caching. @@ -769,7 +744,7 @@ def cached_simplify( return _simplified[expr_str] self._simplify = cached_simplify - self._x0_fixedParameters_idx: Union[None, Sequence[int]] + self._x0_fixedParameters_idx: None | Sequence[int] self._w_recursion_depth: int = 0 self._has_quadratic_nllh: bool = True set_log_level(logger, verbose) @@ -838,188 +813,6 @@ 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") @@ -1160,7 +953,7 @@ def get_rate(symbol: sp.Symbol): # ) def add_component( - self, component: ModelQuantity, insert_first: Optional[bool] = False + self, component: ModelQuantity, insert_first: bool | None = False ) -> None: """ Adds a new ModelQuantity to the model. @@ -1276,6 +1069,24 @@ def add_conservation_law( 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()``. + """ + self._splines.append(spline) + self.add_component( + Expression( + identifier=spline.sbml_id, + name=str(spline.sbml_id), + value=spline_expr, + ) + ) + def get_observable_transformations(self) -> list[ObservableTransformation]: """ List of observable transformations @@ -1459,9 +1270,7 @@ def sparseeq(self, name) -> sp.Matrix: self._generate_sparse_symbol(name) return self._sparseeqs[name] - def colptrs( - self, name: str - ) -> Union[list[sp.Number], list[list[sp.Number]]]: + def colptrs(self, name: str) -> list[sp.Number] | list[list[sp.Number]]: """ Returns (and constructs if necessary) the column pointers for a sparsified symbolic variable. @@ -1478,9 +1287,7 @@ def colptrs( self._generate_sparse_symbol(name) return self._colptrs[name] - def rowvals( - self, name: str - ) -> Union[list[sp.Number], list[list[sp.Number]]]: + 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. @@ -1534,8 +1341,7 @@ def free_symbols(self) -> set[sp.Basic]: """ return set( chain.from_iterable( - state.get_free_symbols() - for state in self.states() + self.algebraic_equations() + state.get_free_symbols() for state in self.states() ) ) @@ -2426,8 +2232,8 @@ def _multiplication( name: str, x: str, y: str, - transpose_x: Optional[bool] = False, - sign: Optional[int] = 1, + transpose_x: bool | None = False, + sign: int | None = 1, ): """ Creates a new symbolic variable according to a multiplication @@ -2629,7 +2435,7 @@ def _get_unique_root( self, root_found: sp.Expr, roots: list[Event], - ) -> Union[sp.Symbol, None]: + ) -> 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 @@ -2803,13 +2609,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. @@ -3901,7 +3707,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 diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model.py index c20509407a..cb0c066e4d 100644 --- a/python/sdist/amici/de_model.py +++ b/python/sdist/amici/de_model.py @@ -13,6 +13,7 @@ generate_measurement_symbol, generate_regularization_symbol, ) +from .constants import SymbolId __all__ = [ "ConservationLaw", @@ -732,3 +733,22 @@ def get_trigger_time(self) -> sp.Float: "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/sbml_import.py b/python/sdist/amici/sbml_import.py index 11ffb16599..eb0b739186 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -32,7 +32,8 @@ DEExporter, DEModel, ) -from .sympy_utils import smart_is_zero_matrix +from .de_model 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 +51,12 @@ 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,7 +183,7 @@ 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() @@ -534,9 +537,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 +640,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: @@ -1974,12 +2064,12 @@ def _make_initial( 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 = [] @@ -2526,6 +2616,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: From eb3fd4a45c59444d45e1a7b3c39de4c202906332 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 27 Feb 2024 13:40:23 +0100 Subject: [PATCH 13/46] Split expressions into static and dynamic (#2303) Split expressions in `w` and its derivatives into dynamic (explicitly or implicitly time-dependent) and static ones. Evaluate static ones only when needed, i.e. after (re)initializing x_rdata or parameters. See #1269 --- .github/actions/setup-amici-cpp/action.yml | 3 + include/amici/abstract_model.h | 46 ++-- include/amici/model.h | 36 ++- matlab/@amifun/getArgs.m | 6 +- matlab/@amimodel/generateC.m | 3 +- models/model_calvetti/CMakeLists.txt | 37 ++- models/model_calvetti/dwdx.cpp | 2 +- models/model_calvetti/main.cpp | 59 +++-- models/model_calvetti/model_calvetti.h | 18 +- models/model_calvetti/w.cpp | 2 +- models/model_dirac/CMakeLists.txt | 37 ++- models/model_dirac/main.cpp | 59 +++-- models/model_dirac/model_dirac.h | 10 +- models/model_events/CMakeLists.txt | 37 ++- models/model_events/main.cpp | 59 +++-- models/model_events/model_events.h | 10 +- models/model_jakstat_adjoint/CMakeLists.txt | 37 ++- models/model_jakstat_adjoint/dwdp.cpp | 2 +- models/model_jakstat_adjoint/dwdx.cpp | 2 +- models/model_jakstat_adjoint/main.cpp | 59 +++-- .../model_jakstat_adjoint.h | 22 +- models/model_jakstat_adjoint/w.cpp | 2 +- .../model_jakstat_adjoint_o2/CMakeLists.txt | 37 ++- models/model_jakstat_adjoint_o2/dwdp.cpp | 2 +- models/model_jakstat_adjoint_o2/dwdx.cpp | 2 +- models/model_jakstat_adjoint_o2/main.cpp | 59 +++-- .../model_jakstat_adjoint_o2.h | 22 +- models/model_jakstat_adjoint_o2/w.cpp | 2 +- models/model_nested_events/CMakeLists.txt | 37 ++- models/model_nested_events/main.cpp | 59 +++-- .../model_nested_events/model_nested_events.h | 10 +- models/model_neuron/CMakeLists.txt | 37 ++- models/model_neuron/main.cpp | 59 +++-- models/model_neuron/model_neuron.h | 10 +- models/model_neuron_o2/CMakeLists.txt | 37 ++- models/model_neuron_o2/dwdx.cpp | 2 +- models/model_neuron_o2/main.cpp | 59 +++-- models/model_neuron_o2/model_neuron_o2.h | 18 +- models/model_neuron_o2/w.cpp | 2 +- models/model_robertson/CMakeLists.txt | 37 ++- models/model_robertson/dwdp.cpp | 2 +- models/model_robertson/dwdx.cpp | 2 +- models/model_robertson/main.cpp | 59 +++-- models/model_robertson/model_robertson.h | 22 +- models/model_robertson/w.cpp | 2 +- models/model_steadystate/CMakeLists.txt | 37 ++- models/model_steadystate/dwdp.cpp | 2 +- models/model_steadystate/dwdx.cpp | 2 +- models/model_steadystate/main.cpp | 59 +++-- models/model_steadystate/model_steadystate.h | 22 +- models/model_steadystate/w.cpp | 2 +- python/sdist/amici/cxxcodeprinter.py | 18 +- python/sdist/amici/de_export.py | 224 +++++++++++++++++- src/abstract_model.cpp | 29 +-- src/model.cpp | 99 +++++--- src/model_dae.cpp | 6 +- src/model_ode.cpp | 4 +- src/solver.cpp | 13 +- swig/model.i | 1 + 59 files changed, 999 insertions(+), 645 deletions(-) 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/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/model.h b/include/amici/model.h index 23f6ac63c8..13de007e00 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<int>& 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 @@ -1828,29 +1840,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/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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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 <iostream> -#include <amici/amici.h> /* AMICI base functions */ -#include "wrapfunctions.h" /* model-provided functions */ +#include "wrapfunctions.h" /* model-provided functions */ +#include <amici/amici.h> /* AMICI base functions */ -template < class T > -std::ostream& operator << (std::ostream& os, const std::vector<T>& v) -{ +template <class T> +std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) { os << "["; - for (typename std::vector<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) - { + for (typename std::vector<T>::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<T>& v) */ int main() { - std::cout<<"********************************"<<std::endl; - std::cout<<"** Running forward simulation **"<<std::endl; - std::cout<<"********************************"<<std::endl<<std::endl; + std::cout << "********************************" << std::endl; + std::cout << "** Running forward simulation **" << std::endl; + std::cout << "********************************" << std::endl << std::endl; // Create a model instance auto model = amici::generic_model::getModel(); @@ -44,21 +43,20 @@ int main() { // Print observable time course auto observable_ids = model->getObservableIds(); - 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) { + 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<<rdata->y[i_time * rdata->ny + i_observable]<<" "; + std::cout << rdata->y[i_time * rdata->ny + i_observable] << " "; } - std::cout<<std::endl<<std::endl; + std::cout << std::endl << std::endl; } - - std::cout<<std::endl; - std::cout<<"**********************************"<<std::endl; - std::cout<<"** Forward sensitivity analysis **"<<std::endl; - std::cout<<"**********************************"<<std::endl<<std::endl; + std::cout << std::endl; + std::cout << "**********************************" << std::endl; + std::cout << "** Forward sensitivity analysis **" << std::endl; + std::cout << "**********************************" << std::endl << std::endl; // Enable first-order sensitivity analysis solver->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 " - <<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)]<<") = "; + 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<<rdata->sx[i_time * rdata->nplist * rdata->nx - + i_nplist * rdata->nx - + i_state]; - std::cout<<std::endl; + std::cout << rdata->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 <cmath> #include <memory> #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/sdist/amici/cxxcodeprinter.py b/python/sdist/amici/cxxcodeprinter.py index 032089393d..adc4c25454 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,7 +217,7 @@ 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] ] diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index be5a70e5cc..b853dd6ad0 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -179,14 +179,15 @@ def arguments(self, ode: bool = True) -> str: "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", + "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", + "const realtype *w, const realtype *tcl, const realtype *spl, " + "bool include_static", assume_pow_positivity=True, sparse=True, ), @@ -211,7 +212,7 @@ def arguments(self, ode: bool = True) -> str: "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", + "const realtype *w, const realtype *tcl, bool include_static", assume_pow_positivity=True, sparse=True, ), @@ -331,7 +332,8 @@ def arguments(self, ode: bool = True) -> str: "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", + "const realtype *h, const realtype *tcl, const realtype *spl, " + "bool include_static", assume_pow_positivity=True, ), "x0": _FunctionInfo( @@ -612,6 +614,10 @@ class DEModel: 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 """ @@ -749,6 +755,8 @@ def cached_simplify( 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 @@ -1345,6 +1353,153 @@ def free_symbols(self) -> set[sp.Basic]: ) ) + 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], + ) + ) + + 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() + ) + + 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 _generate_symbol(self, name: str) -> None: """ Generates the symbolic identifiers for a symbolic variable @@ -3261,9 +3416,57 @@ def _get_function_body( symbols = list(map(sp.Symbol, self.model.sparsesym(function))) else: symbols = self.model.sym(function) - lines += self._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._code_printer._get_sym_lines_array( @@ -3808,7 +4011,7 @@ def get_model_override_implementation( body = ( "" if nobody - else "\n{ind8}{maybe_return}{fun}_{name}({eval_signature});{ind4}\n".format( + 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 ", @@ -3855,7 +4058,9 @@ def get_sunindex_override_implementation( if nobody: impl += "}}\n" else: - impl += "{ind8}{fun}_{indextype}_{name}({eval_signature});\n{ind4}}}\n" + impl += ( + "\n{ind8}{fun}_{indextype}_{name}({eval_signature});\n{ind4}}}\n" + ) return impl.format( ind4=" " * 4, @@ -3892,6 +4097,7 @@ def remove_argument_types(signature: str) -> str: "realtype *", "const int ", "int ", + "bool ", "SUNMatrixContent_Sparse ", "gsl::span<const int>", ] 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/model.cpp b/src/model.cpp index 3478610bbe..54363d8d1b 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( @@ -1048,7 +1073,7 @@ void Model::requireSensitivitiesForAllParameters() { void Model::getExpression( gsl::span<realtype> w, realtype const t, AmiVector const& x ) { - fw(t, computeX_pos(x)); + fw(t, computeX_pos(x), false); writeSlice(derived_state_.w_, w); } @@ -1469,7 +1494,7 @@ void Model::addStateSensitivityEventUpdate( AmiVector const& xdot, AmiVector const& xdot_old, std::vector<realtype> const& stau ) { - fw(t, x_old.data()); + fw(t, x_old.data(), false); for (int ip = 0; ip < nplist(); ip++) { @@ -2040,7 +2065,7 @@ 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()); @@ -2059,8 +2084,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 +2119,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(), @@ -2840,38 +2865,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); } } -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_; @@ -2901,25 +2930,29 @@ void Model::fdwdp(realtype const t, realtype const* x) { } } -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_; @@ -2947,16 +2980,20 @@ void Model::fdwdx(realtype const t, realtype const* x) { } } -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_) { diff --git a/src/model_dae.cpp b/src/model_dae.cpp index a3a8aaea26..ad397bc82f 100644 --- a/src/model_dae.cpp +++ b/src/model_dae.cpp @@ -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 @@ -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), @@ -171,7 +171,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)); diff --git a/src/model_ode.cpp b/src/model_ode.cpp index 257ef45289..e3e401e1bf 100644 --- a/src/model_ode.cpp +++ b/src/model_ode.cpp @@ -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 @@ -143,7 +143,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 diff --git a/src/solver.cpp b/src/solver.cpp index 1a74e8b44b..2caa9d8bc0 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -251,13 +251,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_); } } 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; From 504f4bc25150580b0751feb1fb550b0be747eb8a Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:41:55 +0100 Subject: [PATCH 14/46] Refactor: Move amici.de_model to amici.de_model_components (#2323) ... to make space to move `amici.de_export.DEModel` to `amici.de_model` Related to #2306. --- .github/workflows/test_sbml_semantic_test_suite.yml | 2 +- documentation/python_modules.rst | 2 +- python/sdist/amici/de_export.py | 2 +- python/sdist/amici/{de_model.py => de_model_components.py} | 2 +- python/sdist/amici/sbml_import.py | 2 +- python/tests/test_de_model.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename python/sdist/amici/{de_model.py => de_model_components.py} (99%) 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/documentation/python_modules.rst b/documentation/python_modules.rst index 237a0a021f..03ae7a937e 100644 --- a/documentation/python_modules.rst +++ b/documentation/python_modules.rst @@ -25,7 +25,7 @@ AMICI Python API amici.petab_simulate amici.import_utils amici.de_export - amici.de_model + amici.de_model_components amici.plotting amici.pandas amici.logging diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index b853dd6ad0..126132911d 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -45,7 +45,7 @@ get_switch_statement, csc_matrix, ) -from .de_model import * +from .de_model_components import * from .import_utils import ( ObservableTransformation, SBMLException, diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model_components.py similarity index 99% rename from python/sdist/amici/de_model.py rename to python/sdist/amici/de_model_components.py index cb0c066e4d..eeeabb35db 100644 --- a/python/sdist/amici/de_model.py +++ b/python/sdist/amici/de_model_components.py @@ -199,7 +199,7 @@ def __init__(self, identifier: str, value: sp.Expr): Create a new AlgebraicEquation instance. :param value: - formula of the algebraic equation, solution is given by + Formula of the algebraic equation, the solution is given by ``formula == 0`` """ super().__init__(sp.Symbol(identifier), identifier, value) diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index eb0b739186..5a0e1669ad 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -32,7 +32,7 @@ DEExporter, DEModel, ) -from .de_model import symbol_to_type, Expression +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, 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 From c4bcb9dd255ac947d0762bc79b34ca67338d0d87 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:42:33 +0100 Subject: [PATCH 15/46] Refactor de_export.py, extract C++ function info to cxx_functions.py (#2321) Move everything related to information on C++ model functions to a separate module. Related to #2306. No changes in functionality. --- python/sdist/amici/_codegen/cxx_functions.py | 385 ++++++++++++++++++ python/sdist/amici/de_export.py | 388 +------------------ 2 files changed, 399 insertions(+), 374 deletions(-) create mode 100644 python/sdist/amici/_codegen/cxx_functions.py diff --git a/python/sdist/amici/_codegen/cxx_functions.py b/python/sdist/amici/_codegen/cxx_functions.py new file mode 100644 index 0000000000..25a8af3c2c --- /dev/null +++ b/python/sdist/amici/_codegen/cxx_functions.py @@ -0,0 +1,385 @@ +"""Info about C++ functions in the generated model code.""" +from __future__ import annotations + +from dataclasses import dataclass + + +@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<HermiteSpline>", + ), + "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<const int> 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<const int> 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() +] diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index 126132911d..014096aaf8 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -17,7 +17,6 @@ import os import re import shutil -from dataclasses import dataclass from itertools import chain from pathlib import Path from typing import ( @@ -39,6 +38,17 @@ amiciSwigPath, splines, ) +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.template import apply_template from .cxxcodeprinter import ( AmiciCxxCodePrinter, @@ -86,380 +96,10 @@ 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, 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<HermiteSpline>", - ), - "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<const int> 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<const int> 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 +#: list of equations that have ids which may not be unique non_unique_id_symbols = ["x_rdata", "y"] -# custom c++ function replacements +#: custom c++ function replacements CUSTOM_FUNCTIONS = [ { "sympy": "polygamma", @@ -471,7 +111,7 @@ def arguments(self, ode: bool = True) -> str: {"sympy": "DiracDelta", "c++": "amici::dirac"}, ] -# python log manager +#: python log manager logger = get_logger(__name__, logging.ERROR) From b4ab8a24176b4286cf3fede8d359a256e6e8904f Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 27 Feb 2024 17:43:04 +0100 Subject: [PATCH 16/46] Deterministic ordering of source files in generated CMakeLists.txt (#2322) Simpler model diffs. --- python/sdist/amici/de_export.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/python/sdist/amici/de_export.py b/python/sdist/amici/de_export.py index 014096aaf8..d956056a2e 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -3488,12 +3488,14 @@ def vector_initializer(v): 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 = { From 85e35ae5082da3fc96a4e088d18adefae3753135 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 28 Feb 2024 10:25:19 +0100 Subject: [PATCH 17/46] Refactor de_export.py, extract _codegen.model_class (#2319) Move functionality for generating the ``amici::Model`` subclass code to a separate file. Related to #2306 --- python/sdist/amici/_codegen/model_class.py | 191 ++++++++++++++++++++ python/sdist/amici/de_export.py | 195 ++------------------- 2 files changed, 201 insertions(+), 185 deletions(-) create mode 100644 python/sdist/amici/_codegen/model_class.py 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<const int>", + ] + + 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/de_export.py b/python/sdist/amici/de_export.py index d956056a2e..cdf5d6ac6a 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -49,6 +49,13 @@ 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, @@ -3330,7 +3337,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() @@ -3464,27 +3473,6 @@ def _get_symbol_id_initializer_list(self, name: str) -> str: 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( @@ -3587,169 +3575,6 @@ def set_name(self, model_name: str) -> None: self.model_name = model_name -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<const int>", - ] - - 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, From 4782cadc9c408475c90488a540578ddd3caad259 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 28 Feb 2024 13:17:11 +0100 Subject: [PATCH 18/46] Refactor de_export, extract DEModel (#2324) * Refactor de_export, extract DEModel Move `de_export.DEModel` to `de_model`. Closes #2306. de_export is now down to 1.5K lines, from previously 4K+. Some further cleanup would be good, but it's a start. * .. * .. --- documentation/python_modules.rst | 1 + python/sdist/amici/__init__.py | 2 +- python/sdist/amici/_codegen/cxx_functions.py | 23 + python/sdist/amici/de_export.py | 2255 +---------------- python/sdist/amici/de_model.py | 2276 ++++++++++++++++++ python/sdist/amici/pysb_import.py | 2 +- python/sdist/amici/sbml_import.py | 2 +- python/sdist/amici/sympy_utils.py | 3 +- python/tests/test_misc.py | 4 +- python/tests/test_ode_export.py | 2 +- 10 files changed, 2308 insertions(+), 2262 deletions(-) create mode 100644 python/sdist/amici/de_model.py diff --git a/documentation/python_modules.rst b/documentation/python_modules.rst index 03ae7a937e..2ec565c5fa 100644 --- a/documentation/python_modules.rst +++ b/documentation/python_modules.rst @@ -25,6 +25,7 @@ AMICI Python API amici.petab_simulate amici.import_utils amici.de_export + amici.de_model amici.de_model_components amici.plotting amici.pandas 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/cxx_functions.py b/python/sdist/amici/_codegen/cxx_functions.py index 25a8af3c2c..7831ed97c2 100644 --- a/python/sdist/amici/_codegen/cxx_functions.py +++ b/python/sdist/amici/_codegen/cxx_functions.py @@ -2,6 +2,7 @@ from __future__ import annotations from dataclasses import dataclass +import re @dataclass @@ -383,3 +384,25 @@ def arguments(self, ode: bool = True) -> str: 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/de_export.py b/python/sdist/amici/de_export.py index cdf5d6ac6a..fea9325ab2 100644 --- a/python/sdist/amici/de_export.py +++ b/python/sdist/amici/de_export.py @@ -10,25 +10,17 @@ :py:func:`amici.petab_import.import_model`. """ from __future__ import annotations -import contextlib import copy -import itertools import logging import os import re import shutil -from itertools import chain from pathlib import Path from typing import ( TYPE_CHECKING, - Callable, Literal, ) -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__, @@ -60,32 +52,22 @@ from .cxxcodeprinter import ( AmiciCxxCodePrinter, get_switch_statement, - csc_matrix, ) +from .de_model import DEModel from .de_model_components import * from .import_utils import ( - ObservableTransformation, - SBMLException, - amici_time_symbol, - smart_subs_dict, strip_pysb, - toposort_symbols, - unique_preserve_order, - _default_simplify, ) 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_jacobian, - smart_multiply, smart_is_zero_matrix, - _parallel_applyfunc, ) if TYPE_CHECKING: - from .splines import AbstractSpline + pass # Template for model simulation main.cpp file @@ -100,8 +82,6 @@ ) IDENTIFIER_PATTERN = re.compile(r"^[a-zA-Z_]\w*$") -DERIVATIVE_PATTERN = re.compile(r"^d(x_rdata|xdot|\w+?)d(\w+?)(?:_explicit)?$") - #: list of equations that have ids which may not be unique non_unique_id_symbols = ["x_rdata", "y"] @@ -122,2237 +102,6 @@ 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), - ) - - -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 _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, - verbose: bool | int | None = False, - simplify: Callable | None = _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: 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) - - 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 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()``. - """ - self._splines.append(spline) - self.add_component( - Expression( - identifier=spline.sbml_id, - name=str(spline.sbml_id), - value=spline_expr, - ) - ) - - 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) -> 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) -> 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() - ) - ) - - 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], - ) - ) - - 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() - ) - - 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 _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, - ) = 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, - ) - - 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: 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}`` - - :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], - ) -> 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 - - :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] - - 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 - - class DEExporter: """ The DEExporter class generates AMICI C++ files for a model as diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model.py new file mode 100644 index 0000000000..b69cc6ba68 --- /dev/null +++ b/python/sdist/amici/de_model.py @@ -0,0 +1,2276 @@ +"""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 ( + _default_simplify, + SBMLException, + toposort_symbols, + smart_subs_dict, + ObservableTransformation, + amici_time_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 + +logger = get_logger(__name__, logging.ERROR) + + +DERIVATIVE_PATTERN = re.compile(r"^d(x_rdata|xdot|\w+?)d(\w+?)(?:_explicit)?$") + + +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 _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, + verbose: bool | int | None = False, + simplify: Callable | None = _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: 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) + + 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 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()``. + """ + self._splines.append(spline) + self.add_component( + Expression( + identifier=spline.sbml_id, + name=str(spline.sbml_id), + value=spline_expr, + ) + ) + + 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) -> 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) -> 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() + ) + ) + + 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], + ) + ) + + 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() + ) + + 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 _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, + ) = 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, + ) + + 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: 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}`` + + :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], + ) -> 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 + + :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] + + 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/pysb_import.py b/python/sdist/amici/pysb_import.py index 05f9ed9b28..94aad595d9 100644 --- a/python/sdist/amici/pysb_import.py +++ b/python/sdist/amici/pysb_import.py @@ -27,7 +27,6 @@ from .de_export import ( Constant, DEExporter, - DEModel, DifferentialState, Expression, LogLikelihoodY, @@ -35,6 +34,7 @@ Parameter, SigmaY, ) +from .de_model import DEModel from .import_utils import ( _get_str_symbol_identifiers, _parse_special_functions, diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 5a0e1669ad..61cb79043e 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -27,10 +27,10 @@ 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, ) from .de_model_components import symbol_to_type, Expression from .sympy_utils import smart_is_zero_matrix, smart_multiply diff --git a/python/sdist/amici/sympy_utils.py b/python/sdist/amici/sympy_utils.py index 863fc57f14..bc20c49dc4 100644 --- a/python/sdist/amici/sympy_utils.py +++ b/python/sdist/amici/sympy_utils.py @@ -5,8 +5,7 @@ import contextlib import sympy as sp import logging -from amici.de_export import get_logger -from amici.logging import log_execution_time +from .logging import log_execution_time, get_logger logger = get_logger(__name__, logging.ERROR) diff --git a/python/tests/test_misc.py b/python/tests/test_misc.py index 1ddeb3f760..b68e96f1a0 100644 --- a/python/tests/test_misc.py +++ b/python/tests/test_misc.py @@ -7,9 +7,7 @@ import amici import pytest import sympy as sp -from amici.de_export import ( - smart_subs_dict, -) +from amici.import_utils import smart_subs_dict from amici.testing import skip_on_valgrind diff --git a/python/tests/test_ode_export.py b/python/tests/test_ode_export.py index 65af2935bb..6dc4d85f05 100644 --- a/python/tests/test_ode_export.py +++ b/python/tests/test_ode_export.py @@ -92,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) From 239ce2c3998e98dc71209b7837cd451c94bb5ac7 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 4 Mar 2024 07:45:35 +0100 Subject: [PATCH 19/46] Allow setting MaxConvFails and MaxNonlinIters on solvers (#2335) See [CVodeSetMaxConvFails](https://sundials.readthedocs.io/en/latest/cvodes/Usage/SIM.html#c.CVodeSetMaxConvFails) and [CVodeSetMaxNonlinIters](https://sundials.readthedocs.io/en/latest/cvodes/Usage/SIM.html#c.CVodeSetMaxNonlinIters). Closes #2333. --- include/amici/serialization.h | 2 ++ include/amici/solver.h | 47 +++++++++++++++++++++++++++++++++++ include/amici/solver_cvodes.h | 4 +++ include/amici/solver_idas.h | 4 +++ src/hdf5.cpp | 22 ++++++++++++++++ src/newton_solver.cpp | 4 +-- src/solver.cpp | 27 +++++++++++++++++++- src/solver_cvodes.cpp | 13 ++++++++++ src/solver_idas.cpp | 13 ++++++++++ 9 files changed, 132 insertions(+), 4 deletions(-) diff --git a/include/amici/serialization.h b/include/amici/serialization.h index 6cab4f0353..b5bfe466fc 100644 --- a/include/amici/serialization.h +++ b/include/amici/serialization.h @@ -85,6 +85,8 @@ 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_; } /** diff --git a/include/amici/solver.h b/include/amici/solver.h index 92ae4c47fb..ab4f8ef427 100644 --- a/include/amici/solver.h +++ b/include/amici/solver.h @@ -936,6 +936,34 @@ 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 Serialize Solver (see boost::serialization::serialize) * @param ar Archive to serialize to @@ -1712,6 +1740,18 @@ 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; + /** state (dimension: nx_solver) */ mutable AmiVector x_{0}; @@ -1844,6 +1884,13 @@ 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}; + /** 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..592298b7ec 100644 --- a/include/amici/solver_cvodes.h +++ b/include/amici/solver_cvodes.h @@ -249,6 +249,10 @@ 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; }; } // namespace amici diff --git a/include/amici/solver_idas.h b/include/amici/solver_idas.h index b985a090af..079cee6399 100644 --- a/include/amici/solver_idas.h +++ b/include/amici/solver_idas.h @@ -229,6 +229,10 @@ 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; }; } // namespace amici diff --git a/src/hdf5.cpp b/src/hdf5.cpp index e459eee138..4efed799a8 100644 --- a/src/hdf5.cpp +++ b/src/hdf5.cpp @@ -895,6 +895,16 @@ void writeSolverSettingsToHDF5( file.getId(), hdf5Location.c_str(), "check_sensi_steadystate_conv", &ibuffer, 1 ); + + ibuffer = static_cast<int>(solver.getMaxNonlinIters()); + H5LTset_attribute_int( + file.getId(), hdf5Location.c_str(), "max_nonlin_iters", &ibuffer, 1 + ); + + ibuffer = static_cast<int>(solver.getMaxConvFails()); + H5LTset_attribute_int( + file.getId(), hdf5Location.c_str(), "max_conv_fails", &ibuffer, 1 + ); } void readSolverSettingsFromHDF5( @@ -1106,6 +1116,18 @@ 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") + ); + } } void readSolverSettingsFromHDF5( diff --git a/src/newton_solver.cpp b/src/newton_solver.cpp index 9f011bac1e..c14b05c7f2 100644 --- a/src/newton_solver.cpp +++ b/src/newton_solver.cpp @@ -188,9 +188,7 @@ 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_ - ); + model.fJSparseB(state.t, 0.0, state.x, state.dx, xB_, dxB_, xdot_, Jtmp_); Jtmp_.refresh(); auto status = SUNLinSolSetup_KLU(linsol_, Jtmp_); if (status != SUNLS_SUCCESS) diff --git a/src/solver.cpp b/src/solver.cpp index 2caa9d8bc0..88185817dd 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -44,6 +44,8 @@ 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_) , maxstepsB_(other.maxstepsB_) , sensi_(other.sensi_) {} @@ -191,6 +193,9 @@ void Solver::setup( if (model->nt() > 1) calcIC(model->getTimepoint(1)); + apply_max_nonlin_iters(); + apply_max_conv_fails(); + cpu_time_ = 0.0; cpu_timeB_ = 0.0; } @@ -553,7 +558,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 { @@ -666,6 +673,24 @@ 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_; } + int Solver::getNewtonMaxSteps() const { return newton_maxsteps_; } void Solver::setNewtonMaxSteps(int const newton_maxsteps) { diff --git a/src/solver_cvodes.cpp b/src/solver_cvodes.cpp index f5150a87c7..4fe97720d8 100644 --- a/src/solver_cvodes.cpp +++ b/src/solver_cvodes.cpp @@ -257,6 +257,19 @@ 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"); +} + Solver* CVodeSolver::clone() const { return new CVodeSolver(*this); } void CVodeSolver::allocateSolver() const { diff --git a/src/solver_idas.cpp b/src/solver_idas.cpp index dac085e98d..1c69a041db 100644 --- a/src/solver_idas.cpp +++ b/src/solver_idas.cpp @@ -254,6 +254,19 @@ 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"); +} + Solver* IDASolver::clone() const { return new IDASolver(*this); } void IDASolver::allocateSolver() const { From 4a065e62f8a73a813fb464b00bc5d6cee64c1d09 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 4 Mar 2024 07:46:27 +0100 Subject: [PATCH 20/46] Fix size check in `Model::setStateIsNonNegative` (#2332) Previously, the wrong array was checked :see_no_evil:: ```python amici_model.setAllStatesNonNegative() amici_model.setStateIsNonNegative([]) amici_model.setAllStatesNonNegative() Traceback (most recent call last): File "<ipython-input-22-d7056e8e4e3f>", line 1, in <module> amici_model.setAllStatesNonNegative() File "python/sdist/amici/amici.py", line 2243, in setAllStatesNonNegative return _amici.ModelPtr_setAllStatesNonNegative(self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ RuntimeError: Dimension of input stateIsNonNegative (0) does not agree with number of state variables (2) ``` --- src/model.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model.cpp b/src/model.cpp index 54363d8d1b..b671de3c73 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -883,11 +883,11 @@ void Model::setStateIsNonNegative(std::vector<bool> const& nonNegative) { // in case of conservation laws return; } - if (state_is_non_negative_.size() != gsl::narrow<unsigned long>(nx_rdata)) { + if (nonNegative.size() != gsl::narrow<unsigned long>(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; From 61d17fa1f970debc7c246f011eb0b1608cef702c Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:53:26 +0100 Subject: [PATCH 21/46] GHA: use dateutil from pypi (#2337) Finally works with Python3.12 without DeprecationWarnings --- .github/workflows/test_python_ver_matrix.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test_python_ver_matrix.yml b/.github/workflows/test_python_ver_matrix.yml index 5f9d96d295..28b86d1c01 100644 --- a/.github/workflows/test_python_ver_matrix.yml +++ b/.github/workflows/test_python_ver_matrix.yml @@ -50,10 +50,6 @@ 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 From 3a6b0df34fc18cd7d8aa9b4793d35485ef110f2d Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 4 Mar 2024 09:54:11 +0100 Subject: [PATCH 22/46] Fix uncaught C++ exception in runAmiciSimulation (#2338) Previously, an exception during `ReturnData::processSimulationObjects` would result in program termination. Fixes #1882. --- src/amici.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/amici.cpp b/src/amici.cpp index 6e85dde857..ecff1ea786 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -220,10 +220,20 @@ std::unique_ptr<ReturnData> runAmiciSimulation( ); } - rdata->processSimulationObjects( - preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, posteq.get(), - model, solver, edata - ); + 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) + throw; + logger.log( + LogSeverity::error, "OTHER", "AMICI simulation failed: %s", + ex.what() + ); + } rdata->cpu_time_total = cpu_timer.elapsed_milliseconds(); From 0f961d676cbda261c32360463cc2245e957ff600 Mon Sep 17 00:00:00 2001 From: Polina Lakrisenko <p.lakrisenko@gmail.com> Date: Mon, 4 Mar 2024 14:14:34 +0100 Subject: [PATCH 23/46] Fix missing import in `amici/petab/petab_import.py` (#2342) fixes ``` Traceback (most recent call last): File "//./mnt/src/optimize.py", line 557, in <module> model, model_petab_problem = _model_import( File "/mnt/src/util.py", line 44, in _model_import model = amici.petab_import.import_petab_problem( File "/usr/local/lib/python3.10/dist-packages/amici/petab/petab_import.py", line 79, in import_petab_problem warn( NameError: name 'warn' is not defined ``` --- python/sdist/amici/petab/petab_import.py | 1 + 1 file changed, 1 insertion(+) 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 From 1ab1d555feb1162b9e5be9876ecd14bede374019 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:22:08 +0100 Subject: [PATCH 24/46] Fix ReturnDataView AttributeError: messages (#2341) * Make log messages from ReturnData available through ReturnDataView. * Add `LogItem.__repr__` Closes #2331. --- python/sdist/amici/numpy.py | 9 +++++++-- python/tests/test_sbml_import.py | 2 +- swig/amici.i | 8 ++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/numpy.py index 6e2966ba4b..f75d927b7b 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,7 @@ class ReturnDataView(SwigPtrView): "numnonlinsolvconvfailsB", "cpu_timeB", "cpu_time_total", + "messages", ] def __init__(self, rdata: Union[ReturnDataPtr, ReturnData]): @@ -440,7 +441,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/tests/test_sbml_import.py b/python/tests/test_sbml_import.py index 74a51d020a..ecf21f1f95 100644 --- a/python/tests/test_sbml_import.py +++ b/python/tests/test_sbml_import.py @@ -368,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) diff --git a/swig/amici.i b/swig/amici.i index 3518b296fe..1ef076fe33 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 From e8852be21a25b9fa79fc2fa2bbd44a4c83edabb6 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:23:00 +0100 Subject: [PATCH 25/46] Fix swig/std_unique_ptr.i (#2343) Fixes some `used without template arguments` errors when running swig with `-builtin` or `-keyword`. --- swig/std_unique_ptr.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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<Type>::pointer()); void swap (unique_ptr &__u); pointer get () const; operator bool () const; From 2906611fda0488a95fde73a8312313bf91686e42 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:47:42 +0100 Subject: [PATCH 26/46] Add new return code constant LSETUP_FAIL (#2353) --- include/amici/defines.h | 1 + src/amici.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/amici/defines.h b/include/amici/defines.h index f5ed1e62bb..210710b7ba 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; diff --git a/src/amici.cpp b/src/amici.cpp index ecff1ea786..ef6d640e13 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -69,6 +69,7 @@ std::map<int, std::string> 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<ReturnData> runAmiciSimulation( From 2235ab7d7d4943bb88b071e4da090a4e0b9b37a3 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 5 Mar 2024 16:48:50 +0100 Subject: [PATCH 27/46] Fix in-place building of model wheels (#2352) Fix `python -m build -n` for generated model packages. Fixes half of #2285 --- python/sdist/amici/MANIFEST.template.in | 2 ++ 1 file changed, 2 insertions(+) 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/ * From 777deb0a1a3e50d39b6f6e1e172cf754514d62f3 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 5 Mar 2024 18:49:36 +0100 Subject: [PATCH 28/46] Always include timepoints in NaN/Inf warnings (#2347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always include timepoints in NaN/Inf warnings Closes #2328 --------- Co-authored-by: Fabian Fröhlich <fabian.frohlich@crick.ac.uk> --- include/amici/model.h | 7 +++-- src/amici.cpp | 4 +-- src/model.cpp | 69 +++++++++++++++++++++++++------------------ src/model_dae.cpp | 3 +- src/model_ode.cpp | 3 +- src/solver_cvodes.cpp | 34 +++++++++++---------- src/solver_idas.cpp | 30 +++++++++++-------- 7 files changed, 89 insertions(+), 61 deletions(-) diff --git a/include/amici/model.h b/include/amici/model.h index 13de007e00..29b98aa913 100644 --- a/include/amici/model.h +++ b/include/amici/model.h @@ -1334,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<realtype const> array, ModelQuantity model_quantity + gsl::span<realtype const> array, ModelQuantity model_quantity, + realtype t ) const; /** * @brief Check if the given array has only finite elements. @@ -1347,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<realtype const> array, ModelQuantity model_quantity, - size_t num_cols + size_t num_cols, realtype t ) const; /** diff --git a/src/amici.cpp b/src/amici.cpp index ef6d640e13..cc8c2f00ab 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -223,8 +223,8 @@ std::unique_ptr<ReturnData> runAmiciSimulation( try { rdata->processSimulationObjects( - preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, posteq.get(), - model, solver, edata + preeq.get(), fwd.get(), bwd_success ? bwd.get() : nullptr, + posteq.get(), model, solver, edata ); } catch (std::exception const& ex) { rdata->status = AMICI_ERROR; diff --git a/src/model.cpp b/src/model.cpp index b671de3c73..cefdf1ac97 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -372,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() { @@ -1482,7 +1482,7 @@ void Model::addStateEventUpdate( ); if (always_check_finite_) { - checkFinite(derived_state_.deltax_, ModelQuantity::deltax); + checkFinite(derived_state_.deltax_, ModelQuantity::deltax, t); } // update @@ -1536,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 @@ -1582,7 +1582,7 @@ void Model::updateHeavisideB(int const* rootsfound) { } int Model::checkFinite( - gsl::span<realtype const> array, ModelQuantity model_quantity + gsl::span<realtype const> array, ModelQuantity model_quantity, realtype t ) const { auto it = std::find_if(array.begin(), array.end(), [](realtype x) { return !std::isfinite(x); @@ -1654,23 +1654,27 @@ int Model::checkFinite( gsl_ExpectsDebug(false); model_quantity_str = std::to_string(static_cast<int>(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<int>(flat_index), element_id.c_str() + gsl::narrow<int>(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; @@ -1678,7 +1682,7 @@ int Model::checkFinite( int Model::checkFinite( gsl::span<realtype const> 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); @@ -1768,19 +1772,25 @@ int Model::checkFinite( model_quantity_str = std::to_string(static_cast<int>(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<int>(flat_index), row_id.c_str(), col_id.c_str() + gsl::narrow<int>(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; } @@ -1868,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; } @@ -1895,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) { @@ -1982,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<realtype>::quiet_NaN() + ); } void Model::fsx_rdata( @@ -2072,7 +2085,7 @@ void Model::fy(realtype const t, AmiVector const& x) { 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 ); } } @@ -2875,7 +2888,7 @@ void Model::fw(realtype const t, realtype const* x, bool include_static) { state_.spl_.data(), include_static); if (always_check_finite_) { - checkFinite(derived_state_.w_, ModelQuantity::w); + checkFinite(derived_state_.w_, ModelQuantity::w, t); } } diff --git a/src/model_dae.cpp b/src/model_dae.cpp index ad397bc82f..22025e1181 100644 --- a/src/model_dae.cpp +++ b/src/model_dae.cpp @@ -138,7 +138,8 @@ void Model_DAE::fJDiag( 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!"); } diff --git a/src/model_ode.cpp b/src/model_ode.cpp index e3e401e1bf..787df210ef 100644 --- a/src/model_ode.cpp +++ b/src/model_ode.cpp @@ -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!"); } diff --git a/src/solver_cvodes.cpp b/src/solver_cvodes.cpp index 4fe97720d8..0952724457 100644 --- a/src/solver_cvodes.cpp +++ b/src/solver_cvodes.cpp @@ -927,7 +927,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); } /** @@ -978,7 +978,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); } /** @@ -1041,7 +1041,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); } /** @@ -1067,7 +1067,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); } /** @@ -1094,7 +1094,7 @@ static int froot(realtype t, N_Vector x, realtype* root, void* user_data) { model->froot(t, x, gsl::make_span<realtype>(root, model->ne_solver)); } return model->checkFinite( - gsl::make_span<realtype>(root, model->ne_solver), ModelQuantity::root + gsl::make_span<realtype>(root, model->ne_solver), ModelQuantity::root, t ); } @@ -1119,7 +1119,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 @@ -1128,7 +1128,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); } /** @@ -1154,7 +1154,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); } /** @@ -1174,7 +1174,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); } /** @@ -1193,7 +1193,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 + ); } /** @@ -1212,7 +1214,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 + ); } /** @@ -1228,8 +1232,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<CVodeSolver::user_data_type*>(user_data); Expects(typed_udata); @@ -1238,7 +1242,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 ); } @@ -1267,7 +1271,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 1c69a041db..fa08bc29f9 100644 --- a/src/solver_idas.cpp +++ b/src/solver_idas.cpp @@ -1065,7 +1065,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); } /** @@ -1096,7 +1096,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); } /** @@ -1118,7 +1118,7 @@ int froot( model->froot(t, x, dx, gsl::make_span<realtype>(root, model->ne)); return model->checkFinite( - gsl::make_span<realtype>(root, model->ne), ModelQuantity::root + gsl::make_span<realtype>(root, model->ne), ModelQuantity::root, t ); } @@ -1144,7 +1144,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 @@ -1153,7 +1153,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); } /** @@ -1183,7 +1183,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); } /** @@ -1208,7 +1208,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); } /** @@ -1230,7 +1230,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 + ); } /** @@ -1252,7 +1254,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 + ); } /** @@ -1270,7 +1274,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*/ ) { @@ -1281,7 +1285,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 ); } @@ -1314,7 +1318,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; } From 89b00cf2758d85ac5eb920cf9dfb170656af3234 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Tue, 5 Mar 2024 18:59:08 +0100 Subject: [PATCH 29/46] Make is-zero-checks compatible to the upcoming sympy>1.12 (#2350) Current sympy master (tested: 0ededfcfc033ddca2d1d54a0eda85bf53c63761c): ```python IPython console for SymPy 1.13.dev (Python 3.12.2-64-bit) (ground types: python) In [1]: Float(0) == 0 Out[1]: False In [2]: Float(0).is_zero Out[2]: True ``` vs 1.12: ```python Python console for SymPy 1.12 (Python 3.12.2-64-bit) (ground types: python) >>> Float(0) == 0 True >>> Float(0).is_zero True ``` Therefore, replace `== 0` by `.is_zero`. Amongst other potential issues, this fixes zeros in sparse matrices. Closes #2320. --- python/sdist/amici/cxxcodeprinter.py | 2 +- python/sdist/amici/de_model.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/sdist/amici/cxxcodeprinter.py b/python/sdist/amici/cxxcodeprinter.py index adc4c25454..fb98b0aca0 100644 --- a/python/sdist/amici/cxxcodeprinter.py +++ b/python/sdist/amici/cxxcodeprinter.py @@ -339,7 +339,7 @@ def csc_matrix( for col in range(ncols): symbol_col_ptrs.append(idx) for row in range(nrows): - if matrix[row, col] == 0: + if matrix[row, col].is_zero: continue symbol_row_vals.append(row) diff --git a/python/sdist/amici/de_model.py b/python/sdist/amici/de_model.py index b69cc6ba68..ea2807df52 100644 --- a/python/sdist/amici/de_model.py +++ b/python/sdist/amici/de_model.py @@ -2115,7 +2115,7 @@ def state_is_constant(self, ix: int) -> bool: if isinstance(state, AlgebraicState): return False - return state.get_dt() == 0.0 + return state.get_dt().is_zero def conservation_law_has_multispecies(self, tcl: ConservationLaw) -> bool: """ @@ -2179,7 +2179,7 @@ def _get_unique_root( return None for root in roots: - if sp.simplify(root_found - root.get_val()) == 0: + if sp.simplify(root_found - root.get_val()).is_zero: return root.get_id() # create an event for a new root function From b8be5a0788b44ec5245ba0bbb2dd331d1713f061 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:34:16 +0100 Subject: [PATCH 30/46] Fix type annotations in swig-wrappers (#2344) Depending on swig options/versions, swig may or may not generate type annotations. With these changes, type annotations will be extracted from the docstrings where available, independent of the swig-generated type annotations. Closes #2336. --- python/sdist/amici/swig.py | 43 +++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/python/sdist/amici/swig.py b/python/sdist/amici/swig.py index 902145ff3e..81a030ba3d 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,6 +56,8 @@ class TypeHintFixer(ast.NodeTransformer): } def visit_FunctionDef(self, node): + self._annotation_from_docstring(node) + # Has a return type annotation? if node.returns: node.returns = self._new_annot(node.returns.value) @@ -103,6 +108,42 @@ 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, the type hint is used + as the annotation. + """ + 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"\W*:rtype:\W*(.+)", line): + node.returns = ast.Constant(match.group(1)) + lines_to_remove.add(line_no) + + if match := re.match(r"\W*:type:\W*(\w+):\W*(.+)", line): + 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""" From 46d9d887991c15b8bb315e5d12dfd4f7330d5f04 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:25:14 +0100 Subject: [PATCH 31/46] CMake: Fix/cleanup BLAS linking (#2357) No matter how we found the BLAS, make sure there is always BLAS::BLAS. Closes #2354 --- CMakeLists.txt | 97 ++++----------------------------- cmake/AmiciConfig.cmake | 25 ++++----- cmake/AmiciFindBLAS.cmake | 110 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 102 deletions(-) create mode 100644 cmake/AmiciFindBLAS.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 324426f2a7..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,75 +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} - 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) - 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) - 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() -add_compile_definitions(AMICI_BLAS_${BLAS}) - # Add target to create version file add_custom_target( version @@ -285,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)") @@ -315,10 +237,6 @@ target_include_directories( $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/swig> 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") @@ -354,11 +272,11 @@ target_link_libraries( SUNDIALS::sunnonlinsolfixedpoint_static SUNDIALS::cvodes_static SUNDIALS::idas_static - ${BLAS_LIBRARIES} $<$<BOOL:${Boost_CHRONO_FOUND}>:Boost::chrono> $<$<BOOL:${OpenMP_FOUND}>:OpenMP::OpenMP_CXX> ${CMAKE_DL_LIBS} PRIVATE + BLAS::BLAS $<$<BOOL:${SUNDIALS_SUPERLUMT_ENABLE}>:SUNDIALS::sundials_sunlinsolsuperlumt> ) @@ -457,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 @@ -467,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/cmake/AmiciConfig.cmake b/cmake/AmiciConfig.cmake index ebef45d6e0..d1e86c151e 100644 --- a/cmake/AmiciConfig.cmake +++ b/cmake/AmiciConfig.cmake @@ -1,12 +1,5 @@ @PACKAGE_INIT@ -# TODO remove after cmake files for test models have been regenerated -# cmake >=3.27 -if(POLICY CMP0144) - cmake_policy(SET CMP0144 NEW) -endif(POLICY CMP0144) - - include(CMakeFindDependencyMacro) find_package(OpenMP) @@ -31,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( @@ -48,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() From 536a68e1182b1005622e7539a7f4a31fc9a0ab94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Fr=C3=B6hlich?= <fabian.frohlich@crick.ac.uk> Date: Wed, 6 Mar 2024 17:59:47 +0000 Subject: [PATCH 32/46] Fix venv related installation issues (#2356) * fix venv and BLAS * fixup * fixup? * Update runNotebook.sh * revert BLAS * remove virtualenv * remove venv creation from installAmiciSource * clear venv in buildInstall.sh * cleanup * doh * add venv back to installAmiciSource * readd numpy * export python executable in source install --- .github/workflows/test_petab_test_suite.yml | 8 +++---- .github/workflows/test_python_cplusplus.yml | 14 ++++++------ .github/workflows/test_python_ver_matrix.yml | 6 ++--- .gitignore | 1 + scripts/buildAmici.sh | 24 +++++++++++++++++++- scripts/installAmiciArchive.sh | 8 +++---- scripts/installAmiciSource.sh | 7 ++++-- scripts/run-SBMLTestsuite.sh | 2 +- scripts/run-codecov.sh | 2 +- scripts/run-python-tests.sh | 2 +- scripts/run-valgrind-py.sh | 2 +- scripts/runNotebook.sh | 2 +- 12 files changed, 52 insertions(+), 26 deletions(-) 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 58dd5480e5..f729d47867 100644 --- a/.github/workflows/test_python_cplusplus.yml +++ b/.github/workflows/test_python_cplusplus.yml @@ -45,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 \ @@ -64,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" \ @@ -138,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" \ @@ -214,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 @@ -251,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 @@ -296,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 28b86d1c01..414daadccc 100644 --- a/.github/workflows/test_python_ver_matrix.yml +++ b/.github/workflows/test_python_ver_matrix.yml @@ -51,15 +51,15 @@ jobs: run: scripts/installAmiciSource.sh # 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/.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/scripts/buildAmici.sh b/scripts/buildAmici.sh index 507a391621..2a3e7c7531 100755 --- a/scripts/buildAmici.sh +++ b/scripts/buildAmici.sh @@ -25,7 +25,29 @@ 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" +# install numpy +python3 -m pip install numpy ${cmake} \ -Wdev -DAMICI_CXX_OPTIONS="-Wall;-Wextra${extra_cxx_flags}" \ 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)") From 19f7bafe9dfd83cea8fc982661d294b8296c296f Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 20:10:23 +0100 Subject: [PATCH 33/46] SBML import: Evaluate initial assignments (#2359) Evaluate initial assignments to parameters to determine whether the targets are amici parameters or expressions. Related to https://github.com/AMICI-dev/AMICI/pull/2304. For example, it the initial assignment is `log(10)`, this should still be a parameter instead of an expression, but `sympy.log(10).is_Number` will be `False`. --- python/sdist/amici/sbml_import.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/sdist/amici/sbml_import.py b/python/sdist/amici/sbml_import.py index 61cb79043e..55d6dad903 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -1143,7 +1143,12 @@ def _process_parameters( # parameter ID => initial assignment sympy expression par_id_to_ia = { - par.getId(): 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 From dcc81d154bd05ea759c881ee33442871f2898403 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:07:31 +0100 Subject: [PATCH 34/46] Fix issues with paths containing blanks for sundials (#2361) ... --- ThirdParty/sundials/CMakeLists.txt | 6 +++--- ThirdParty/sundials/cmake/tpl/FindKLU.cmake | 2 +- ThirdParty/sundials/cmake/tpl/SundialsKLU.cmake | 17 +++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) 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 From ddffa93f707eb4f129ef773c00ba6e0ddebcb963 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:40:40 +0100 Subject: [PATCH 35/46] Enable specifying maximum solver step size (#2360) Expose [CVodeSetMaxStep](https://sundials.readthedocs.io/en/latest/cvodes/Usage/SIM.html#c.CVodeSetMaxStep). Closes #2358. --- include/amici/serialization.h | 1 + include/amici/solver.h | 20 ++++++++++++++++++++ include/amici/solver_cvodes.h | 2 ++ include/amici/solver_idas.h | 2 ++ src/hdf5.cpp | 11 +++++++++++ src/solver.cpp | 10 ++++++++++ src/solver_cvodes.cpp | 6 ++++++ src/solver_idas.cpp | 6 ++++++ 8 files changed, 58 insertions(+) diff --git a/include/amici/serialization.h b/include/amici/serialization.h index b5bfe466fc..97172e8375 100644 --- a/include/amici/serialization.h +++ b/include/amici/serialization.h @@ -87,6 +87,7 @@ void serialize(Archive& ar, amici::Solver& s, unsigned int const /*version*/) { ar & s.maxtime_; ar & s.max_conv_fails_; ar & s.max_nonlin_iters_; + ar & s.max_step_size_; } /** diff --git a/include/amici/solver.h b/include/amici/solver.h index ab4f8ef427..a52e80e82d 100644 --- a/include/amici/solver.h +++ b/include/amici/solver.h @@ -964,6 +964,18 @@ class Solver { */ int getMaxConvFails() const; + /** + * @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 @@ -1752,6 +1764,11 @@ class Solver { */ 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}; @@ -1891,6 +1908,9 @@ class Solver { * 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 592298b7ec..8abf407f1d 100644 --- a/include/amici/solver_cvodes.h +++ b/include/amici/solver_cvodes.h @@ -253,6 +253,8 @@ class CVodeSolver : public Solver { void apply_max_nonlin_iters() const override; void apply_max_conv_fails() 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 079cee6399..3d8a9df485 100644 --- a/include/amici/solver_idas.h +++ b/include/amici/solver_idas.h @@ -233,6 +233,8 @@ class IDASolver : public Solver { void apply_max_nonlin_iters() const override; void apply_max_conv_fails() const override; + + void apply_max_step_size() const override; }; } // namespace amici diff --git a/src/hdf5.cpp b/src/hdf5.cpp index 4efed799a8..e980619e5f 100644 --- a/src/hdf5.cpp +++ b/src/hdf5.cpp @@ -802,6 +802,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<int>(solver.getMaxSteps()); H5LTset_attribute_int( file.getId(), hdf5Location.c_str(), "maxsteps", &ibuffer, 1 @@ -1000,6 +1005,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") ); diff --git a/src/solver.cpp b/src/solver.cpp index 88185817dd..352017a6ee 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -46,6 +46,7 @@ Solver::Solver(Solver const& other) , 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_) {} @@ -195,6 +196,7 @@ void Solver::setup( apply_max_nonlin_iters(); apply_max_conv_fails(); + apply_max_step_size(); cpu_time_ = 0.0; cpu_timeB_ = 0.0; @@ -691,6 +693,14 @@ void Solver::setMaxConvFails(int max_conv_fails) { int Solver::getMaxConvFails() const { return max_conv_fails_; } +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) { diff --git a/src/solver_cvodes.cpp b/src/solver_cvodes.cpp index 0952724457..626b4cc050 100644 --- a/src/solver_cvodes.cpp +++ b/src/solver_cvodes.cpp @@ -270,6 +270,12 @@ void CVodeSolver::apply_max_conv_fails() const { throw CvodeException(status, "CVodeSetMaxConvFails"); } +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 { diff --git a/src/solver_idas.cpp b/src/solver_idas.cpp index fa08bc29f9..d97d6b3911 100644 --- a/src/solver_idas.cpp +++ b/src/solver_idas.cpp @@ -267,6 +267,12 @@ void IDASolver::apply_max_conv_fails() const { throw IDAException(status, "IDASetMaxConvFails"); } +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 { From d7603b10d0837e75a15949db3b8f810fe7a6b7f7 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 22:05:31 +0100 Subject: [PATCH 36/46] Fix Solver::dky_ initialization (#2362) `Solver::dky_` is always empty. Any call to `CVodeGetDky` should fail. Seems like it's never used. --- src/solver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solver.cpp b/src/solver.cpp index 352017a6ee..c1c048e4cc 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -1186,6 +1186,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); From 2316f2ad0ab0a13d07358b328f519ff01b11af58 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Wed, 6 Mar 2024 23:01:51 +0100 Subject: [PATCH 37/46] Fix petab import: initial assignment targets as constant parameters (#2345) During PEtab import, parameters that are targets of initial assignments have so far not been turned into constant parameters, because they didn't exist in the amici model (see #2304). Now that those parameters remain in the model, they should be turned into constant parameters, unless specified otherwise. Requires https://github.com/PEtab-dev/libpetab-python/pull/248, otherwise PEtab parameter mapping will provide potentially incorrect values for those parameters. --- python/sdist/amici/petab/sbml_import.py | 20 ++++++++++++--- python/sdist/amici/sbml_import.py | 15 +++-------- python/sdist/setup.cfg | 2 +- python/tests/test_petab_import.py | 34 ++++++++++++++++++++++--- 4 files changed, 52 insertions(+), 19 deletions(-) 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/sbml_import.py b/python/sdist/amici/sbml_import.py index 55d6dad903..8f7f67b02f 100644 --- a/python/sdist/amici/sbml_import.py +++ b/python/sdist/amici/sbml_import.py @@ -187,18 +187,11 @@ def __init__( 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 diff --git a/python/sdist/setup.cfg b/python/sdist/setup.cfg index 0d27a0918e..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 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 From 9824abad241c5acc97ce3d8ece65e3486c630f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Fr=C3=B6hlich?= <fabian.frohlich@crick.ac.uk> Date: Thu, 7 Mar 2024 08:38:23 +0000 Subject: [PATCH 38/46] Update dataframes import/export (#2351) * Update pandas.py * add doc + fix scales * fix venv and BLAS * fix tests * revert BLAS changes * Update scripts/installAmiciArchive.sh --------- Co-authored-by: Daniel Weindl <dweindl@users.noreply.github.com> --- python/sdist/amici/pandas.py | 57 ++++++++++++++++++++++++++++++++++-- scripts/buildAmici.sh | 1 - 2 files changed, 55 insertions(+), 3 deletions(-) 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/scripts/buildAmici.sh b/scripts/buildAmici.sh index 2a3e7c7531..80b724c8c3 100755 --- a/scripts/buildAmici.sh +++ b/scripts/buildAmici.sh @@ -46,7 +46,6 @@ fi # set python executable for cmake export PYTHON_EXECUTABLE="${amici_path}/venv/bin/python" -# install numpy python3 -m pip install numpy ${cmake} \ From 2dfd2bb3d2e74186abc8f7bfcf9f8c43c08ad9a4 Mon Sep 17 00:00:00 2001 From: Paul Jonas Jost <70631928+PaulJonasJost@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:09:57 +0100 Subject: [PATCH 39/46] Added amici.petab.conditions to readthedocs (#2364) --- documentation/python_modules.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/python_modules.rst b/documentation/python_modules.rst index 2ec565c5fa..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 From 8d655240d9eea295ecaa113e105eb360244be52c Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:10:28 +0100 Subject: [PATCH 40/46] Improve debugging info in ReturnData (#2349) * Improve debugging info in ReturnData * Add `ReturnData::t_last` that holds the last solver timepoint (Closes #2246) * `ReturnData::J` is now the evaluted at `t_last` instead of the last successfully reached output timepoint (Closes #2334) * `ReturnData::xdot` is now the evaluted at `t_last` instead of the last successfully reached output timepoint * skip xdot/J checks in case of failures --- include/amici/forwardproblem.h | 2 +- include/amici/rdata.h | 7 +++++-- python/sdist/amici/numpy.py | 1 + src/amici.cpp | 2 ++ src/forwardproblem.cpp | 5 ++++- src/hdf5.cpp | 4 ++++ tests/cpp/testfunctions.cpp | 23 +++++++++++++---------- 7 files changed, 30 insertions(+), 14 deletions(-) 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/rdata.h b/include/amici/rdata.h index 6357d24748..b5b4c269b4 100644 --- a/include/amici/rdata.h +++ b/include/amici/rdata.h @@ -104,12 +104,12 @@ class ReturnData : public ModelDimensions { */ std::vector<realtype> ts; - /** time derivative (shape `nx`) */ + /** time derivative (shape `nx`) evaluated at `t_last`. */ std::vector<realtype> xdot; /** * Jacobian of differential equation right hand side (shape `nx` x `nx`, - * row-major) + * row-major) evaluated at `t_last`. */ std::vector<realtype> J; @@ -456,6 +456,9 @@ class ReturnData : public ModelDimensions { /** log messages */ std::vector<LogItem> messages; + /** The final internal time of the solver. */ + realtype t_last{std::numeric_limits<realtype>::quiet_NaN()}; + protected: /** offset for sigma_residuals */ realtype sigma_offset; diff --git a/python/sdist/amici/numpy.py b/python/sdist/amici/numpy.py index f75d927b7b..c1aef949c6 100644 --- a/python/sdist/amici/numpy.py +++ b/python/sdist/amici/numpy.py @@ -239,6 +239,7 @@ class ReturnDataView(SwigPtrView): "cpu_timeB", "cpu_time_total", "messages", + "t_last", ] def __init__(self, rdata: Union[ReturnDataPtr, ReturnData]): diff --git a/src/amici.cpp b/src/amici.cpp index cc8c2f00ab..6166ab9352 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -236,6 +236,8 @@ std::unique_ptr<ReturnData> runAmiciSimulation( ); } + rdata->t_last = solver.gett(); + rdata->cpu_time_total = cpu_timer.elapsed_milliseconds(); // verify that reported CPU times are plausible 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 e980619e5f..303de576fb 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 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 { From 3dded5ca4e1f1202bef5d3b6865f5bf63eead43c Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Thu, 7 Mar 2024 14:18:39 +0100 Subject: [PATCH 41/46] Skip recreating N_Vector in AmiVector::copy (#2363) We only copy if the sizes match. Since the std::vector is not reallocated, there is no need to recreate the N_Vector. --- src/vector.cpp | 1 - 1 file changed, 1 deletion(-) 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() { From 7a920e25c14bba59a6eac7a43c602ede147a98ec Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:18:41 +0100 Subject: [PATCH 42/46] Enable setting constraints on state variables (#2340) In addition to the current `Model.setStateIsNonNegative`, this adds the option to set additional (non)negativity/positivity constraints to be enforced by the solver. See [CVodeSetConstraints](https://sundials.readthedocs.io/en/latest/cvode/Usage/index.html#c.CVodeSetConstraints) for details. Related to #2327. --- include/amici/defines.h | 9 ++++++ include/amici/serialization.h | 21 ++++++++++++++ include/amici/solver.h | 28 +++++++++++++++++- include/amici/solver_cvodes.h | 2 ++ include/amici/solver_idas.h | 2 ++ include/amici/vector.h | 35 +++++++++++++++++++++- python/tests/test_hdf5.py | 2 ++ python/tests/test_sbml_import.py | 50 ++++++++++++++++++++++++++++++++ src/hdf5.cpp | 10 +++++++ src/solver.cpp | 26 +++++++++++++++++ src/solver_cvodes.cpp | 12 ++++++++ src/solver_idas.cpp | 12 ++++++++ swig/amici.i | 1 + 13 files changed, 208 insertions(+), 2 deletions(-) diff --git a/include/amici/defines.h b/include/amici/defines.h index 210710b7ba..bd97d9a0b2 100644 --- a/include/amici/defines.h +++ b/include/amici/defines.h @@ -255,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/serialization.h b/include/amici/serialization.h index 97172e8375..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 <chrono> @@ -87,6 +88,7 @@ void serialize(Archive& ar, amici::Solver& s, unsigned int const /*version*/) { ar & s.maxtime_; ar & s.max_conv_fails_; ar & s.max_nonlin_iters_; + ar & s.constraints_; ar & s.max_step_size_; } @@ -278,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 <class Archive> +void serialize( + Archive& ar, amici::AmiVector& v, unsigned int const /*version*/ +) { + if (Archive::is_loading::value) { + std::vector<realtype> 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 a52e80e82d..661a9fac25 100644 --- a/include/amici/solver.h +++ b/include/amici/solver.h @@ -964,6 +964,24 @@ class Solver { */ 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<realtype> const& constraints); + + /** + * @brief Get constraints on the model state. + * @return constraints + */ + std::vector<realtype> getConstraints() const { + return constraints_.getVector(); + } + /** * @brief Set the maximum step size * @param max_step_size maximum step size. `0.0` means no limit. @@ -1130,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; @@ -1648,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<void, free_solver_ptr> solver_memory_; @@ -1809,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 diff --git a/include/amici/solver_cvodes.h b/include/amici/solver_cvodes.h index 8abf407f1d..8d04b22a34 100644 --- a/include/amici/solver_cvodes.h +++ b/include/amici/solver_cvodes.h @@ -254,6 +254,8 @@ class CVodeSolver : public Solver { void apply_max_conv_fails() const override; + void apply_constraints() const override; + void apply_max_step_size() const override; }; diff --git a/include/amici/solver_idas.h b/include/amici/solver_idas.h index 3d8a9df485..c8efc69c0c 100644 --- a/include/amici/solver_idas.h +++ b/include/amici/solver_idas.h @@ -234,6 +234,8 @@ class IDASolver : public Solver { void apply_max_conv_fails() const override; + void apply_constraints() const override; + void apply_max_step_size() const override; }; 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 <gsl/gsl-lite.hpp> +namespace amici { +class AmiVector; +} + +// for serialization friend +namespace boost { +namespace serialization { +template <class Archive> +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<realtype> rvec) + explicit AmiVector(gsl::span<realtype const> rvec) : AmiVector(std::vector<realtype>(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 <class Archive> + friend void boost::serialization::serialize( + Archive& ar, AmiVector& s, unsigned int version + ); + private: /** main data storage */ std::vector<realtype> vec_; @@ -405,6 +428,16 @@ namespace gsl { inline span<realtype> make_span(N_Vector nv) { return span<realtype>(N_VGetArrayPointer(nv), N_VGetLength_Serial(nv)); } + +/** + * @brief Create span from N_Vector + * @param nv + * + */ +inline span<realtype const> make_span(amici::AmiVector const& av) { + return make_span(av.getVector()); +} + } // namespace gsl #endif /* AMICI_VECTOR_H */ 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_sbml_import.py b/python/tests/test_sbml_import.py index ecf21f1f95..aaab5688cc 100644 --- a/python/tests/test_sbml_import.py +++ b/python/tests/test_sbml_import.py @@ -722,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/src/hdf5.cpp b/src/hdf5.cpp index 303de576fb..0454b634f1 100644 --- a/src/hdf5.cpp +++ b/src/hdf5.cpp @@ -914,6 +914,10 @@ void writeSolverSettingsToHDF5( H5LTset_attribute_int( file.getId(), hdf5Location.c_str(), "max_conv_fails", &ibuffer, 1 ); + + createAndWriteDouble1DDataset( + file, hdf5Location + "/constraints", solver.getConstraints() + ); } void readSolverSettingsFromHDF5( @@ -1143,6 +1147,12 @@ void readSolverSettingsFromHDF5( getIntScalarAttribute(file, datasetPath, "max_conv_fails") ); } + + if (locationExists(file, datasetPath + "/constraints")) { + solver.setConstraints( + getDoubleDataset1D(file, datasetPath + "/constraints") + ); + } } void readSolverSettingsFromHDF5( diff --git a/src/solver.cpp b/src/solver.cpp index c1c048e4cc..6fc1132c4d 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -200,6 +200,8 @@ void Solver::setup( cpu_time_ = 0.0; cpu_timeB_ = 0.0; + + apply_constraints(); } void Solver::setupB( @@ -646,6 +648,15 @@ void Solver::applySensitivityTolerances() const { } } +void Solver::apply_constraints() const { + if (constraints_.getLength() != 0 + && gsl::narrow<int>(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 { @@ -693,6 +704,21 @@ void Solver::setMaxConvFails(int max_conv_fails) { int Solver::getMaxConvFails() const { return max_conv_fails_; } +void Solver::setConstraints(std::vector<realtype> 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."); diff --git a/src/solver_cvodes.cpp b/src/solver_cvodes.cpp index 626b4cc050..e5771ff391 100644 --- a/src/solver_cvodes.cpp +++ b/src/solver_cvodes.cpp @@ -270,6 +270,18 @@ void CVodeSolver::apply_max_conv_fails() const { 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) diff --git a/src/solver_idas.cpp b/src/solver_idas.cpp index d97d6b3911..4f96c95f86 100644 --- a/src/solver_idas.cpp +++ b/src/solver_idas.cpp @@ -267,6 +267,18 @@ void IDASolver::apply_max_conv_fails() const { 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) diff --git a/swig/amici.i b/swig/amici.i index 1ef076fe33..46a58f8365 100644 --- a/swig/amici.i +++ b/swig/amici.i @@ -327,6 +327,7 @@ SteadyStateStatus = enum('SteadyStateStatus') NewtonDampingFactorMode = enum('NewtonDampingFactorMode') FixedParameterContext = enum('FixedParameterContext') RDataReporting = enum('RDataReporting') +Constraint = enum('Constraint') %} %template(SteadyStateStatusVector) std::vector<amici::SteadyStateStatus>; From c43ce3b360a447a61c605ce487f013f0558dd061 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Thu, 7 Mar 2024 21:17:36 +0100 Subject: [PATCH 43/46] Log stacktraces only in debug mode (#2366) Log stacktraces only in debug mode Closes #2186 --- python/tests/test_preequilibration.py | 4 ---- src/amici.cpp | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) 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/src/amici.cpp b/src/amici.cpp index 6166ab9352..2f60a8e12a 100644 --- a/src/amici.cpp +++ b/src/amici.cpp @@ -206,11 +206,12 @@ std::unique_ptr<ReturnData> 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) From 6f12f85ae59657790dc9b19faabe7d79f95b333e Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Thu, 7 Mar 2024 21:18:31 +0100 Subject: [PATCH 44/46] Fix type annotations in swig-wrappers (again) (#2365) Some things were missing in https://github.com/AMICI-dev/AMICI/pull/2344 --- python/sdist/amici/swig.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/python/sdist/amici/swig.py b/python/sdist/amici/swig.py index 81a030ba3d..fbc486c301 100644 --- a/python/sdist/amici/swig.py +++ b/python/sdist/amici/swig.py @@ -59,7 +59,7 @@ 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? @@ -112,8 +112,11 @@ 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, the type hint is used - as the annotation. + 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: @@ -124,11 +127,19 @@ def _annotation_from_docstring(self, node: ast.FunctionDef): lines_to_remove = set() for line_no, line in enumerate(docstring): - if match := re.match(r"\W*:rtype:\W*(.+)", line): + 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"\W*:type:\W*(\w+):\W*(.+)", line): + 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)) From b1bd988285c016d72a8a86da0fad88791c8fb526 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <dweindl@users.noreply.github.com> Date: Thu, 7 Mar 2024 21:30:14 +0100 Subject: [PATCH 45/46] Doc: Fix headings in ExampleJax (#2371) * Doc: Fix headings in ExampleJax To properly integrate into our sphinx docs. * remove duplicated notebook --- documentation/ExampleJax.ipynb | 1114 +----------------- python/examples/example_jax/ExampleJax.ipynb | 15 +- 2 files changed, 10 insertions(+), 1119 deletions(-) mode change 100644 => 120000 documentation/ExampleJax.ipynb 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": [ - "<div>\n", - "<style scoped>\n", - " .dataframe tbody tr th:only-of-type {\n", - " vertical-align: middle;\n", - " }\n", - "\n", - " .dataframe tbody tr th {\n", - " vertical-align: top;\n", - " }\n", - "\n", - " .dataframe thead th {\n", - " text-align: right;\n", - " }\n", - "</style>\n", - "<table border=\"1\" class=\"dataframe\">\n", - " <thead>\n", - " <tr style=\"text-align: right;\">\n", - " <th></th>\n", - " <th>parameterName</th>\n", - " <th>parameterScale</th>\n", - " <th>lowerBound</th>\n", - " <th>upperBound</th>\n", - " <th>nominalValue</th>\n", - " <th>estimate</th>\n", - " </tr>\n", - " <tr>\n", - " <th>parameterId</th>\n", - " <th></th>\n", - " <th></th>\n", - " <th></th>\n", - " <th></th>\n", - " <th></th>\n", - " <th></th>\n", - " </tr>\n", - " </thead>\n", - " <tbody>\n", - " <tr>\n", - " <th>Epo_degradation_BaF3</th>\n", - " <td>EPO_{degradation,BaF3}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>0.026983</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_exp_hetero</th>\n", - " <td>k_{exp,hetero}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>0.000010</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_exp_homo</th>\n", - " <td>k_{exp,homo}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>0.006170</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_imp_hetero</th>\n", - " <td>k_{imp,hetero}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>0.016368</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_imp_homo</th>\n", - " <td>k_{imp,homo}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>97749.379402</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_phos</th>\n", - " <td>k_{phos}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>15766.507020</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>ratio</th>\n", - " <td>ratio</td>\n", - " <td>lin</td>\n", - " <td>-5.00000</td>\n", - " <td>5</td>\n", - " <td>0.693000</td>\n", - " <td>0</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_pSTAT5A_rel</th>\n", - " <td>\\sigma_{pSTAT5A,rel}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>3.852612</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_pSTAT5B_rel</th>\n", - " <td>\\sigma_{pSTAT5B,rel}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>6.591478</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_rSTAT5A_rel</th>\n", - " <td>\\sigma_{rSTAT5A,rel}</td>\n", - " <td>log10</td>\n", - " <td>0.00001</td>\n", - " <td>100000</td>\n", - " <td>3.152713</td>\n", - " <td>1</td>\n", - " </tr>\n", - " <tr>\n", - " <th>specC17</th>\n", - " <td>specC17</td>\n", - " <td>lin</td>\n", - " <td>-5.00000</td>\n", - " <td>5</td>\n", - " <td>0.107000</td>\n", - " <td>0</td>\n", - " </tr>\n", - " </tbody>\n", - "</table>\n", - "</div>" - ], - "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": [ - "<div>\n", - "<style scoped>\n", - " .dataframe tbody tr th:only-of-type {\n", - " vertical-align: middle;\n", - " }\n", - "\n", - " .dataframe tbody tr th {\n", - " vertical-align: top;\n", - " }\n", - "\n", - " .dataframe thead th {\n", - " text-align: right;\n", - " }\n", - "</style>\n", - "<table border=\"1\" class=\"dataframe\">\n", - " <thead>\n", - " <tr style=\"text-align: right;\">\n", - " <th></th>\n", - " <th>amici</th>\n", - " <th>jax</th>\n", - " </tr>\n", - " </thead>\n", - " <tbody>\n", - " <tr>\n", - " <th>Epo_degradation_BaF3</th>\n", - " <td>-3.546026e-01</td>\n", - " <td>-3.640394e-01</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_exp_hetero</th>\n", - " <td>-2.401005e+03</td>\n", - " <td>-2.401010e+03</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_exp_homo</th>\n", - " <td>-4.073832e-01</td>\n", - " <td>-4.106763e-01</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_imp_hetero</th>\n", - " <td>-1.432855e-01</td>\n", - " <td>-1.639030e-01</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_imp_homo</th>\n", - " <td>2.006412e-10</td>\n", - " <td>2.006412e-10</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_phos</th>\n", - " <td>-2.179950e-07</td>\n", - " <td>-2.089803e-07</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_pSTAT5A_rel</th>\n", - " <td>-1.215545e-03</td>\n", - " <td>-1.222887e-03</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_pSTAT5B_rel</th>\n", - " <td>-1.583889e-03</td>\n", - " <td>-1.580870e-03</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_rSTAT5A_rel</th>\n", - " <td>-2.643776e-03</td>\n", - " <td>-2.641361e-03</td>\n", - " </tr>\n", - " </tbody>\n", - "</table>\n", - "</div>" - ], - "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": [ - "<div>\n", - "<style scoped>\n", - " .dataframe tbody tr th:only-of-type {\n", - " vertical-align: middle;\n", - " }\n", - "\n", - " .dataframe tbody tr th {\n", - " vertical-align: top;\n", - " }\n", - "\n", - " .dataframe thead th {\n", - " text-align: right;\n", - " }\n", - "</style>\n", - "<table border=\"1\" class=\"dataframe\">\n", - " <thead>\n", - " <tr style=\"text-align: right;\">\n", - " <th></th>\n", - " <th>amici</th>\n", - " <th>jax</th>\n", - " </tr>\n", - " </thead>\n", - " <tbody>\n", - " <tr>\n", - " <th>Epo_degradation_BaF3</th>\n", - " <td>-3.546026e-01</td>\n", - " <td>-3.546504e-01</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_exp_hetero</th>\n", - " <td>-2.401005e+03</td>\n", - " <td>-2.401005e+03</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_exp_homo</th>\n", - " <td>-4.073832e-01</td>\n", - " <td>-4.074248e-01</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_imp_hetero</th>\n", - " <td>-1.432855e-01</td>\n", - " <td>-1.433139e-01</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_imp_homo</th>\n", - " <td>2.006412e-10</td>\n", - " <td>2.006412e-10</td>\n", - " </tr>\n", - " <tr>\n", - " <th>k_phos</th>\n", - " <td>-2.179950e-07</td>\n", - " <td>-2.179076e-07</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_pSTAT5A_rel</th>\n", - " <td>-1.215545e-03</td>\n", - " <td>-1.215596e-03</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_pSTAT5B_rel</th>\n", - " <td>-1.583889e-03</td>\n", - " <td>-1.583805e-03</td>\n", - " </tr>\n", - " <tr>\n", - " <th>sd_rSTAT5A_rel</th>\n", - " <td>-2.643776e-03</td>\n", - " <td>-2.643703e-03</td>\n", - " </tr>\n", - " </tbody>\n", - "</table>\n", - "</div>" - ], - "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/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." ] }, { From 59d1d9f409ef393d18dc0d7b2e94247162a7fb58 Mon Sep 17 00:00:00 2001 From: Daniel Weindl <daniel.weindl@helmholtz-munich.de> Date: Thu, 7 Mar 2024 20:08:07 +0100 Subject: [PATCH 46/46] Bump version; update changelog --- CHANGELOG.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ version.txt | 2 +- 2 files changed, 71 insertions(+), 1 deletion(-) 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/version.txt b/version.txt index 2157409059..ca222b7cf3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.22.0 +0.23.0