def test_points(a, b): # Check that initial interval splitting is done according to # `points`, by checking that consecutive sets of 15 point (for # gk15) function evaluations lie between `points` points = (0, 0.25, 0.5, 0.75, 1.0) points += tuple(-x for x in points) quadrature_points = 15 interval_sets = [] count = 0 def f(x): nonlocal count if count % quadrature_points == 0: interval_sets.append(set()) count += 1 interval_sets[-1].add(float(x)) return 0.0 quad_vec(f, a, b, points=points, quadrature='gk15', limit=0) # Check that all point sets lie in a single `points` interval for p in interval_sets: j = np.searchsorted(sorted(points), tuple(p)) assert np.all(j == j[0])
def test_quad_vec_simple(quadrature): n = np.arange(10) f = lambda x: x**n for epsabs in [0.1, 1e-3, 1e-6]: if quadrature == 'trapz' and epsabs < 1e-4: # slow: skip continue kwargs = dict(epsabs=epsabs, quadrature=quadrature) exact = 2**(n+1)/(n + 1) res, err = quad_vec(f, 0, 2, norm='max', **kwargs) assert_allclose(res, exact, rtol=0, atol=epsabs) res, err = quad_vec(f, 0, 2, norm='2', **kwargs) assert np.linalg.norm(res - exact) < epsabs res, err = quad_vec(f, 0, 2, norm='max', points=(0.5, 1.0), **kwargs) assert_allclose(res, exact, rtol=0, atol=epsabs) res, err, *rest = quad_vec(f, 0, 2, norm='max', epsrel=1e-8, full_output=True, limit=10000, **kwargs) assert_allclose(res, exact, rtol=0, atol=epsabs)
def test_quad_vec_simple(): n = np.arange(10) f = lambda x: x**n for epsabs in [0.1, 1e-3, 1e-6]: exact = 2**(n + 1) / (n + 1) res, err = quad_vec(f, 0, 2, norm='max', epsabs=epsabs) assert_allclose(res, exact, rtol=0, atol=epsabs) res, err = quad_vec(f, 0, 2, norm='2', epsabs=epsabs) assert np.linalg.norm(res - exact) < epsabs res, err = quad_vec(f, 0, 2, norm='max', epsabs=epsabs, points=(0.5, 1.0)) assert_allclose(res, exact, rtol=0, atol=epsabs) res, err, *rest = quad_vec(f, 0, 2, norm='max', epsrel=1e-8, epsabs=epsabs, full_output=True, limit=10000, quadrature='trapz') assert_allclose(res, exact, rtol=0, atol=epsabs)
def test_quad_vec_pool(): f = _lorenzian res, err = quad_vec(f, -np.inf, np.inf, norm='max', epsabs=1e-4, workers=4) assert_allclose(res, np.pi, rtol=0, atol=1e-4) with Pool(10) as pool: f = lambda x: 1 / (1 + x**2) res, err = quad_vec(f, -np.inf, np.inf, norm='max', epsabs=1e-4, workers=pool.map) assert_allclose(res, np.pi, rtol=0, atol=1e-4)
def test_quad_vec_pool_args(extra_args, workers): f = _func_with_args exact = np.array([0, 4/3, 8/3]) res, err = quad_vec(f, 0, 1, args=extra_args, workers=workers) assert_allclose(res, exact, rtol=0, atol=1e-4) with Pool(workers) as pool: res, err = quad_vec(f, 0, 1, args=extra_args, workers=pool.map) assert_allclose(res, exact, rtol=0, atol=1e-4)
def test_quad_vec_pool(): from multiprocessing.dummy import Pool f = _lorenzian res, err = quad_vec(f, -np.inf, np.inf, norm='max', epsabs=1e-4, workers=4) assert_allclose(res, np.pi, rtol=0, atol=1e-4) with Pool(10) as pool: f = lambda x: 1 / (1 + x**2) res, err = quad_vec(f, -np.inf, np.inf, norm='max', epsabs=1e-4, workers=pool.map) assert_allclose(res, np.pi, rtol=0, atol=1e-4)
def LF2_2d(mu_x, mu_y, sigma, f): Print("Called") loss = -np.sum( np.log( quad_vec( lambda y: quad_vec( lambda x: P_2d(x, y, mu_x, mu_y, sigma, f) * (gauss2d(x, y, xy_reco, xy_sigma)), -lim, lim)[0], -lim, lim)[0])) Print("Returning Loss") return loss
def test_nan_inf(): def f_nan(x): return np.nan def f_inf(x): return np.inf if x < 0.1 else 1/x res, err, info = quad_vec(f_nan, 0, 1, full_output=True) assert info.status == 3 res, err, info = quad_vec(f_inf, 0, 1, full_output=True) assert info.status == 3
def test_nan_inf(): def f_nan(x): return np.nan def f_inf(x): return np.inf if x < 0.1 else 1 / x res, err, info = quad_vec(f_nan, 0, 1, full_output=True) assert info.status == 3 res, err, info = quad_vec(f_inf, 0, 1, full_output=True) assert info.status == 3
def test_quad_vec_simple_inf(quadrature): f = lambda x: 1 / (1 + np.float64(x)**2) for epsabs in [0.1, 1e-3, 1e-6]: if quadrature == 'trapz' and epsabs < 1e-4: # slow: skip continue kwargs = dict(norm='max', epsabs=epsabs, quadrature=quadrature) res, err = quad_vec(f, 0, np.inf, **kwargs) assert_allclose(res, np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, 0, -np.inf, **kwargs) assert_allclose(res, -np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, 0, **kwargs) assert_allclose(res, np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, 0, **kwargs) assert_allclose(res, -np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, np.inf, **kwargs) assert_allclose(res, np.pi, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, -np.inf, **kwargs) assert_allclose(res, -np.pi, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, np.inf, **kwargs) assert_allclose(res, 0, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, -np.inf, **kwargs) assert_allclose(res, 0, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, 0, np.inf, points=(1.0, 2.0), **kwargs) assert_allclose(res, np.pi / 2, rtol=0, atol=max(epsabs, err)) f = lambda x: np.sin(x + 2) / (1 + x**2) exact = np.pi / np.e * np.sin(2) epsabs = 1e-5 res, err, info = quad_vec(f, -np.inf, np.inf, limit=1000, norm='max', epsabs=epsabs, quadrature=quadrature, full_output=True) assert info.status == 1 assert_allclose(res, exact, rtol=0, atol=max(epsabs, 1.5 * err))
def test_quad_vec_simple_inf(): f = lambda x: 1 / (1 + np.float64(x)**2) for epsabs in [0.1, 1e-3, 1e-6]: res, err = quad_vec(f, 0, np.inf, norm='max', epsabs=epsabs) assert_allclose(res, np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, 0, -np.inf, norm='max', epsabs=epsabs) assert_allclose(res, -np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, 0, norm='max', epsabs=epsabs) assert_allclose(res, np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, 0, norm='max', epsabs=epsabs) assert_allclose(res, -np.pi / 2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, np.inf, norm='max', epsabs=epsabs) assert_allclose(res, np.pi, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, -np.inf, norm='max', epsabs=epsabs) assert_allclose(res, -np.pi, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, np.inf, norm='max', epsabs=epsabs) assert_allclose(res, 0, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, -np.inf, norm='max', epsabs=epsabs) assert_allclose(res, 0, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, 0, np.inf, norm='max', epsabs=epsabs, points=(1.0, 2.0)) assert_allclose(res, np.pi / 2, rtol=0, atol=max(epsabs, err)) f = lambda x: np.sin(x + 2) / (1 + x**2) exact = np.pi / np.e * np.sin(2) epsabs = 1e-5 res, err, info = quad_vec(f, -np.inf, np.inf, limit=1000, norm='max', epsabs=epsabs, full_output=True) assert_allclose(res, exact, rtol=0, atol=max(epsabs, err))
def test_quad_vec_args(): f = lambda x, a: x * (x + a) * np.arange(3) a = 2 exact = np.array([0, 4/3, 8/3]) res, err = quad_vec(f, 0, 1, args=(a,)) assert_allclose(res, exact, rtol=0, atol=1e-4)
def voigt_nobg(x, a, b, s, g, clib=True): """Voigt function with no background (Base Voigt function). This is the base of all the other Voigt functions. Parameters ---------- ${SINGLE_VOIGT} ${CLIB} ${EXTRA_STD} """ warnings.filterwarnings("ignore", category=IntegrationWarning) u = x - b if clib and not_on_rtd: i = [ quad(cvoigt, -np.inf, np.inf, args=(v, s, g), epsabs=1.49e-1, epsrel=1.49e-4)[0] for v in u ] else: i = quad_vec( lambda y: np.exp(-y**2 / (2 * s**2)) / (g**2 + (u - y)**2), -np.inf, np.inf, **rtd)[0] const = g / (s * np.sqrt(2 * np.pi**3)) return a * const * np.array(i)
def test_univar_cond(self): # ================= Univarite unconditional density with Boston dataset ================== for estimator_cls in ESTIMATOR_CLS: X, y = load_boston(return_X_y=True) # Train/test splits y_train, y_test, X_train, X_test = train_test_split(y, X, random_state=11) estimator = estimator_cls(context_size=X_train.shape[1], n_epochs=1000, input_noise_std=0.3, context_noise_std=0.1, n_components=5, lr=0.001, transform_classes=DEFAULT_TRANSFORMS) estimator.fit(train_inputs=y_train, train_context=X_train, verbose=True, val_inputs=y_test, val_context=X_test, log_frequency=1000) # Density check with torch.no_grad(): int_res = integrate.quad_vec(lambda x: np.exp(estimator.log_prob(np.repeat(x, len(X_test)), context=X_test)), -np.inf, np.inf, epsabs=EPSABS)[0] logging.info(f'Mean integral of cond density: {int_res.mean()}') np.testing.assert_array_almost_equal(int_res, np.ones(len(X_test)), ASSERT_DECIMAL) # Sampling with torch.no_grad(): y_sampled = estimator.sample(num_samples=1, context=X_test).reshape(-1) g = self._plot_univariate(y_test, y_sampled) g.fig.suptitle(f'Uni-variate conditional sampling ({estimator_cls.__name__})') plt.show()
def quad_fn(interp3d, ray_axes, near, far): points = None #np.linspace(near, far, nx/2) res = integrate.quad_vec(lambda r: interp3d(ray_axes * r - dv), near, far, points=points, limit=quad_lim) return res[0]
def SolveStokes(force, pos, args): mu = args[0] if args[1] == "stokeslet": res = si.quad_vec( lambda x: nm.einsum("ij,j", OseenTensor([pos[0] - x, pos[1], pos[2]], mu), f(x, 0, 0)), -np.inf, np.inf)[0] return res
def test_num_eval(quadrature): def f(x): count[0] += 1 return x**5 count = [0] res = quad_vec(f, 0, 1, norm='max', full_output=True, quadrature=quadrature) assert res[2].neval == count[0]
def test_num_eval(): def f(x): count[0] += 1 return x**5 for q in ['gk21', 'trapz']: count = [0] res = quad_vec(f, 0, 1, norm='max', full_output=True, quadrature=q) assert res[2].neval == count[0]
def _integrate_esd_second_term_quad(self): second_term, second_term_errors = integrate.quad_vec( lambda theta: self._esd_second_term_integrand_func( np.array([theta])), 0, np.pi / 2, ) _check_errors_ok(second_term_errors) return second_term
def Q_day(t, beta, rho, eps, phi=phis): # Takes either single or list of days to calculate insol for r, theta = polar_pos(eps, t) mag, phase, c = trig_coefs(beta, rho, theta.reshape(-1, 1), phi) I_day = quad_vec(lambda gamma: I_fast(gamma, mag, phase, c), 0, 2 * np.pi, epsrel=1)[0] Q_day = K / (8 * np.pi**2 * r**2) * I_day.T return Q_day
def integrated_vortex_c_2d(start_pt, end_pt, col_pt): """Integrates vortex_2d to obtain vortex_c_2d output.""" panel_length = np.linalg.norm(end_pt - start_pt) panel_tangent = (end_pt - start_pt) / panel_length def integrand(s): vortex_pt = start_pt + panel_tangent * s return vortex_2d(1, vortex_pt, col_pt) return integrate.quad_vec(integrand, 0, panel_length, epsabs=1e-9)[0]
def test_quad_vec_simple(): n = np.arange(10) f = lambda x: x**n for epsabs in [0.1, 1e-3, 1e-6]: exact = 2**(n+1)/(n + 1) res, err = quad_vec(f, 0, 2, norm='max', epsabs=epsabs) assert_allclose(res, exact, rtol=0, atol=epsabs) res, err = quad_vec(f, 0, 2, norm='2', epsabs=epsabs) assert np.linalg.norm(res - exact) < epsabs res, err = quad_vec(f, 0, 2, norm='max', epsabs=epsabs, points=(0.5, 1.0)) assert_allclose(res, exact, rtol=0, atol=epsabs) res, err, *rest = quad_vec(f, 0, 2, norm='max', epsrel=1e-8, epsabs=epsabs, full_output=True, limit=10000, quadrature='trapz') assert_allclose(res, exact, rtol=0, atol=epsabs)
def test_info(): def f(x): return np.ones((3, 2, 1)) res, err, info = quad_vec(f, 0, 1, norm='max', full_output=True) assert info.success == True assert info.status == 0 assert info.message == 'Target precision reached.' assert info.neval > 0 assert info.intervals.shape[1] == 2 assert info.integrals.shape == (info.intervals.shape[0], 3, 2, 1) assert info.errors.shape == (info.intervals.shape[0],)
def test_info(): def f(x): return np.ones((3, 2, 1)) res, err, info = quad_vec(f, 0, 1, norm='max', full_output=True) assert info.success == True assert info.status == 0 assert info.message == 'Target precision reached.' assert info.neval > 0 assert info.intervals.shape[1] == 2 assert info.integrals.shape == (info.intervals.shape[0], 3, 2, 1) assert info.errors.shape == (info.intervals.shape[0], )
def test_quad_vec_simple_inf(): f = lambda x: 1 / (1 + np.float64(x)**2) for epsabs in [0.1, 1e-3, 1e-6]: res, err = quad_vec(f, 0, np.inf, norm='max', epsabs=epsabs) assert_allclose(res, np.pi/2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, 0, -np.inf, norm='max', epsabs=epsabs) assert_allclose(res, -np.pi/2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, 0, norm='max', epsabs=epsabs) assert_allclose(res, np.pi/2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, 0, norm='max', epsabs=epsabs) assert_allclose(res, -np.pi/2, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, np.inf, norm='max', epsabs=epsabs) assert_allclose(res, np.pi, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, -np.inf, norm='max', epsabs=epsabs) assert_allclose(res, -np.pi, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, np.inf, np.inf, norm='max', epsabs=epsabs) assert_allclose(res, 0, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, -np.inf, -np.inf, norm='max', epsabs=epsabs) assert_allclose(res, 0, rtol=0, atol=max(epsabs, err)) res, err = quad_vec(f, 0, np.inf, norm='max', epsabs=epsabs, points=(1.0, 2.0)) assert_allclose(res, np.pi/2, rtol=0, atol=max(epsabs, err)) f = lambda x: np.sin(x + 2) / (1 + x**2) exact = np.pi / np.e * np.sin(2) epsabs = 1e-5 res, err, info = quad_vec(f, -np.inf, np.inf, limit=1000, norm='max', epsabs=epsabs, full_output=True) assert_allclose(res, exact, rtol=0, atol=max(epsabs, err))
def computeMagFieldResponse(coiloffset, reflection_coefficient, wavenumber): """ . """ from scipy.special import jv from scipy.integrate import quad_vec def integrand(wavenumber): return np.imag(reflection_coefficient) * jv( 0, wavenumber * coiloffset) * wavenumber**2 integrated, error = quad_vec(integrand, 0, np.inf) return 1 - coiloffset**3 * integrated
def _integrate_esd_first_term_quad(self): rflats = self.radii.flatten() first_term_integral = np.array( [ integrate.quad_vec( lambda x: self._esd_first_term_integrand_func( np.array([x]), rflats[i:i + 1]), MIN_INTEGRATION_RADIUS, rflats[i], ) for i in range(self.radii.size) ], dtype=object, ) _check_errors_ok(first_term_integral[:, 1].astype(float)) return np.concatenate(first_term_integral[:, 0]).astype(float)
def _plot_and_test_mb_cond_dist(synt_ex: SyntheticExample, var_ind, method): logging.info( f'Calculating MB conditional distribution, using method {method}') var = synt_ex.var_names[var_ind] sample = synt_ex.sem.sample(SAMPLE_SIZE, seed=SEED) global_context = { node: sample[:, node_ind] for (node_ind, node) in enumerate(synt_ex.var_names) if node != var } mc_prob = synt_ex.sem.mb_conditional_log_prob( var, global_context=global_context, method=method, quad_epsabs=EPSABS, mc_size=MC_SIZE) # Checking integration to zero integrand = lambda val: mc_prob( torch.tensor(val).repeat(1, len(sample))).exp().numpy() int_res = quad_vec(integrand, *synt_ex.sem.support_bounds, epsabs=EPSABS)[0] logging.info(f'Mean integral of cond density: {int_res.mean()}') if method == 'quad': np.testing.assert_array_almost_equal(int_res.flatten(), np.ones(len(sample)), ASSERT_DECIMAL) # Plotting conditional distributions values = torch.linspace(sample[:, var_ind].min() - 1.0, sample[:, var_ind].max() + 1.0, 200) mc_prob_vals = mc_prob(values.unsqueeze(-1).repeat( 1, len(sample))).exp().T fig, ax = plt.subplots() for i, mc_prob_val in enumerate(mc_prob_vals): ax.plot(values, mc_prob_val, alpha=0.1, c='blue') plt.title( f'Density of {var} / {[node for node in synt_ex.var_names if node != var]}' ) plt.show(block=False)
no_time_steps = 10 f0 = 100 seed = 123456789 no_paths = 1000000 delta_vix = 1.0 / 12.0 T = 0.1 # random number generator rnd_generator = RNG.RndGenerator(seed) option_vix_price = [] implied_vol_vix = [] value = quad_vec(lambda x: np.exp(nu * nu * np.power(x, 2.0 * h)), 0.0, 1.0 / 12.0) beta_vix_0 = np.sqrt(value[0] / delta_vix) vix_t0 = sigma_0 * beta_vix_0 vix_t_0_aux = ExpansionTools.get_vix_rbergomi_t(0.000001, delta_vix + 0.000001, delta_vix, nu, h, np.asfortranarray(v0), v0, 200) no_strikes = 30 strikes = np.linspace(0.95, 1.05, no_strikes) * vix_t0 map_output = RBergomi_Engine.get_path_multi_step(0.0, T, parameters, f0, sigma_0, no_paths, no_time_steps, Types.TYPE_STANDARD_NORMAL_SAMPLING.ANTITHETIC, rnd_generator) for i in range(0, no_strikes): t_i_vix = T + delta_vix
def mb_conditional_log_prob(self, node: str, global_context: Dict[str, Tensor] = None, method='mc', mc_size=500, quad_epsabs=1e-2, mc_seed=None) -> callable: """ Conditional log-probability function (density) of node, conditioning on Markov-Blanket of node Args: node: Node global_context: Conditioning global_context, as dict of all the other variables, each value should be torch.Tensor of shape (n, ) method: 'mc' or 'quad', method to compute normalisation constant (Monte-Carlo integration or quadrature integration) mc_size: if method == 'mc', MC samples for integration mc_seed: mc_seed for MC sampling quad_epsabs: epsabs for scipy.integrate.quad Returns: """ global_context = {} if global_context is None else global_context # Checking, if all vars from MarkovBlanket(node) are present assert all([ mb_var in global_context.keys() for mb_var in self.get_markov_blanket(node) ]) parents_context = { par: global_context[par] for par in self.model[node]['parents'] } context_size = len(list(global_context.values())[0]) if method == 'mc': torch.manual_seed(mc_seed) if mc_seed is not None else None sample_shape = ( mc_size, 1) if len(parents_context) != 0 and self.is_batched else ( mc_size, context_size) sampled_value = self.parents_conditional_sample( node, parents_context, sample_shape) normalisation_constant = self.children_log_prob( node, sampled_value, global_context).exp().mean(0) elif method == 'quad': normalisation_constant = [] for cont_ind in tqdm(range(context_size)): global_context_slice = { node: value[cont_ind:cont_ind + 1] for (node, value) in global_context.items() } parents_context_slice = { par: global_context_slice[par] for par in self.model[node]['parents'] } def integrand(value): value = torch.tensor([value]) parents_cond_dist = self.parents_conditional_distribution( node, parents_context_slice) unnorm_log_prob = parents_cond_dist.log_prob(value) + \ self.children_log_prob(node, value, global_context_slice) return unnorm_log_prob.exp().item() normalisation_constant.append( quad_vec(integrand, *self.support_bounds, epsabs=quad_epsabs)[0]) normalisation_constant = torch.tensor(normalisation_constant) else: raise NotImplementedError() def cond_log_prob(value): value = value.reshape(-1, context_size) result = self.parents_conditional_distribution( node, parents_context).log_prob(value) # Considering only inside-support values for conditional distributions of children_nodes in_support = (~torch.isinf(result)) for val_ind, val in enumerate(value): global_context_tile = { n: v[in_support[val_ind]] for (n, v) in global_context.items() } children_lob_prob = self.children_log_prob( node, val[in_support[val_ind]].unsqueeze(0), global_context_tile) result[val_ind, in_support[val_ind]] += children_lob_prob.squeeze() return result - normalisation_constant.log() return cond_log_prob
def LF2_1d(mu, sigma): return -np.sum( np.log( quad_vec(lambda x: gauss(x, mu, sigma) * gauss(x, mus, sigmas), *lims)[0]))
def gamma_n_to_p(z_gamma,xi_nu): integral=quad_vec(lambda epsilon: n_to_p_int(epsilon,z_gamma,sign=1,xi_nu=xi_nu),1,np.inf) return integral[0]
# ..., c-3, c-2, c-1, c0, c1, c2, c3, ... order = 100 # -order to order i.e -100 to 100 # you can change the order to get proper figure # too much is also not good, and too less will not produce good result print("generating coefficients ...") # lets compute fourier coefficients from -order to order c = [] pbar = tqdm(total=(order * 2 + 1)) # we need to calculate the coefficients from -order to order for n in range(-order, order + 1): # calculate definite integration from 0 to 2*PI # formula is given in readme coef = 1 / tau * quad_vec( lambda t: f(t, t_list, x_list, y_list) * np.exp(-n * t * 1j), 0, tau, limit=100, full_output=1)[0] c.append(coef) pbar.update(1) pbar.close() print("completed generating coefficients.") # converting list into numpy array c = np.array(c) # save the coefficients for later use np.save("coeff.npy", c) ## -- now to make animation with epicycle -- ##
def __call__(self, estimator: ConditionalDistributionEstimator, sem: StructuralEquationModel, target_var: str, context_vars: Tuple[str], exp_args: Union[DictConfig, dict], conditioning_mode: str = 'all', test_df: pd.DataFrame = None, sort_estimator_context=True): logger.info( f"Calculating {self.name} for {target_var} / {context_vars}") assert target_var not in context_vars context = { node: torch.tensor(test_df.loc[:, node]) for node in context_vars } context_size = len(test_df) logger.info("Initializing SEM conditional distributions") if conditioning_mode == 'true_parents': data_log_prob = sem.parents_conditional_distribution( target_var, parents_context=context).log_prob elif conditioning_mode == 'true_markov_blanket' or conditioning_mode == 'all': data_log_prob = sem.mb_conditional_log_prob(target_var, global_context=context, **exp_args['mb_dist']) elif conditioning_mode == 'arbitrary' and isinstance( sem, LinearGaussianNoiseSEM): data_log_prob = sem.conditional_distribution( target_var, context=context).log_prob else: raise NotImplementedError('Unknown conditioning type!') def log_prob_from_np(value, log_prob_func): value = torch.tensor([[value]]) with torch.no_grad(): return log_prob_func(value.repeat(context_size, 1)).squeeze() logger.info("Initializing estimator's conditional distributions") if sort_estimator_context: test_context = test_df[Sampler._order_fset( context_vars)].to_numpy() else: test_context = test_df[context_vars].to_numpy() model_log_prob = estimator.conditional_distribution( test_context).log_prob logger.info("Calculating integral") if self.name == 'conditional_kl_divergence' or self.name == 'conditional_hellinger_distance': def integrand(value): data_log_p = log_prob_from_np(value, data_log_prob) model_log_p = log_prob_from_np(value, model_log_prob) if self.name == 'conditional_kl_divergence': res = (data_log_p - model_log_p) * data_log_p.exp() elif self.name == 'conditional_hellinger_distance': res = (torch.sqrt(data_log_p.exp()) - torch.sqrt(model_log_p.exp()))**2 res[torch.isnan(res)] = 0.0 # Out of support values return res.numpy() if self.name == 'conditional_kl_divergence': result = integrate.quad_vec( integrand, *sem.support_bounds, epsabs=exp_args['metrics']['epsabs'])[0] else: result = integrate.quad_vec( integrand, -np.inf, np.inf, epsabs=exp_args['metrics']['epsabs'])[0] if self.name == 'conditional_hellinger_distance': result = np.sqrt(0.5 * result) elif self.name == 'conditional_js_divergence': # functions to integrate def integrand1(value): data_log_p = log_prob_from_np(value, data_log_prob) model_log_p = log_prob_from_np(value, model_log_prob) log_mixture = np.log(0.5) + torch.logsumexp( torch.stack([data_log_p, model_log_p]), 0) res = (data_log_p - log_mixture) * data_log_p.exp() res[torch.isnan(res)] = 0.0 # Out of support values return res.numpy() def integrand2(value): data_log_p = log_prob_from_np(value, data_log_prob) model_log_p = log_prob_from_np(value, model_log_prob) log_mixture = np.log(0.5) + torch.logsumexp( torch.stack([data_log_p, model_log_p]), 0) res = (model_log_p - log_mixture) * model_log_p.exp() res[torch.isnan(res)] = 0.0 # Out of support values return res.numpy() result = 0.5 * ( integrate.quad_vec(integrand1, -np.inf, np.inf, epsabs=exp_args['metrics']['epsabs'])[0] + integrate.quad_vec(integrand2, -np.inf, np.inf, epsabs=exp_args['metrics']['epsabs'])[0]) else: raise NotImplementedError() # Bounds check if not ((result + exp_args['metrics']['epsabs']) >= 0.0).all(): logger.warning( f'{((result + exp_args["metrics"]["epsabs"]) < 0.0).sum()} contexts have negative distances, ' f'Please increase cond distribution estimation accuracy. Negative values will be ignored.' ) result = result[(result + exp_args['metrics']['epsabs']) >= 0.0] if self.name == 'conditional_js_divergence' and not ( result - exp_args["metrics"]["epsabs"] <= np.log(2)).all(): logger.warning( f'{(result - exp_args["metrics"]["epsabs"] > np.log(2)).sum()} contexts have distances, ' f'larger than log(2), ' f'please increase cond distribution estimation accuracy. Larger values will be ignored.' ) result = result[(result - exp_args["metrics"]["epsabs"]) <= np.log(2)] elif self.name == 'conditional_hellinger_distance' and not ( (result - exp_args["metrics"]["epsabs"]) <= 1.0).all(): logger.warning( f'{((result - exp_args["metrics"]["epsabs"]) > 1.0).sum()} contexts have distances, larger than 1.0, ' f'please increase cond distribution estimation accuracy. Larger values will be ignored.' ) result = result[(result - exp_args.metrics.epsabs) <= 1.0] return result.mean()
def get_analytic_value(self, *args, model_type=None, compute_greek=False): if model_type == ANALYTIC_MODEL.BLACK_SCHOLES_MODEL: pass elif model_type == ANALYTIC_MODEL.SABR_MODEL: alpha = args[0] rho = args[1] nu = args[2] pass elif model_type == ANALYTIC_MODEL.HESTON_MODEL_ATTARI: r = args[0] theta = args[1] rho = args[2] k = args[3] epsilon = args[4] v0 = args[5] risk_lambda = args[6] b2 = k + risk_lambda u2 = -0.5 integrator = partial(f_attari_heston, t=self._delta_time, v=v0, spot=self._spot, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b2, u=u2, strike=self._strike) integral_value = quad_vec(integrator, 0.0, np.inf) df = np.exp(-r * self._delta_time) discrete_value = self._spot - 0.5 * self._strike * df stochastic_adjustment = (self._strike * df / np.pi) * integral_value[0][0] price = discrete_value - stochastic_adjustment if compute_greek: delta_integrator = partial(f_delta_attari_heston, t=self._delta_time, v=v0, spot=self._spot, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b2, u=u2, strike=self._strike) dual_delta_integrator = partial(f_dual_delta_attari_heston, t=self._delta_time, v=v0, spot=self._spot, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b2, u=u2, strike=self._strike) gamma_integrator = partial(f_gamma_attari_heston, t=self._delta_time, v=v0, spot=self._spot, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b2, u=u2, strike=self._strike) delta_integral = quad_vec(delta_integrator, 0.0, np.inf) dual_delta = quad_vec(dual_delta_integrator, 0.0, np.inf) gamma_integral = quad_vec(gamma_integrator, 0.0, np.inf) aux_dual_delta = (discrete_value - price) / self._strike greeks_map = { TypeGreeks.DELTA: 1.0 - (self._strike * df / np.pi) * delta_integral[0], TypeGreeks.GAMMA: -(self._strike * df / np.pi) * gamma_integral[0], TypeGreeks.DUAL_DELTA: -0.5 * df - aux_dual_delta - (df * self._strike / np.pi) * dual_delta[0] } return price, greeks_map else: return price elif model_type == ANALYTIC_MODEL.HESTON_MODEL_LEWIS: r = args[0] theta = args[1] rho = args[2] k = args[3] epsilon = args[4] v0 = args[5] integrator = partial(f_lewis_heston, t=self._delta_time, v=v0, spot=self._spot, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, strike=self._strike) integral_value = quad_vec(integrator, 0.0, np.inf) df = np.exp(-r * self._delta_time) price = self._spot - (df * self._strike / np.pi) * integral_value[0] return price elif model_type == ANALYTIC_MODEL.HESTON_MODEL_REGULAR: r = args[0] theta = args[1] rho = args[2] k = args[3] epsilon = args[4] v0 = args[5] risk_lambda = args[6] u1 = 0.5 b1 = k + risk_lambda - epsilon * rho b2 = k + risk_lambda u2 = -0.5 if self._option_type == TypeEuropeanOption.CALL: phi = 1.0 else: phi = -1.0 integrator1 = partial(f_heston, t=self._delta_time, x=np.log(self._spot), v=v0, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b1, u=u1, strike=self._strike) integrator2 = partial(f_heston, t=self._delta_time, x=np.log(self._spot), v=v0, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b2, u=u2, strike=self._strike) int_val_1 = quad_vec(integrator1, 0.0, np.inf) value_1_aux = 0.5 + (1.0 / np.pi) * int_val_1[0][0] p1 = 0.5 * (1 - phi) + phi * value_1_aux int_val_2 = quad_vec(integrator2, 0.0, np.inf) value_2_aux = 0.5 + (1.0 / np.pi) * int_val_2[0][0] p2 = 0.5 * (1 - phi) + phi * value_2_aux df = np.exp(-r * self._delta_time) price = self._spot * p1 - df * self._strike * p2 if compute_greek: gamma_integrator = partial(f_gamma_heston, t=self._delta_time, x=np.log(self._spot), v=v0, r_t=r, theta=theta, rho=rho, k=k, epsilon=epsilon, b=b2, u=u2, strike=self._strike) gamma_output = quad_vec(gamma_integrator, 0.0, np.inf) gamma = gamma_output[0] / (np.pi * self._spot) greeks_map = { TypeGreeks.DELTA: phi * p1, TypeGreeks.GAMMA: gamma, TypeGreeks.DUAL_DELTA: -phi * df * p2 } return price, greeks_map else: return price elif model_type == ANALYTIC_MODEL.BATES_MODEL_LEWIS: r = args[0] theta = args[1] rho = args[2] k = args[3] epsilon = args[4] v0 = args[5] muJ = args[6] sigmaJ = args[7] lambdaJ = args[8] integrator = partial(f_lewis_bate, t=self._delta_time, v=v0, spot=self._spot, r_t=r, theta=theta, rho=rho, k=k, mu_jump=muJ, sigma_jump=sigmaJ, lambda_jump=lambdaJ, epsilon=epsilon, strike=self._strike) integral_value = quad_vec(integrator, 0.0, np.inf) df = np.exp(-r * self._delta_time) price = self._spot - (df * self._strike / np.pi) * integral_value[0] return price else: raise Exception("The method " + str(model_type) + " is unknown.")