Skip to content

Commit 93da7ae

Browse files
committed
integration parameters are now part of the constructor
1 parent 1280bdf commit 93da7ae

File tree

7 files changed

+161
-133
lines changed

7 files changed

+161
-133
lines changed

src/algorithms/semiparam_algorithms/nvm_semi_param_algorithms/g_estimation_given_mu_rqmc_based.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ def v_sequence_default_value(n: float) -> float:
3131
GRID_SIZE_DEFAULT_VALUE: int = 200
3232
INTEGRATION_TOLERANCE_DEFAULT_VALUE: float = 1e-2
3333
INTEGRATION_LIMIT_DEFAULT_VALUE: int = 50
34-
INTEGRATOR_DEFAULT = RQMCIntegrator()
3534

3635

3736
class SemiParametricGEstimationGivenMuRQMCBased:
@@ -70,8 +69,7 @@ def __init__(self, sample: Optional[_typing.NDArray[np.float64]] = None, **kwarg
7069
self.x_data,
7170
self.grid_size,
7271
self.integration_tolerance,
73-
self.integration_limit,
74-
self.integrator
72+
self.integration_limit
7573
) = self._validate_kwargs(self.n, **kwargs)
7674
self.denominator: float = 2 * math.pi * self.n
7775
self.precompute_gamma_grid()
@@ -81,7 +79,7 @@ def __init__(self, sample: Optional[_typing.NDArray[np.float64]] = None, **kwarg
8179
@staticmethod
8280
def _validate_kwargs(
8381
n: int, **kwargs: Unpack[ParamsAnnotation]
84-
) -> tuple[float, float, float, float, List[float], int, float, int, Integrator]:
82+
) -> tuple[float, float, float, float, List[float], int, float, int]:
8583
mu: float = kwargs.get("mu", MU_DEFAULT_VALUE)
8684
gmm: float = kwargs.get("gmm", GAMMA_DEFAULT_VALUE)
8785
u_value: float = kwargs.get("u_value", U_SEQUENCE_DEFAULT_VALUE(n))
@@ -90,8 +88,7 @@ def _validate_kwargs(
9088
grid_size: int = kwargs.get("grid_size", GRID_SIZE_DEFAULT_VALUE)
9189
integration_tolerance: float = kwargs.get("integration_tolerance", INTEGRATION_TOLERANCE_DEFAULT_VALUE)
9290
integration_limit: int = kwargs.get("integration_limit", INTEGRATION_LIMIT_DEFAULT_VALUE)
93-
integrator: Integrator = kwargs.get("integrator_type", INTEGRATOR_DEFAULT)
94-
return mu, gmm, u_value, v_value, x_data, grid_size, integration_tolerance, integration_limit, integrator
91+
return mu, gmm, u_value, v_value, x_data, grid_size, integration_tolerance, integration_limit
9592

9693
def conjugate_psi(self, u: float) -> complex:
9794
return complex((u**2) / 2, self.mu * u)
@@ -166,16 +163,15 @@ def second_v_integrand(self, v: float, x: float) -> np.ndarray:
166163
x_power = self.x_powers[x][idx]
167164
return (self.second_u_integrals[idx] * x_power) / gamma_val
168165

169-
def compute_integrals_for_x(self, x: float, integrator: Integrator = None) -> float:
166+
def compute_integrals_for_x(self, x: float, integrator: Integrator = RQMCIntegrator()) -> float:
170167
"""Compute integrals using RQMC for v-integration."""
171-
integrator = integrator or self.integrator
172-
first_integral = integrator.compute_integral(func=lambda t: np.sum(self.first_v_integrand(t * self.v_value, x)) * self.v_value).value
168+
first_integral = integrator.compute(func=lambda t: np.sum(self.first_v_integrand(t * self.v_value, x)) * self.v_value).value
173169

174-
second_integral = integrator.compute_integral(func=lambda t: np.sum(self.second_v_integrand(-t * self.v_value, x)) * self.v_value).value
170+
second_integral = integrator.compute(func=lambda t: np.sum(self.second_v_integrand(-t * self.v_value, x)) * self.v_value).value
175171

176172
total = (first_integral + second_integral) / self.denominator
177173
return max(0.0, total.real)
178174

179175
def algorithm(self, sample: np._typing.NDArray) -> EstimateResult:
180-
y_data = [self.compute_integrals_for_x(x, self.integrator) for x in self.x_data]
176+
y_data = [self.compute_integrals_for_x(x, RQMCIntegrator()) for x in self.x_data]
181177
return EstimateResult(list_value=y_data, success=True)

src/algorithms/support_algorithms/integrator.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,8 @@ class Integrator(Protocol):
1313

1414
"""Base class for integral calculation"""
1515

16-
def compute_integral(self, func: Callable, params: dict) -> IntegrationResult:
16+
def __init__(self):
17+
...
18+
19+
def compute(self, func: Callable) -> IntegrationResult:
1720
...
Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,45 @@
1-
from typing import Callable
1+
from typing import Callable, Optional
22

33
from scipy.integrate import quad
44
from src.algorithms.support_algorithms.integrator import IntegrationResult
55

66
class QuadIntegrator:
77

8-
def compute_integral(self, func: Callable, params: dict) -> IntegrationResult:
8+
def __init__(
9+
self,
10+
a: float = 0,
11+
b: float = 1,
12+
args: tuple = (),
13+
full_output: int = 0,
14+
epsabs: float | int = 1.49e-08,
15+
epsrel: float | int = 1.49e-08,
16+
limit: float | int = 50,
17+
points=None,
18+
weight: float | int = None,
19+
wvar=None,
20+
wopts=None,
21+
maxp1: float | int = 50,
22+
limlst: int = 50,
23+
complex_func: bool = False,
24+
):
25+
self.params = {
26+
'a': a,
27+
'b': b,
28+
'args': args,
29+
'full_output': full_output,
30+
'epsabs': epsabs,
31+
'epsrel': epsrel,
32+
'limit': limit,
33+
'points': points,
34+
'weight': weight,
35+
'wvar': wvar,
36+
'wopts': wopts,
37+
'maxp1': maxp1,
38+
'limlst': limlst,
39+
'complex_func': complex_func
40+
}
41+
42+
def compute(self, func: Callable, params: dict) -> IntegrationResult:
943

1044
"""
1145
Compute integral via quad integrator
@@ -17,11 +51,11 @@ def compute_integral(self, func: Callable, params: dict) -> IntegrationResult:
1751
Returns: moment approximation and error tolerance
1852
"""
1953

20-
full_output_requested = params.pop('full_output', False)
21-
quad_res = quad(func, **params)
22-
if full_output_requested:
23-
value, error, message = quad_res
54+
verbose = params.pop('full_output', False)
55+
result = quad(func, **params)
56+
if verbose:
57+
value, error, message = result
2458
else:
25-
value, error = quad_res
59+
value, error = result
2660
message = None
2761
return IntegrationResult(value, error, message)

src/algorithms/support_algorithms/rqmc.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,44 @@ def __call__(self) -> tuple[float, float]:
229229

230230

231231
class RQMCIntegrator:
232+
"""
233+
Randomize Quasi Monte Carlo Method
232234
233-
def compute_integral(self, func: Callable, params: dict) -> IntegrationResult:
235+
Args:
236+
error_tolerance: pre-specified error tolerance
237+
count: number of rows of random values matrix
238+
base_n: number of columns of random values matrix
239+
i_max: allowed number of cycles
240+
a: parameter for quantile of normal distribution
241+
242+
"""
243+
244+
def __init__(
245+
self,
246+
error_tolerance: float = 1e-6,
247+
count: int = 25,
248+
base_n: int = 2 ** 6,
249+
i_max: int = 100,
250+
a: float = 0.00047,
251+
):
252+
self.params = {
253+
'error_tolerance': error_tolerance,
254+
"count": count,
255+
"base_n": base_n,
256+
"i_max": i_max,
257+
"a": a
258+
}
259+
260+
def compute(self, func: Callable) -> IntegrationResult:
234261
"""
235262
Compute integral via RQMC integrator
236263
237264
Args:
238265
func: integrated function
239-
params: Parameters of integration algorithm
240266
241267
Returns: moment approximation and error tolerance
242268
"""
243269

244-
rqmc = RQMC(func, **params)()
245-
return IntegrationResult(rqmc[0], rqmc[1])
270+
result = RQMC(func, **self.params)()
271+
return IntegrationResult(result[0], result[1])
272+

src/mixtures/nm_mixture.py

Lines changed: 35 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -60,175 +60,155 @@ def _params_validation(self, data_collector: Any, params: dict[str, float | rv_c
6060
raise ValueError("Gamma cant be zero")
6161
return data_class
6262

63-
def _classical_moment(self, n: int, params: dict, integrator: Integrator = None) -> tuple[float, float]:
63+
def _classical_moment(self, n: int, integrator: Integrator = QuadIntegrator()) -> tuple[float, float]:
6464
"""
6565
Compute n-th moment of classical NMM
6666
6767
Args:
6868
n (): Moment ordinal
69-
params (): Parameters of integration algorithm
70-
integrator (): type of integrator to computing
69+
integrator (): class of integrator with params to computing
7170
7271
Returns: moment approximation and error tolerance
7372
7473
"""
7574
mixture_moment = 0
7675
error_tolerance = 0
77-
integrator = integrator or QuadIntegrator()
7876
for k in range(0, n + 1):
7977
for l in range(0, k + 1):
8078
coefficient = binom(n, n - k) * binom(k, k - l) * (self.params.beta ** (k - l)) * (
8179
self.params.gamma ** l)
82-
mixing_moment = integrator.compute_integral(lambda u: self.params.distribution.ppf(u) ** (k - l),
83-
{"a": 0, "b": 1, **params})
80+
mixing_moment = integrator.compute(lambda u: self.params.distribution.ppf(u) ** (k - l))
8481
error_tolerance += (self.params.beta ** (k - l)) * mixing_moment.error
8582
mixture_moment += coefficient * (self.params.alpha ** (n - k)) * mixing_moment.value * norm.moment(l)
8683
return mixture_moment, error_tolerance
8784

8885

89-
def _canonical_moment(self, n: int, params: dict, integrator: Integrator = None) -> tuple[float, float]:
86+
def _canonical_moment(self, n: int, integrator: Integrator = QuadIntegrator()) -> tuple[float, float]:
9087
"""
9188
Compute n-th moment of canonical NMM
9289
9390
Args:
9491
n (): Moment ordinal
95-
params (): Parameters of integration algorithm
96-
integrator (): type of integrator to computing
92+
integrator (): class of integrator with params to computing
9793
9894
Returns: moment approximation and error tolerance
9995
10096
"""
10197
mixture_moment = 0
10298
error_tolerance = 0
103-
integrator = integrator or QuadIntegrator()
10499
for k in range(0, n + 1):
105100
coefficient = binom(n, n - k) * (self.params.sigma ** k)
106-
mixing_moment = integrator.compute_integral(lambda u: self.params.distribution.ppf(u) ** (n - k),
107-
{"a": 0, "b": 1, **params})
101+
mixing_moment = integrator.compute(lambda u: self.params.distribution.ppf(u) ** (n - k))
108102
error_tolerance += mixing_moment.error
109103
mixture_moment += coefficient * mixing_moment.value * norm.moment(k)
110104
return mixture_moment, error_tolerance
111105

112-
def compute_moment(self, n: int, params: dict, integrator: Integrator = None) -> tuple[float, float]:
106+
def compute_moment(self, n: int, integrator: Integrator = QuadIntegrator) -> tuple[float, float]:
113107
"""
114108
Compute n-th moment of NMM
115109
116110
Args:
117111
n (): Moment ordinal
118-
params (): Parameters of integration algorithm
119-
integrator (): type of integrator to computing
112+
integrator (): class of integrator with params to computing
120113
121114
Returns: moment approximation and error tolerance
122115
123116
"""
124117
if isinstance(self.params, _NMMClassicDataCollector):
125-
return self._classical_moment(n, params, integrator)
126-
return self._canonical_moment(n, params, integrator)
118+
return self._classical_moment(n, integrator)
119+
return self._canonical_moment(n, integrator)
127120

128-
def _canonical_compute_cdf(self, x: float, params: dict, integrator: Integrator = None) -> tuple[float, float]:
121+
def _canonical_compute_cdf(self, x: float, integrator: Integrator = RQMCIntegrator) -> tuple[float, float]:
129122
"""
130123
Equation for canonical cdf
131124
Args:
132125
x (): point
133-
params (): parameters of RQMC algorithm
134-
integrator (): type of integrator to computing
126+
integrator (): class of integrator with params to computing
135127
136128
Returns: computed cdf and error tolerance
137129
138130
"""
139-
integrator = integrator or RQMCIntegrator()
140-
rqmc = integrator.compute_integral(func=lambda u: norm.cdf((x - self.params.distribution.ppf(u)) / np.abs(self.params.sigma)), **params)
141-
return rqmc.value, rqmc.error
131+
result = integrator.compute(func=lambda u: norm.cdf((x - self.params.distribution.ppf(u)) / np.abs(self.params.sigma)))
132+
return result.value, result.error
142133

143-
def _classical_compute_cdf(self, x: float, params: dict, integrator: Integrator = None) -> tuple[float, float]:
134+
def _classical_compute_cdf(self, x: float, integrator: Integrator = RQMCIntegrator) -> tuple[float, float]:
144135
"""
145136
Equation for classic cdf
146137
Args:
147138
x (): point
148-
params (): parameters of RQMC algorithm
149-
integrator (): type of integrator to computing
139+
integrator (): class of integrator with params to computing
150140
151141
Returns: computed cdf and error tolerance
152142
153143
"""
154-
integrator = integrator or RQMCIntegrator()
155-
rqmc = integrator.compute_integral(func=
144+
result = integrator.compute(func=
156145
lambda u: norm.cdf(
157146
(x - self.params.alpha - self.params.beta * self.params.distribution.ppf(u)) / np.abs(self.params.gamma)
158-
),
159-
**params
147+
)
160148
)
161-
return rqmc.value, rqmc.error
149+
return result.value, result.error
162150

163-
def compute_cdf(self, x: float, params: dict, integrator: Integrator = None) -> tuple[float, float]:
151+
def compute_cdf(self, x: float, integrator: Integrator = RQMCIntegrator) -> tuple[float, float]:
164152
"""
165153
Choose equation for cdf estimation depends on Mixture form
166154
Args:
167155
x (): point
168-
params (): parameters of RQMC algorithm
169-
integrator (): type of integrator to computing
156+
integrator (): class of integrator with params to computing
170157
171158
Returns: Computed pdf and error tolerance
172159
173160
"""
174161
if isinstance(self.params, _NMMCanonicalDataCollector):
175-
return self._canonical_compute_cdf(x, params, integrator)
176-
return self._classical_compute_cdf(x, params, integrator)
162+
return self._canonical_compute_cdf(x, integrator)
163+
return self._classical_compute_cdf(x, integrator)
177164

178-
def _canonical_compute_pdf(self, x: float, params: dict, integrator: Integrator = None) -> tuple[float, float]:
165+
def _canonical_compute_pdf(self, x: float, integrator: Integrator = RQMCIntegrator) -> tuple[float, float]:
179166
"""
180167
Equation for canonical pdf
181168
Args:
182169
x (): point
183-
params (): parameters of RQMC algorithm
184-
integrator (): type of integrator to computing
170+
integrator (): class of integrator with params to computing
185171
186172
Returns: computed pdf and error tolerance
187173
188174
"""
189-
integrator = integrator or RQMCIntegrator()
190-
rqmc = integrator.compute_integral(func=
175+
result = integrator.compute(func=
191176
lambda u: (1 / np.abs(self.params.sigma))
192177
* norm.pdf((x - self.params.distribution.ppf(u)) / np.abs(self.params.sigma)),
193-
**params
194178
)
195-
return rqmc.value, rqmc.error
179+
return result.value, result.error
196180

197-
def _classical_compute_pdf(self, x: float, params: dict, integrator: Integrator = None) -> tuple[float, float]:
181+
def _classical_compute_pdf(self, x: float, integrator: Integrator = RQMCIntegrator()) -> tuple[float, float]:
198182
"""
199183
Equation for classic pdf
200184
Args:
201185
x (): point
202-
params (): parameters of RQMC algorithm
203-
integrator (): type of integrator to computing
186+
integrator (): class of integrator with params to computing
204187
205188
Returns: computed pdf and error tolerance
206189
207190
"""
208-
integrator = integrator or RQMCIntegrator()
209-
rqmc = integrator.compute_integral(func=
191+
result = integrator.compute(func=
210192
lambda u: (1 / np.abs(self.params.gamma))
211193
* norm.pdf(
212194
(x - self.params.alpha - self.params.beta * self.params.distribution.ppf(u)) / np.abs(self.params.gamma)
213195
),
214-
**params
215196
)
216-
return rqmc.value, rqmc.error
197+
return result.value, result.error
217198

218-
def compute_pdf(self, x: float, params: dict, integrator: Integrator = None) -> tuple[float, float]:
199+
def compute_pdf(self, x: float, integrator: Integrator = RQMCIntegrator()) -> tuple[float, float]:
219200
"""
220201
Choose equation for pdf estimation depends on Mixture form
221202
Args:
222203
x (): point
223-
params (): parameters of RQMC algorithm
224-
integrator (): type of integrator to computing
204+
integrator (): class of integrator with params to computing
225205
226206
Returns: Computed pdf and error tolerance
227207
228208
"""
229209
if isinstance(self.params, _NMMCanonicalDataCollector):
230-
return self._canonical_compute_pdf(x, params, integrator)
231-
return self._classical_compute_pdf(x, params, integrator)
210+
return self._canonical_compute_pdf(x, integrator)
211+
return self._classical_compute_pdf(x, integrator)
232212

233213
def _classical_compute_log_pdf(self, x: float, params: dict) -> tuple[float, float]:
234214
"""

0 commit comments

Comments
 (0)