Coverage for physioblocks / library / functions / base_operations.py: 100%

47 statements  

« 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/>. 

26 

27"""Define simple operations to initialize parameters in the configuration.""" 

28 

29from __future__ import annotations 

30 

31from collections.abc import Iterable 

32from dataclasses import dataclass, field 

33from typing import Any 

34 

35import numpy as np 

36 

37from physioblocks.base.operators import AbstractBaseOperators 

38from physioblocks.registers.type_register import register_type 

39from physioblocks.simulation import AbstractFunction 

40 

41# Sum funtion type id 

42SUM_TYPE_ID = "sum" 

43 

44 

45@dataclass 

46@register_type(SUM_TYPE_ID) 

47class Sum(AbstractFunction, AbstractBaseOperators): 

48 """ 

49 Sum the elements in ``add`` and subtract the elements in ``subtract``. 

50 """ 

51 

52 add: Iterable[Any] = field(default_factory=list) 

53 """the values to sum""" 

54 

55 subtract: Iterable[Any] | None = None 

56 """the values to subtract""" 

57 

58 @property 

59 def operation_value(self) -> Any: 

60 """ 

61 Value used with base operators. 

62 

63 :return: the current evaluation of the function 

64 :rtype: Any 

65 """ 

66 return self.eval() 

67 

68 def eval(self) -> Any: 

69 """ 

70 Sum the elements in ``add`` and subtract the elements in ``subtract``. 

71 

72 :return: the sum result 

73 :rtype: Any 

74 """ 

75 

76 pos = np.sum(np.array(self.add), axis=0) 

77 

78 if self.subtract is None: 

79 return pos 

80 

81 neg = np.sum(np.array(self.subtract), axis=0) 

82 return pos - neg 

83 

84 

85def _multiply(elements: Iterable[Any]) -> Any: 

86 result = 1.0 

87 for elem in elements: 

88 result = np.multiply(result, elem) 

89 return result 

90 

91 

92# Product function type name 

93PRODUCT_TYPE_ID = "product" 

94 

95 

96@dataclass 

97@register_type(PRODUCT_TYPE_ID) 

98class Product(AbstractFunction, AbstractBaseOperators): 

99 """ 

100 Multiply all values provided in ``factors`` list and divide the 

101 result with the multiplication of the values in the ``inverses`` list. 

102 

103 ..note:: It uses the numpy multiply function 

104 

105 """ 

106 

107 factors: Iterable[Any] = field(default_factory=list) 

108 """The values to multiply""" 

109 

110 inverses: Iterable[Any] | None = None 

111 """The values to inverse then multiply""" 

112 

113 @property 

114 def operation_value(self) -> Any: 

115 """ 

116 Value used with base operators. 

117 

118 :return: the current evaluation of the function 

119 :rtype: Any 

120 """ 

121 return self.eval() 

122 

123 def eval(self) -> Any: 

124 product = _multiply(self.factors) 

125 if self.inverses is None: 

126 return product 

127 else: 

128 inverses_product = _multiply(self.inverses) 

129 return product / inverses_product