Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
LikelihoodGradientJob.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * PB, Patrick Bos, Netherlands eScience Center, p.bos@esciencecenter.nl
5 *
6 * Copyright (c) 2021, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
14
21#include "RooMsgService.h"
22#include "RooMinimizer.h"
23
25#include "Minuit2/MnStrategy.h"
26
27#include <cmath>
28
29namespace RooFit {
30namespace TestStatistics {
31
32LikelihoodGradientJob::LikelihoodGradientJob(std::shared_ptr<RooAbsL> likelihood,
33 std::shared_ptr<WrapperCalculationCleanFlags> calculation_is_clean,
34 std::size_t N_dim, RooMinimizer *minimizer, SharedOffset offset)
35 : LikelihoodGradientWrapper(std::move(likelihood), std::move(calculation_is_clean), N_dim, minimizer,
36 std::move(offset)),
37 grad_(N_dim),
38 N_tasks_(N_dim)
39{
40 minuit_internal_x_.reserve(N_dim);
42}
43
45 const std::vector<ROOT::Fit::ParameterSettings> &parameter_settings)
46{
47 gradf_.SetInitialGradient(parameter_settings, grad_);
48}
49
55
57{
58 assert(istrat >= 0);
59 ROOT::Minuit2::MnStrategy strategy(static_cast<unsigned int>(istrat));
60
63 setNCycles(strategy.GradientNCycles());
64}
65
66void LikelihoodGradientJob::setStepTolerance(double step_tolerance) const
67{
68 gradf_.SetStepTolerance(step_tolerance);
69}
70
71void LikelihoodGradientJob::setGradTolerance(double grad_tolerance) const
72{
73 gradf_.SetGradTolerance(grad_tolerance);
74}
75
76void LikelihoodGradientJob::setNCycles(unsigned int ncycles) const
77{
78 gradf_.SetNCycles(ncycles);
79}
80
81void LikelihoodGradientJob::setErrorLevel(double error_level) const
82{
83 gradf_.SetErrorLevel(error_level);
84}
85
86///////////////////////////////////////////////////////////////////////////////
87/// Job overrides:
88
90{
91 run_derivator(task);
92}
93
94// SYNCHRONIZATION FROM WORKERS TO MASTER
95
97{
98 task_result_t task_result{id_, task, grad_[task]};
100 memcpy(message.data(), &task_result, sizeof(task_result_t));
101 get_manager()->messenger().send_from_worker_to_master(std::move(message));
102}
103
105{
106 auto result = message.data<task_result_t>();
107 grad_[result->task_id] = result->grad;
109 bool job_completed = (N_tasks_at_workers_ == 0);
110 return job_completed;
111}
112
113// END SYNCHRONIZATION FROM WORKERS TO MASTER
114
115// SYNCHRONIZATION FROM MASTER TO WORKERS (STATE)
116
118{
119 // TODO optimization: only send changed parameters (now sending all)
120 RooFit::MultiProcess::Message gradient_message(grad_.begin(), grad_.end());
121 RooFit::MultiProcess::Message minuit_internal_x_message(minuit_internal_x_.begin(), minuit_internal_x_.end());
122 double maxFCN = minimizer_->maxFCN();
123 double fcnOffset = minimizer_->fcnOffset();
124 ++state_id_;
125
127 // The function value known by the master corresponds to the previous
128 // offsets, so it cannot be used to skip the central-point evaluation on
129 // the workers in this update.
130 double fValAtX = std::numeric_limits<double>::quiet_NaN();
133 id_, state_id_, isCalculating_, maxFCN, fcnOffset, fValAtX, std::move(gradient_message),
134 std::move(minuit_internal_x_message), std::move(offsets_message));
136 } else {
138 fval_at_x_, std::move(gradient_message),
139 std::move(minuit_internal_x_message));
140 }
141}
142
148
150{
151 bool more;
152
154 assert(more);
156
157 if (more) {
158 auto maxFCN = get_manager()->messenger().receive_from_master_on_worker<double>(&more);
159 minimizer_->maxFCN() = maxFCN;
160 assert(more);
161
162 auto fcnOffset = get_manager()->messenger().receive_from_master_on_worker<double>(&more);
163 minimizer_->fcnOffset() = fcnOffset;
164 assert(more);
165
166 auto fValAtX = get_manager()->messenger().receive_from_master_on_worker<double>(&more);
167 assert(more);
168
169 auto gradient_message =
171 assert(more);
172 auto gradient_message_begin = gradient_message.data<ROOT::Minuit2::DerivatorElement>();
173 auto gradient_message_end =
174 gradient_message_begin + gradient_message.size() / sizeof(ROOT::Minuit2::DerivatorElement);
175 std::copy(gradient_message_begin, gradient_message_end, grad_.begin());
176
177 auto minuit_internal_x_message =
179 auto minuit_internal_x_message_begin = minuit_internal_x_message.data<double>();
180 auto minuit_internal_x_message_end =
181 minuit_internal_x_message_begin + minuit_internal_x_message.size() / sizeof(double);
182 std::copy(minuit_internal_x_message_begin, minuit_internal_x_message_end, minuit_internal_x_.begin());
183
184 if (more) {
185 // offsets also incoming
186 auto offsets_message =
188 assert(!more);
189 auto offsets_message_begin = offsets_message.data<ROOT::Math::KahanSum<double>>();
190 std::size_t N_offsets = offsets_message.size() / sizeof(ROOT::Math::KahanSum<double>);
191 shared_offset_.offsets().resize(N_offsets);
192 auto offsets_message_end = offsets_message_begin + N_offsets;
193 std::copy(offsets_message_begin, offsets_message_end, shared_offset_.offsets().begin());
194 }
195
196 // Since the gradient parallelization only support Minuit 2, we can do this cast
197 auto &minim = static_cast<ROOT::Minuit2::Minuit2Minimizer &>(*minimizer_->_minimizer);
198
199 // The master already knows the function value at the current point from
200 // the line search that Minuit just completed; pre-seeding the derivator's
201 // cache with it makes the SetupDifferentiate call below skip its full
202 // likelihood evaluation at the central point.
203 if (!std::isnan(fValAtX)) {
204 gradf_.PreseedFVal(fValAtX, {minuit_internal_x_.data(), static_cast<std::size_t>(minimizer_->getNPar())});
205 }
206
207 // note: the next call must stay after the (possible) update of the offset, because it
208 // calls the likelihood function, so the offset must be correct at this point
210 minimizer_->fitter()->Config().ParamsSettings());
211 }
212}
213
214// END SYNCHRONIZATION FROM MASTER TO WORKERS (STATE)
215
216///////////////////////////////////////////////////////////////////////////////
217/// Calculation stuff (mostly duplicates of RooGradMinimizerFcn code):
218
219void LikelihoodGradientJob::run_derivator(unsigned int i_component) const
220{
221 // Since the gradient parallelization only support Minuit 2, we can do this cast
222 auto &minim = static_cast<ROOT::Minuit2::Minuit2Minimizer &>(*minimizer_->_minimizer);
223
224 // Calculate the derivative etc for these parameters
225 grad_[i_component] = gradf_.FastPartialDerivative(minim.GetFCN(), minimizer_->fitter()->Config().ParamsSettings(),
226 i_component, grad_[i_component]);
227}
228
230{
231 if (get_manager()->process_manager().is_master()) {
232 isCalculating_ = true;
234
235 // master fills queue with tasks
236 for (std::size_t ix = 0; ix < N_tasks_; ++ix) {
237 MultiProcess::JobTask job_task{id_, state_id_, ix};
238 get_manager()->queue()->add(job_task);
239 }
241 // wait for task results back from workers to master (put into _grad)
243
244 calculation_is_clean_->gradient = true;
245 isCalculating_ = false;
247 }
248}
249
251{
252 if (get_manager()->process_manager().is_master()) {
253 if (!calculation_is_clean_->gradient) {
254 fval_at_x_ = std::numeric_limits<double>::quiet_NaN();
256 }
257
258 // put the results from _grad into *grad
259 for (Int_t ix = 0; ix < minimizer_->getNPar(); ++ix) {
260 grad[ix] = grad_[ix].derivative;
261 }
262 }
263}
264
265void LikelihoodGradientJob::fillGradientWithPrevResult(double *grad, double *previous_grad, double *previous_g2,
266 double *previous_gstep, double fValAtX)
267{
268 if (get_manager()->process_manager().is_master()) {
269 for (std::size_t i_component = 0; i_component < N_tasks_; ++i_component) {
270 grad_[i_component] = {previous_grad[i_component], previous_g2[i_component], previous_gstep[i_component]};
271 }
272
273 fval_at_x_ = fValAtX;
274
275 if (!calculation_is_clean_->gradient) {
278 }
282 }
283 }
284
285 // put the results from _grad into *grad
286 for (Int_t ix = 0; ix < minimizer_->getNPar(); ++ix) {
287 grad[ix] = grad_[ix].derivative;
288 previous_g2[ix] = grad_[ix].second_derivative;
289 previous_gstep[ix] = grad_[ix].step_size;
290 }
291 }
292}
293
294void LikelihoodGradientJob::updateMinuitInternalParameterValues(const std::vector<double> &minuit_internal_x)
295{
296 minuit_internal_x_ = minuit_internal_x;
297}
298
300{
301 return true;
302}
303
304} // namespace TestStatistics
305} // namespace RooFit
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
The Kahan summation is a compensated summation algorithm, which significantly reduces numerical error...
Definition Util.h:141
double ErrorDef() const
error definition
Minuit2Minimizer class implementing the ROOT::Math::Minimizer interface for Minuit2 minimization algo...
API class for defining four levels of strategies: low (0), medium (1), high (2), very high (>=3); act...
Definition MnStrategy.h:255
double GradientStepTolerance() const
Definition MnStrategy.h:265
double GradientTolerance() const
Definition MnStrategy.h:266
unsigned int GradientNCycles() const
Definition MnStrategy.h:264
void PreseedFVal(double fval, std::span< const double > cx)
Pre-seed the cache of the function value at the central point, so that a subsequent SetupDifferentiat...
void SetInitialGradient(std::span< const ROOT::Fit::ParameterSettings > parameters, std::vector< DerivatorElement > &gradient)
This function was not implemented as in Minuit2.
void SetNCycles(unsigned int value)
void SetupDifferentiate(unsigned int nDim, const FCNBase *function, const double *cx, std::span< const ROOT::Fit::ParameterSettings > parameters)
This function sets internal state based on input parameters.
DerivatorElement FastPartialDerivative(const FCNBase *function, std::span< const ROOT::Fit::ParameterSettings > parameters, unsigned int i_component, const DerivatorElement &previous)
static bool getTimingAnalysis()
Definition Config.cxx:87
std::size_t id_
Definition Job.h:46
std::size_t state_id_
Definition Job.h:47
JobManager * get_manager()
Get JobManager instance; create and activate if necessary.
Definition Job.cxx:112
void gather_worker_results()
Wait for all tasks to be retrieved for the current Job.
Definition Job.cxx:126
A contiguous byte buffer used as the unit of interprocess communication.
Definition Message.h:30
std::size_t size() const
Size of the message in bytes.
Definition Message.h:65
value_t receive_from_master_on_worker(bool *more=nullptr)
Definition Messenger.h:175
void send_from_worker_to_master(T &&item)
specialization that sends the final part of a message
Definition Messenger.h:190
void publish_from_master_to_workers(T &&item)
specialization that sends the final part of a message
Definition Messenger.h:145
static void start_timer(std::string section_name)
static void end_timer(std::string section_name)
virtual void add(JobTask job_task)=0
Enqueue a task.
bool usesMinuitInternalValues() override
Implement usesMinuitInternalValues to return true when you want Minuit to send this class Minuit-inte...
void update_state() override
Virtual function to update any necessary state on workers.
std::vector< ROOT::Minuit2::DerivatorElement > grad_
void updateMinuitInternalParameterValues(const std::vector< double > &minuit_internal_x) override
Minuit passes in parameter values that may not conform to RooFit internal standards (like applying ra...
void run_derivator(unsigned int i_component) const
Calculation stuff (mostly duplicates of RooGradMinimizerFcn code):
double fval_at_x_
Function value at minuit_internal_x_ as known by the master (NaN when unknown); broadcast to workers ...
void send_back_task_result_from_worker(std::size_t task) override
void synchronizeWithMinimizer(const ROOT::Math::MinimizerOptions &options) override
Synchronize minimizer settings with calculators in child classes.
LikelihoodGradientJob(std::shared_ptr< RooAbsL > likelihood, std::shared_ptr< WrapperCalculationCleanFlags > calculation_is_clean, std::size_t N_dim, RooMinimizer *minimizer, SharedOffset offset)
void setStepTolerance(double step_tolerance) const
void setGradTolerance(double grad_tolerance) const
bool receive_task_result_on_master(const RooFit::MultiProcess::Message &message) override
void evaluate_task(std::size_t task) override
Job overrides:
void synchronizeParameterSettingsImpl(const std::vector< ROOT::Fit::ParameterSettings > &parameter_settings) override
void fillGradientWithPrevResult(double *grad, double *previous_grad, double *previous_g2, double *previous_gstep, double fValAtX) override
Virtual base class for implementation of likelihood gradient calculation strategies.
std::shared_ptr< WrapperCalculationCleanFlags > calculation_is_clean_
Wrapper class around ROOT::Math::Minimizer that provides a seamless interface between the minimizer f...
auto fitter()
Return underlying ROOT fitter object.
std::unique_ptr< ROOT::Math::Minimizer > _minimizer
! pointer to used minimizer
double & fcnOffset() const
double & maxFCN()
int getNPar() const
OffsetVec & offsets()
std::size_t State
Definition types.h:23
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:73
combined job_object, state and task identifier type
Definition types.h:25