survivalist.functions
1# This program is free software: you can redistribute it and/or modify 2# it under the terms of the GNU General Public License as published by 3# the Free Software Foundation, either version 3 of the License, or 4# (at your option) any later version. 5# 6# This program is distributed in the hope that it will be useful, 7# but WITHOUT ANY WARRANTY; without even the implied warranty of 8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9# GNU General Public License for more details. 10# 11# You should have received a copy of the GNU General Public License 12# along with this program. If not, see <http://www.gnu.org/licenses/>. 13 14import numpy as np 15from sklearn.utils import check_consistent_length 16 17__all__ = ["StepFunction"] 18 19 20class StepFunction: 21 """Callable step function. 22 23 .. math:: 24 25 f(z) = a * y_i + b, 26 x_i \\leq z < x_{i + 1} 27 28 Parameters 29 ---------- 30 x : ndarray, shape = (n_points,) 31 Values on the x axis in ascending order. 32 33 y : ndarray, shape = (n_points,) 34 Corresponding values on the y axis. 35 36 a : float, optional, default: 1.0 37 Constant to multiply by. 38 39 b : float, optional, default: 0.0 40 Constant offset term. 41 42 domain : tuple, optional 43 A tuple with two entries that sets the limits of the 44 domain of the step function. 45 If entry is `None`, use the first/last value of `x` as limit. 46 """ 47 48 def __init__(self, x, y, *, a=1.0, b=0.0, domain=(0, None)): 49 check_consistent_length(x, y) 50 self.x = x 51 self.y = y 52 self.a = a 53 self.b = b 54 domain_lower = self.x[0] if domain[0] is None else domain[0] 55 domain_upper = self.x[-1] if domain[1] is None else domain[1] 56 self._domain = (float(domain_lower), float(domain_upper)) 57 58 @property 59 def domain(self): 60 """Returns the domain of the function, that means 61 the range of values that the function accepts. 62 63 Returns 64 ------- 65 lower_limit : float 66 Lower limit of domain. 67 68 upper_limit : float 69 Upper limit of domain. 70 """ 71 return self._domain 72 73 def __call__(self, x): 74 """Evaluate step function. 75 76 Values outside the interval specified by `self.domain` 77 will raise an exception. 78 Values in `x` that are in the interval `[self.domain[0]; self.x[0]]` 79 get mapped to `self.y[0]`. 80 81 Parameters 82 ---------- 83 x : float|array-like, shape=(n_values,) 84 Values to evaluate step function at. 85 86 Returns 87 ------- 88 y : float|array-like, shape=(n_values,) 89 Values of step function at `x`. 90 """ 91 x = np.atleast_1d(x) 92 if not np.isfinite(x).all(): 93 raise ValueError("x must be finite") 94 if np.min(x) < self._domain[0] or np.max(x) > self.domain[1]: 95 raise ValueError( 96 f"x must be within [{self.domain[0]:f}; {self.domain[1]:f}]") 97 98 # x is within the domain, but we need to account for self.domain[0] <= x < self.x[0] 99 x = np.clip(x, a_min=self.x[0], a_max=None) 100 101 i = np.searchsorted(self.x, x, side="left") 102 not_exact = self.x[i] != x 103 i[not_exact] -= 1 104 value = self.a * self.y[i] + self.b 105 if value.shape[0] == 1: 106 return value[0] 107 return value 108 109 def __repr__(self): 110 return f"StepFunction(x={self.x!r}, y={self.y!r}, a={self.a!r}, b={self.b!r})" 111 112 def __eq__(self, other): 113 if isinstance(other, type(self)): 114 return all(self.x == other.x) and all(self.y == other.y) and self.a == other.a and self.b == other.b 115 return False
class
StepFunction:
21class StepFunction: 22 """Callable step function. 23 24 .. math:: 25 26 f(z) = a * y_i + b, 27 x_i \\leq z < x_{i + 1} 28 29 Parameters 30 ---------- 31 x : ndarray, shape = (n_points,) 32 Values on the x axis in ascending order. 33 34 y : ndarray, shape = (n_points,) 35 Corresponding values on the y axis. 36 37 a : float, optional, default: 1.0 38 Constant to multiply by. 39 40 b : float, optional, default: 0.0 41 Constant offset term. 42 43 domain : tuple, optional 44 A tuple with two entries that sets the limits of the 45 domain of the step function. 46 If entry is `None`, use the first/last value of `x` as limit. 47 """ 48 49 def __init__(self, x, y, *, a=1.0, b=0.0, domain=(0, None)): 50 check_consistent_length(x, y) 51 self.x = x 52 self.y = y 53 self.a = a 54 self.b = b 55 domain_lower = self.x[0] if domain[0] is None else domain[0] 56 domain_upper = self.x[-1] if domain[1] is None else domain[1] 57 self._domain = (float(domain_lower), float(domain_upper)) 58 59 @property 60 def domain(self): 61 """Returns the domain of the function, that means 62 the range of values that the function accepts. 63 64 Returns 65 ------- 66 lower_limit : float 67 Lower limit of domain. 68 69 upper_limit : float 70 Upper limit of domain. 71 """ 72 return self._domain 73 74 def __call__(self, x): 75 """Evaluate step function. 76 77 Values outside the interval specified by `self.domain` 78 will raise an exception. 79 Values in `x` that are in the interval `[self.domain[0]; self.x[0]]` 80 get mapped to `self.y[0]`. 81 82 Parameters 83 ---------- 84 x : float|array-like, shape=(n_values,) 85 Values to evaluate step function at. 86 87 Returns 88 ------- 89 y : float|array-like, shape=(n_values,) 90 Values of step function at `x`. 91 """ 92 x = np.atleast_1d(x) 93 if not np.isfinite(x).all(): 94 raise ValueError("x must be finite") 95 if np.min(x) < self._domain[0] or np.max(x) > self.domain[1]: 96 raise ValueError( 97 f"x must be within [{self.domain[0]:f}; {self.domain[1]:f}]") 98 99 # x is within the domain, but we need to account for self.domain[0] <= x < self.x[0] 100 x = np.clip(x, a_min=self.x[0], a_max=None) 101 102 i = np.searchsorted(self.x, x, side="left") 103 not_exact = self.x[i] != x 104 i[not_exact] -= 1 105 value = self.a * self.y[i] + self.b 106 if value.shape[0] == 1: 107 return value[0] 108 return value 109 110 def __repr__(self): 111 return f"StepFunction(x={self.x!r}, y={self.y!r}, a={self.a!r}, b={self.b!r})" 112 113 def __eq__(self, other): 114 if isinstance(other, type(self)): 115 return all(self.x == other.x) and all(self.y == other.y) and self.a == other.a and self.b == other.b 116 return False
Callable step function.
$$f(z) = a * y_i + b, x_i \leq z < x_{i + 1}$$
Parameters
x : ndarray, shape = (n_points,) Values on the x axis in ascending order.
y : ndarray, shape = (n_points,) Corresponding values on the y axis.
a : float, optional, default: 1.0 Constant to multiply by.
b : float, optional, default: 0.0 Constant offset term.
domain : tuple, optional
A tuple with two entries that sets the limits of the
domain of the step function.
If entry is None, use the first/last value of x as limit.