From 287dd8482f09072ffb04bbc482e3b1b253b3e455 Mon Sep 17 00:00:00 2001 From: Zihao Xu Date: Wed, 28 Feb 2024 20:42:23 -0600 Subject: [PATCH 1/6] add functions --- appletree/parameter.py | 15 +++++++++------ appletree/utils.py | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/appletree/parameter.py b/appletree/parameter.py index dd52e91a..b867ced9 100644 --- a/appletree/parameter.py +++ b/appletree/parameter.py @@ -4,6 +4,7 @@ import numpy as np from appletree.randgen import TwoHalfNorm +from appletree.utils import errors_to_two_half_norm_sigmas class Parameter: @@ -81,10 +82,12 @@ def sample_prior(self): val = np.random.normal(**kwargs) self._parameter_dict[par_name] = np.clip(val, *setting["allowed_range"]) elif prior_type == "twohalfnorm": + sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], + args["sigma_neg"]]) kwargs = { "mu": args["mu"], - "sigma_pos": args["sigma_pos"], - "sigma_neg": args["sigma_neg"], + "sigma_pos": sigmas[0], + "sigma_neg": sigmas[1], } val = TwoHalfNorm.rvs(**kwargs) self._parameter_dict[par_name] = np.clip(val, *setting["allowed_range"]) @@ -150,14 +153,14 @@ def log_prior(self): std = args["std"] log_prior += -((val - mean) ** 2) / 2 / std**2 elif prior_type == "twohalfnorm": + sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], + args["sigma_neg"]]) mu = args["mu"] - sigma_pos = args["sigma_pos"] - sigma_neg = args["sigma_neg"] log_prior += TwoHalfNorm.logpdf( x=val, mu=mu, - sigma_pos=sigma_pos, - sigma_neg=sigma_neg, + sigma_pos=sigmas[0], + sigma_neg=sigmas[1], ) elif prior_type == "free": pass diff --git a/appletree/utils.py b/appletree/utils.py index 2d2ea179..b731148e 100644 --- a/appletree/utils.py +++ b/appletree/utils.py @@ -10,6 +10,9 @@ import matplotlib as mpl from matplotlib.patches import Rectangle from matplotlib import pyplot as plt +from scipy.special import erf +from scipy.optimize import root +from scipy.stats import chi2 import GOFevaluation from appletree.share import _cached_configs @@ -576,3 +579,14 @@ def check_unused_configs(): unused_configs = set(_cached_configs.keys()) - _cached_configs.accessed_keys if unused_configs: warn(f"Detected unused configs: {unused_configs}, you might set the configs incorrectly.") + + +def errors_to_two_half_norm_sigmas(errors): + """This function solves the sigmas for a two-half-norm distribution, + such that the 16 and 84 percentile corresponds to the given errors.""" + def _to_solve(x, errors, p): + return [x[0] / (x[0] + x[1]) * (1 - erf(errors[0] / x[0] / np.sqrt(2))) - p / 2, + x[1] / (x[0] + x[1]) * (1 - erf(errors[1] / x[1] / np.sqrt(2))) - p / 2] + res = root(_to_solve, errors, args=(errors, 1 - chi2.cdf(1, 1))) + assert res.success, f"Cannot solve sigmas of TwoHalfNorm for errors {errors}!" + return res.x From 60dcd037f3ab403a56a0acae99c48fa99e47b646 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 02:57:38 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- appletree/parameter.py | 6 ++---- appletree/utils.py | 12 ++++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/appletree/parameter.py b/appletree/parameter.py index b867ced9..79df48a4 100644 --- a/appletree/parameter.py +++ b/appletree/parameter.py @@ -82,8 +82,7 @@ def sample_prior(self): val = np.random.normal(**kwargs) self._parameter_dict[par_name] = np.clip(val, *setting["allowed_range"]) elif prior_type == "twohalfnorm": - sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], - args["sigma_neg"]]) + sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], args["sigma_neg"]]) kwargs = { "mu": args["mu"], "sigma_pos": sigmas[0], @@ -153,8 +152,7 @@ def log_prior(self): std = args["std"] log_prior += -((val - mean) ** 2) / 2 / std**2 elif prior_type == "twohalfnorm": - sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], - args["sigma_neg"]]) + sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], args["sigma_neg"]]) mu = args["mu"] log_prior += TwoHalfNorm.logpdf( x=val, diff --git a/appletree/utils.py b/appletree/utils.py index b731148e..75fe99b9 100644 --- a/appletree/utils.py +++ b/appletree/utils.py @@ -582,11 +582,15 @@ def check_unused_configs(): def errors_to_two_half_norm_sigmas(errors): - """This function solves the sigmas for a two-half-norm distribution, - such that the 16 and 84 percentile corresponds to the given errors.""" + """This function solves the sigmas for a two-half-norm distribution, such that the 16 and 84 + percentile corresponds to the given errors.""" + def _to_solve(x, errors, p): - return [x[0] / (x[0] + x[1]) * (1 - erf(errors[0] / x[0] / np.sqrt(2))) - p / 2, - x[1] / (x[0] + x[1]) * (1 - erf(errors[1] / x[1] / np.sqrt(2))) - p / 2] + return [ + x[0] / (x[0] + x[1]) * (1 - erf(errors[0] / x[0] / np.sqrt(2))) - p / 2, + x[1] / (x[0] + x[1]) * (1 - erf(errors[1] / x[1] / np.sqrt(2))) - p / 2, + ] + res = root(_to_solve, errors, args=(errors, 1 - chi2.cdf(1, 1))) assert res.success, f"Cannot solve sigmas of TwoHalfNorm for errors {errors}!" return res.x From bcdf16699e70a4e9a0786a331016e7d7a195921c Mon Sep 17 00:00:00 2001 From: Zihao Xu Date: Mon, 4 Mar 2024 10:27:30 -0600 Subject: [PATCH 3/6] more documentation --- appletree/parameter.py | 4 ++++ appletree/utils.py | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/appletree/parameter.py b/appletree/parameter.py index 79df48a4..19402b60 100644 --- a/appletree/parameter.py +++ b/appletree/parameter.py @@ -82,6 +82,8 @@ def sample_prior(self): val = np.random.normal(**kwargs) self._parameter_dict[par_name] = np.clip(val, *setting["allowed_range"]) elif prior_type == "twohalfnorm": + # We need to convert errors to sigmas + # See the docstring of errors_to_two_half_norm_sigmas for details sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], args["sigma_neg"]]) kwargs = { "mu": args["mu"], @@ -152,6 +154,8 @@ def log_prior(self): std = args["std"] log_prior += -((val - mean) ** 2) / 2 / std**2 elif prior_type == "twohalfnorm": + # We need to convert errors to sigmas + # See the docstring of errors_to_two_half_norm_sigmas for details sigmas = errors_to_two_half_norm_sigmas([args["sigma_pos"], args["sigma_neg"]]) mu = args["mu"] log_prior += TwoHalfNorm.logpdf( diff --git a/appletree/utils.py b/appletree/utils.py index 75fe99b9..5809d0a7 100644 --- a/appletree/utils.py +++ b/appletree/utils.py @@ -583,7 +583,16 @@ def check_unused_configs(): def errors_to_two_half_norm_sigmas(errors): """This function solves the sigmas for a two-half-norm distribution, such that the 16 and 84 - percentile corresponds to the given errors.""" + percentile corresponds to the given errors. + + In the two-half-norm distribution, the positive and negative errors are assumed to be + the std of the glued normal distributions. While we interpret the 16 and 84 percentile as + the input errors, thus we need to solve the sigmas for the two-half-norm distribution. The solution + is determined by the following conditions: + - The 16 percentile of the two-half-norm distribution should be the negative error. + - The 84 percentile of the two-half-norm distribution should be the positive error. + - The mode of the two-half-norm distribution should be 0. + """ def _to_solve(x, errors, p): return [ From ceb2a3867bc15d6ade3dc48d65bb3f282b18f6e3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 16:27:53 +0000 Subject: [PATCH 4/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- appletree/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/appletree/utils.py b/appletree/utils.py index 5809d0a7..4a11b6d1 100644 --- a/appletree/utils.py +++ b/appletree/utils.py @@ -592,6 +592,7 @@ def errors_to_two_half_norm_sigmas(errors): - The 16 percentile of the two-half-norm distribution should be the negative error. - The 84 percentile of the two-half-norm distribution should be the positive error. - The mode of the two-half-norm distribution should be 0. + """ def _to_solve(x, errors, p): From e897b8e491ffd7838009c912f34baaa6569c2ff9 Mon Sep 17 00:00:00 2001 From: Zihao Xu Date: Mon, 4 Mar 2024 21:36:56 -0500 Subject: [PATCH 5/6] code style change --- appletree/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appletree/utils.py b/appletree/utils.py index 4a11b6d1..28d4d969 100644 --- a/appletree/utils.py +++ b/appletree/utils.py @@ -587,8 +587,8 @@ def errors_to_two_half_norm_sigmas(errors): In the two-half-norm distribution, the positive and negative errors are assumed to be the std of the glued normal distributions. While we interpret the 16 and 84 percentile as - the input errors, thus we need to solve the sigmas for the two-half-norm distribution. The solution - is determined by the following conditions: + the input errors, thus we need to solve the sigmas for the two-half-norm distribution. + The solution is determined by the following conditions: - The 16 percentile of the two-half-norm distribution should be the negative error. - The 84 percentile of the two-half-norm distribution should be the positive error. - The mode of the two-half-norm distribution should be 0. From 6796dc0cb9efcc09c84069c9b5ea2d3ac179847a Mon Sep 17 00:00:00 2001 From: dachengx Date: Tue, 5 Mar 2024 23:18:22 +0800 Subject: [PATCH 6/6] Export errors_to_two_half_norm_sigmas --- appletree/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appletree/utils.py b/appletree/utils.py index 7e356178..c5340ef6 100644 --- a/appletree/utils.py +++ b/appletree/utils.py @@ -605,6 +605,7 @@ def cum_integrate_midpoint(x, y): return x_mid, np.cumsum(dx * y_mid) +@export def check_unused_configs(): """Check if there are unused configs.""" unused_configs = set(_cached_configs.keys()) - _cached_configs.accessed_keys @@ -612,6 +613,7 @@ def check_unused_configs(): warn(f"Detected unused configs: {unused_configs}, you might set the configs incorrectly.") +@export def errors_to_two_half_norm_sigmas(errors): """This function solves the sigmas for a two-half-norm distribution, such that the 16 and 84 percentile corresponds to the given errors.