Coverage for physioblocks / utils / math_utils.py: 94%
16 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-09 16:40 +0100
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-09 16:40 +0100
1# SPDX-FileCopyrightText: Copyright INRIA
2#
3# SPDX-License-Identifier: LGPL-3.0-only
4#
5# Copyright INRIA
6#
7# This file is part of PhysioBlocks, a library mostly developed by the
8# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9#
10# Authors:
11# - Colin Drieu
12# - Dominique Chapelle
13# - François Kimmig
14# - Philippe Moireau
15#
16# PhysioBlocks is free software: you can redistribute it and/or modify it under the
17# terms of the GNU Lesser General Public License as published by the Free Software
18# Foundation, version 3 of the License.
19#
20# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23#
24# You should have received a copy of the GNU Lesser General Public License along with
25# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
27"""Defines some math functions to help compute quantities"""
29from typing import Any
31import numpy as np
34def exp_diff(a: float, b: float, diff: float) -> Any:
35 """
36 Computes exponential differences with more numerical accuracy when a and b are close
37 using the relationship:
39 .. math::
41 e^a - e^b = 2\\ e^{\\frac{a + b}{2}}\\ \\text{sinh}(\\frac{a + b}{2})
43 :param a: value of a
44 :type a: np.float64
46 :param b: value of b
47 :type b: np.float64
49 :param diff: value of a - b
50 :type diff: np.float64
52 :return: exponential difference value
53 :rtype: np.float64
54 """
55 return np.exp(0.5 * (a + b)) * 2.0 * np.sinh(0.5 * diff)
58def power_diff(a: float, b: float, diff: float, n: int) -> Any:
59 """
60 Computes the a and b power n difference with more numerical accuracy when a and
61 b are close by using the following relationship:
63 .. math::
65 a^n - b^n = (a-b) * \\sum_{i = 0}^{n -1}{a^i b^{n-1-i}}
67 When n is negative, the following transformation is used:
69 .. math::
71 \\frac{1}{a^n} - \\frac{1}{b^n} = -\\frac{a^n-b^n}{{ab}^n}
73 :param a: value of a
74 :type a: np.float64
76 :param b: value of b
77 :type b: np.float64
79 :param diff: value of a - b
80 :type diff: np.float64
82 :return: the a and b power n difference value
83 :rtype: np.float64
84 """
86 if n < 0:
87 return -power_diff(a, b, diff, -n) / np.pow(a * b, -n)
88 elif n > 0:
89 return diff * _power_dec(a, b, n - 1, 0)
90 else:
91 return 0.0
94def _power_dec(a: float, b: float, n1: int, n2: int) -> Any:
95 """
96 Helper recursive function used by :func:`power_diff` to compute the term:
98 .. math::
100 \\sum_{i = 0}^{n -1}{a^i b^{n-1-i}}
101 """
103 if n1 != 0 or n2 != 0:
104 if n1 != 0:
105 return np.pow(a, n1) * np.pow(b, n2) + _power_dec(a, b, n1 - 1, n2 + 1)
106 else:
107 return np.pow(b, n2)
109 return 1.0