Skip to content

Commit 18fc144

Browse files
committed
Merge branch 'main' into best_epoch
2 parents 6925fb3 + 58b40ed commit 18fc144

53 files changed

Lines changed: 1439 additions & 464 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/documentation.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
- name: Build Sphinx HTML
3131
run: |
3232
cd colibri/doc/sphinx
33-
make html
33+
make html SPHINXOPTS="-W --keep-going"
3434
- name: Upload Pages artifact
3535
uses: actions/upload-pages-artifact@v3
3636
with:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Documentation regarding the usage and installation is available at <https://hep-
3939
- Command-line scripts for common workflows (`colibri`, `evolve_fit`, etc.)
4040
- Integration with external PDF model repositories
4141

42-
<img src="./colibri-diagram-hessian.png" alt="colibri diagram" width="90%">
42+
<img src="./colibri-diagram-blackjax.png" alt="colibri diagram" width="90%">
4343

4444
---
4545

colibri-diagram-blackjax.png

160 KB
Loading

colibri-diagram-hessian.png

-142 KB
Binary file not shown.

colibri/analytic_fit.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,11 @@ def analytic_evidence_uniform_prior(sol_covmat, sol_mean, max_logl, a_vec, b_vec
8282
return log_evidence, log_occam_factor
8383

8484

85-
@check_pdf_model_is_linear
8685
def analytic_fit(
8786
central_covmat_index,
88-
_pred_data,
89-
pdf_model,
87+
forward_map,
9088
analytic_settings,
9189
prior_settings,
92-
FIT_XGRID,
9390
fast_kernel_arrays,
9491
):
9592
"""
@@ -106,40 +103,35 @@ def analytic_fit(
106103
central_covmat_index: commondata_utils.CentralCovmatIndex
107104
dataclass containing central values and covariance matrix.
108105
109-
_pred_data: @jax.jit CompiledFunction
110-
Prediction function for the fit.
111-
112-
pdf_model: pdf_model.PDFModel
113-
PDF model to fit.
106+
forward_map: @jax.jit CompiledFunction
107+
Forward map function for the fit.
114108
115109
analytic_settings: dict
116110
Settings for the analytic fit.
117111
118112
prior_settings: PriorSettings
119113
Settings for the prior.
120114
121-
FIT_XGRID: np.ndarray
122-
xgrid of the theory, computed by a production rule by taking
123-
the sorted union of the xgrids of the datasets entering the fit.
124-
125115
fast_kernel_arrays: tuple
126116
Tuple containing the fast kernel arrays.
127117
"""
118+
# Ensure that the PDF model is linear before running the fit.
119+
log.info("Checking that the PDF model is linear...")
120+
check_pdf_model_is_linear(forward_map, fast_kernel_arrays)
128121

129122
log.warning("The prior is assumed to be flat in the parameters.")
130123
log.warning(
131124
"Assuming that the prior is wide enough to fully cover the gaussian likelihood."
132125
)
133126

134-
parameters = pdf_model.param_names
135-
pred_and_pdf = pdf_model.pred_and_pdf_func(FIT_XGRID, forward_map=_pred_data)
127+
parameters = forward_map.param_names
136128

137129
# Precompute predictions for the basis of the model
138130
bases = jnp.identity(len(parameters))
139131
predictions = jnp.array(
140-
[pred_and_pdf(basis, fast_kernel_arrays)[0] for basis in bases]
132+
[forward_map(fast_kernel_arrays, basis)[0] for basis in bases]
141133
)
142-
intercept = pred_and_pdf(jnp.zeros(len(parameters)), fast_kernel_arrays)[0]
134+
intercept = forward_map(fast_kernel_arrays, jnp.zeros(len(parameters)))[0]
143135

144136
# Construct the analytic solution
145137
central_values = central_covmat_index.central_values

colibri/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"colibri.param_initialisation",
3333
"colibri.export_results",
3434
"colibri.closure_test",
35+
"colibri.forward_map",
3536
"reportengine.report",
3637
]
3738

colibri/bayes_prior.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,13 @@
55
cast_to_numpy,
66
get_full_posterior,
77
)
8-
from colibri.checks import check_pdf_models_equal
98
from colibri.core import BayesianPrior
109
import tensorflow_probability.substrates.jax as tfp
1110

1211
tfd = tfp.distributions
1312

1413

15-
@check_pdf_models_equal
16-
def bayesian_prior(prior_settings, pdf_model):
14+
def bayesian_prior(prior_settings, forward_map):
1715
"""
1816
Produces a prior transform function.
1917
@@ -22,6 +20,10 @@ def bayesian_prior(prior_settings, pdf_model):
2220
prior_settings: dict
2321
The settings for the prior transform.
2422
23+
forward_map: ForwardMap
24+
The forward map of the problem, used to determine parameter names and ordering.
25+
26+
2527
Returns
2628
-------
2729
prior_transform: @jax.jit CompiledFunction
@@ -31,8 +33,8 @@ def bayesian_prior(prior_settings, pdf_model):
3133
prior_specs = prior_settings.prior_distribution_specs
3234

3335
if "bounds" in prior_specs:
34-
# Use param names from the model to order bounds correctly
35-
param_names = pdf_model.param_names
36+
# Use param names from the forward map to order bounds correctly
37+
param_names = forward_map.param_names
3638
bounds_dict = prior_specs["bounds"]
3739
missing = [p for p in param_names if p not in bounds_dict]
3840
if missing:
@@ -45,8 +47,9 @@ def bayesian_prior(prior_settings, pdf_model):
4547

4648
elif "min_val" in prior_specs and "max_val" in prior_specs:
4749
# Global bounds for all parameters
48-
mins = prior_specs["min_val"]
49-
maxs = prior_specs["max_val"]
50+
n_params = len(forward_map.param_names)
51+
mins = jnp.array([float(prior_specs["min_val"])] * n_params)
52+
maxs = jnp.array([float(prior_specs["max_val"])] * n_params)
5053

5154
else:
5255
raise ValueError(

colibri/blackjax_fit.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from jax.scipy.special import logsumexp
1818
import tqdm
1919
import anesthetic
20+
import pandas as pd
2021

2122
from colibri.core import BlackJAXFit
2223
from colibri.export_results import export_bayes_results, write_replicas
@@ -37,7 +38,7 @@
3738

3839

3940
def blackjax_fit(
40-
pdf_model,
41+
forward_map,
4142
bayesian_prior,
4243
blackjax_settings,
4344
log_likelihood,
@@ -47,8 +48,8 @@ def blackjax_fit(
4748
4849
Parameters
4950
----------
50-
pdf_model: pdf_model.PDFModel
51-
The PDF model to fit.
51+
forward_map: ForwardMap
52+
The forward map whose ``param_names`` enumerate all fit parameters.
5253
5354
bayesian_prior: BayesianPrior, @jax.jit CompiledFunction
5455
The prior function for the model.
@@ -68,9 +69,9 @@ def blackjax_fit(
6869
log.info(f"Running fit with backend: {jax.default_backend()}")
6970

7071
# set the BlackJAX seed
71-
rng_key = jax.random.PRNGKey(blackjax_settings["seed"])
72+
rng_key = jax.random.PRNGKey(blackjax_settings["blackjax_seed"])
7273
log.info(f"BlackJAX initialisation seed: {rng_key}")
73-
n_dims = pdf_model.n_parameters
74+
n_dims = len(forward_map.param_names)
7475
n_live = blackjax_settings["n_live"]
7576
n_delete = int(blackjax_settings["delete_fraction"] * n_live)
7677

@@ -141,13 +142,17 @@ def one_step(carry, xs):
141142
data=final_states.particles,
142143
logL=final_states.loglikelihood,
143144
logL_birth=final_states.loglikelihood_birth,
144-
columns=pdf_model.param_names,
145+
columns=forward_map.param_names,
145146
)
146147
# write nested_samples.csv to blackjax_logs
147148
log_dir = blackjax_settings["log_dir"]
148149
os.makedirs(log_dir, exist_ok=True) # Create directory if it doesn't exist
149150
nested_samples.to_csv(log_dir + "/nested_samples.csv")
150151

152+
# Export resampled posterior samples
153+
posterior_df = pd.DataFrame(resampled_posterior, columns=forward_map.param_names)
154+
posterior_df.to_csv(os.path.join(log_dir, "posterior_samples.csv"), index=False)
155+
151156
# Compute bayesian metrics (similar to UltraNest)
152157
# Find maximum likelihood point
153158
max_ll_idx = jnp.argmax(final_states.loglikelihood)
@@ -167,7 +172,7 @@ def one_step(carry, xs):
167172
"logZ_err": logzs.std(),
168173
"ess": ess_value,
169174
},
170-
param_names=pdf_model.param_names,
175+
param_names=forward_map.param_names,
171176
resampled_posterior=resampled_posterior,
172177
full_posterior_samples=full_samples,
173178
bayesian_metrics={

colibri/checks.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,26 @@
77
from reportengine.checks import make_argcheck
88
import jax.numpy as jnp
99
import jax
10-
from colibri.theory_predictions import make_pred_data, fast_kernel_arrays
11-
12-
from colibri.utils import get_fit_path, get_pdf_model, pdf_models_equal
10+
from colibri.utils import get_fit_path, get_pdf_model
1311

1412

1513
@make_argcheck
16-
def check_pdf_models_equal(prior_settings, pdf_model, theoryid):
14+
def check_pdf_models_equal(prior_settings, forward_map, theoryid):
1715
"""
1816
Decorator that can be added to functions to check that the
1917
PDF model used as prior (eg when using prior_settings["type"] == "prior_from_gauss_posterior")
20-
matches the PDF model used in the current fit (pdf_model).
18+
matches the PDF model used in the current fit (via ``forward_map.pdf_param_names``).
2119
"""
2220

2321
if prior_settings.prior_distribution == "prior_from_gauss_posterior":
2422

2523
prior_fit = prior_settings.prior_distribution_specs["prior_fit"]
2624
prior_pdf_model = get_pdf_model(prior_fit)
2725

28-
if not pdf_models_equal(prior_pdf_model, pdf_model):
26+
if prior_pdf_model.param_names != list(forward_map.pdf_param_names):
2927
raise ValueError(
30-
f"PDF model {pdf_model} does not match prior settings {prior_pdf_model}"
28+
f"PDF param names from forward_map {list(forward_map.pdf_param_names)} "
29+
f"do not match prior PDF model param names {prior_pdf_model.param_names}"
3130
)
3231

3332
# load filter.yml runcard of the prior fit
@@ -41,19 +40,20 @@ def check_pdf_models_equal(prior_settings, pdf_model, theoryid):
4140
)
4241

4342

44-
@make_argcheck
45-
def check_pdf_model_is_linear(pdf_model, FIT_XGRID, data):
43+
def check_pdf_model_is_linear(forward_map, fast_kernel_arrays):
4644
"""
4745
Decorator that can be added to functions to check that the
4846
PDF model is linear.
47+
48+
Note that the FK arrays are taken as an argument rather than rebuilt here,
49+
so that they are guaranteed to be consistent with the
50+
``fill_fk_xgrid_with_zeros`` setting ``forward_map`` was built with.
4951
"""
5052

51-
pred_data = make_pred_data(data, FIT_XGRID)
52-
fk = fast_kernel_arrays(data, FIT_XGRID)
53+
fk = fast_kernel_arrays
5354

54-
parameters = pdf_model.param_names
55-
pred_and_pdf = pdf_model.pred_and_pdf_func(FIT_XGRID, forward_map=pred_data)
56-
intercept = pred_and_pdf(jnp.zeros(len(parameters)), fk)[0]
55+
parameters = forward_map.param_names
56+
intercept, _ = forward_map(fk, jnp.zeros(len(parameters)))
5757

5858
# Run the check for 10 random points in the parameter space
5959
for i in range(10):
@@ -65,16 +65,16 @@ def check_pdf_model_is_linear(pdf_model, FIT_XGRID, data):
6565

6666
# Test additivity
6767
add_check = jnp.isclose(
68-
pred_and_pdf(x1, fk)[0] + pred_and_pdf(x2, fk)[0],
69-
pred_and_pdf(x1 + x2, fk)[0] + intercept,
68+
forward_map(fk, x1)[0] + forward_map(fk, x2)[0],
69+
forward_map(fk, x1 + x2)[0] + intercept,
7070
)
7171

7272
# Test homogeneity
7373
c = jax.random.uniform(key, (1,))
7474

7575
homogeneity_check = jnp.isclose(
76-
c * (pred_and_pdf(x1, fk)[0] - intercept),
77-
pred_and_pdf(c * x1, fk)[0] - intercept,
76+
c * (forward_map(fk, x1)[0] - intercept),
77+
forward_map(fk, c * x1)[0] - intercept,
7878
)
7979

8080
if not add_check.all() or not homogeneity_check.all():

colibri/commondata_utils.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,7 @@ def level_0_commondata_tuple(
6767
Subset of flavour (evolution basis) indices to be used.
6868
6969
fill_fk_xgrid_with_zeros: bool, default is False
70-
If True, then the missing xgrid points in the FK table
71-
will be filled with zeros. This is useful when the FK table
72-
is needed as tensor of shape (Ndat, Nfl, Nfk_xgrid) with Nfk_xgrid and Nfl fixed
73-
for all datasets.
74-
70+
Must match the value used to build ``fast_kernel_arrays``.
7571
7672
Returns
7773
-------

0 commit comments

Comments
 (0)