def test_log_pdf(xscale: Scale): normed_test_loc = 0.5 normed_test_s = 0.1 test_loc = xscale.denormalize_point(normed_test_loc) test_s = normed_test_s * xscale.width ergoLogisticMixture = LogisticMixture( components=[ Logistic( loc=xscale.denormalize_point(0.2), s=0.5 * xscale.width, scale=xscale, ), Logistic(loc=test_loc, s=test_s, scale=xscale), ], probs=[1.8629593e-29, 1.0], ) ergoLogistic = Logistic(loc=test_loc, s=test_s, scale=xscale) ## Test PDF normed_scipydist = scipy.stats.logistic(normed_test_loc, normed_test_s) for x in np.linspace(0, 1, 10): denormalized_x = xscale.denormalize_point(x) assert (normed_scipydist.pdf(x) / xscale.width == pytest.approx( float(ergoLogistic.pdf(denormalized_x)), rel=1e-3) == pytest.approx(float(ergoLogisticMixture.pdf(denormalized_x)), rel=1e-3))
def test_mixture_ppf_adversarial(): # Make a mixture with one very improbable distribution and one dominant mixture = LogisticMixture( [Logistic(10, 3), Logistic(5, 5)], [1.8629593e-29, 1.0]) assert mixture.ppf(0.5) == pytest.approx(5.0, rel=1e-3) assert mixture.ppf(0.01) == pytest.approx(-17.9755, rel=1e-3) assert mixture.ppf(0.001) == pytest.approx(-29.5337, rel=1e-3) assert mixture.ppf(0.99) == pytest.approx(27.9755, rel=1e-3) assert mixture.ppf(0.999) == pytest.approx(39.5337, rel=1e-3)
def test_logistic_mixture_normalization(): mixture = LogisticMixture([Logistic(-40, 1), Logistic(50, 10)], [0.5, 0.5]) for scale_min, scale_max in [(0, 10), (10, 100), (-10, 10), (-100, -10)]: assert (mixture.normalize(scale_min, scale_max).denormalize(scale_min, scale_max) == mixture) normalized = mixture.normalize(-50, 50) assert normalized == LogisticMixture( [Logistic(0.1, 0.01), Logistic(1, 0.1)], [0.5, 0.5])
def test_percentiles_from_mixture(): mixture = LogisticMixture( components=[Logistic(loc=1, scale=0.1), Logistic(loc=2, scale=0.1)], probs=[0.5, 0.5], ) conditions = mixture.percentiles(percentiles=[0.1, 0.5, 0.9]) for condition in conditions: if condition.max == 0.5: assert condition.p == pytest.approx(1.5, rel=0.01) return conditions
def test_cdf(xscale: Scale): scipydist_normed = scipy.stats.logistic(0.5, 0.05) true_loc = xscale.denormalize_point(0.5) true_s = 0.05 * xscale.width ergodist = Logistic(loc=true_loc, s=true_s, scale=xscale) for x in np.linspace(0, 1, 10): assert scipydist_normed.cdf(x) == pytest.approx(float( ergodist.cdf(xscale.denormalize_point(x))), rel=1e-3) # TODO: consider a better approach for log scale if isinstance(xscale, LogScale): for x in np.linspace(xscale.low, xscale.high, 10): assert scipydist_normed.cdf( xscale.normalize_point(x)) == pytest.approx(float( ergodist.cdf(x)), rel=1e-3) else: scipydist_true = scipy.stats.logistic(true_loc, true_s) for x in np.linspace(xscale.low, xscale.high, 10): assert scipydist_true.cdf(x) == pytest.approx(float( ergodist.cdf(x)), rel=1e-3)
def test_logistic_mixture_normalization(): scale = Scale(-50, 50) scalex2 = Scale(-100, 100) mixture = LogisticMixture( components=[Logistic(-40, 1, scale), Logistic(50, 10, scale)], probs=[0.5, 0.5], ) mixturex2 = LogisticMixture( components=[Logistic(-80, 2, scalex2), Logistic(100, 20, scalex2)], probs=[0.5, 0.5], ) assert mixturex2 == mixture.normalize().denormalize(scalex2) assert mixture == mixturex2.normalize().denormalize(scale) normalized = (mixture.normalize() ) # not necessary to normalize but here for readability assert normalized == LogisticMixture( [Logistic(0.1, 0.01, Scale(0, 1)), Logistic(1, 0.1, Scale(0, 1))], [0.5, 0.5], )
def test_mixture_ppf_adversarial(): # Make a mixture with one very improbable distribution and one dominant mixture = LogisticMixture([Logistic(10, 3), Logistic(5, 5)], [1.8629593e-29, 1.0]) assert mixture.ppf(0.5) == pytest.approx(5.0, rel=1e-3) assert mixture.ppf(0.01) == pytest.approx(-17.9755, rel=1e-3) assert mixture.ppf(0.001) == pytest.approx(-29.5337, rel=1e-3) assert mixture.ppf(0.99) == pytest.approx(27.9755, rel=1e-3) assert mixture.ppf(0.999) == pytest.approx(39.5337, rel=1e-3) # Make a mixture with hugely overlapping distributions mixture = LogisticMixture( [ Logistic(4000000.035555004, 200000.02), Logistic(4000000.0329152746, 200000.0), ], [0.5, 0.5], ) assert mixture.ppf(0.5) == pytest.approx(4000000.0342351394, rel=1e-3) assert mixture.ppf(0.01) == pytest.approx(3080976.018257023, rel=1e-3) assert mixture.ppf(0.001) == pytest.approx(2618649.009437881, rel=1e-3) assert mixture.ppf(0.99) == pytest.approx(4919024.050213255, rel=1e-3) assert mixture.ppf(0.999) == pytest.approx(5381351.059032397, rel=1e-3)
def test_pdf(xscale: Scale): normed_test_loc = 0.5 normed_test_s = 0.1 test_loc = xscale.denormalize_point(normed_test_loc) test_s = normed_test_s * xscale.width ergoLogisticMixture = LogisticMixture( components=[ Logistic( loc=xscale.denormalize_point(0.2), s=0.5 * xscale.width, scale=xscale, ), Logistic(loc=test_loc, s=test_s, scale=xscale), ], probs=[1.8629593e-29, 1.0], ) ergoLogistic = Logistic(loc=test_loc, s=test_s, scale=xscale) ## Make sure it integrates to 1 _xs = xscale.denormalize_points(np.linspace(0, 1, 100)) densities_logistic = np.array([float(ergoLogistic.pdf(x)) for x in _xs]) densities_mixture = np.array( [float(ergoLogisticMixture.pdf(x)) for x in _xs]) auc_logistic = float(trapz(densities_logistic, x=_xs)) auc_mixture = float(trapz(densities_mixture, x=_xs)) assert (1 == pytest.approx(auc_logistic, abs=0.03) == pytest.approx( auc_mixture, abs=0.03)) if not isinstance(xscale, LogScale): scipydist = scipy.stats.logistic(test_loc, test_s) for x in np.linspace(xscale.denormalize_point(0), xscale.denormalize_point(1), 10): assert (scipydist.pdf(x) == pytest.approx( float(ergoLogistic.pdf(x)), rel=1e-3) == pytest.approx( float(ergoLogisticMixture.pdf(x)), rel=1e-3))
def test_truncated_ppf(xscale: Scale): normed_test_loc = 0.5 normed_test_s = 0.1 test_loc = xscale.denormalize_point(normed_test_loc) test_s = normed_test_s * xscale.width normed_baseline_dist = scipy.stats.logistic(normed_test_loc, normed_test_s) def ppf_through_cdf(dist, q): return scipy.optimize.bisect(lambda x: dist.cdf(x) - q, dist.ppf(0.0001), dist.ppf(0.9999), maxiter=1000) # No bounds dist_w_no_bounds = Truncate(Logistic(loc=test_loc, s=test_s, scale=xscale)) for x in np.linspace(0.01, 0.99, 8): assert dist_w_no_bounds.ppf(x) == pytest.approx(float( xscale.denormalize_point(normed_baseline_dist.ppf(x))), rel=0.001) # Floor dist_w_floor = Truncate( Logistic(loc=test_loc, s=test_s, scale=xscale), floor=xscale.denormalize_point(0.5), ) mix_w_floor = LogisticMixture( components=[ Truncate( # type: ignore Logistic(test_loc, s=test_s, scale=xscale), floor=xscale.denormalize_point(0.5), ) ], probs=[1.0], ) for x in np.linspace(0.01, 0.99, 8): assert dist_w_floor.ppf(x) == pytest.approx(float(mix_w_floor.ppf(x)), rel=0.001) assert dist_w_floor.ppf(x) == pytest.approx(float( ppf_through_cdf(dist_w_floor, x)), rel=0.001) # Ceiling dist_w_ceiling = Truncate( Logistic(loc=test_loc, s=test_s, scale=xscale), ceiling=xscale.denormalize_point(0.8), ) mix_w_ceiling = LogisticMixture( components=[ Truncate( # type: ignore Logistic(test_loc, s=test_s, scale=xscale), ceiling=xscale.denormalize_point(0.8), ) ], probs=[1.0], ) for x in np.linspace(0.01, 0.99, 8): assert dist_w_ceiling.ppf(x) == pytest.approx(float( mix_w_ceiling.ppf(x)), rel=0.001) assert dist_w_ceiling.ppf(x) == pytest.approx(float( ppf_through_cdf(dist_w_ceiling, x)), rel=0.001) # Floor and Ceiling dist_w_floor_and_ceiling = Truncate( Logistic(loc=test_loc, s=test_s, scale=xscale), floor=xscale.denormalize_point(0.2), ceiling=xscale.denormalize_point(0.8), ) mix_w_floor_and_ceiling = LogisticMixture( components=[ Truncate( # type: ignore Logistic(test_loc, s=test_s, scale=xscale), floor=xscale.denormalize_point(0.2), ceiling=xscale.denormalize_point(0.8), ) ], probs=[1.0], ) for x in np.linspace(0.01, 0.99, 8): assert dist_w_floor_and_ceiling.ppf(x) == pytest.approx(float( mix_w_floor_and_ceiling.ppf(x)), rel=0.001) assert dist_w_floor_and_ceiling.ppf(x) == pytest.approx(float( ppf_through_cdf(dist_w_floor_and_ceiling, x)), rel=0.001)
def test_cdf(): jax_dist = Logistic(loc=10, scale=1) original_dist = jax_dist.rv() for x in range(5, 15): assert jax_dist.cdf(x) == pytest.approx(original_dist.cdf(x), rel=0.1)