Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
ParamOptimizer.cpp
Go to the documentation of this file.
1#include "ParamOptimizer.h"
2
3ParamOptimizer::ParamOptimizer(std::shared_ptr<BlockAccessor> scope)
4 : scopes_{std::move(scope)} {}
5ParamOptimizer::ParamOptimizer(std::vector<std::shared_ptr<BlockAccessor>> scopes)
6 : scopes_{std::move(scopes)} {}
7
8void ParamOptimizer::set_value(const BlockName& block, const LhaID& id, scalar_t v) {
9 ops_.push_back(OpSetValue{block, id, v});
10}
11void ParamOptimizer::set_param(const BlockName& block, const LhaID& id, std::shared_ptr<Parameter> p) {
12 ops_.push_back(OpSetParam{block, id, std::move(p)});
13}
14void ParamOptimizer::remove(const BlockName& block, const LhaID& id) {
15 ops_.push_back(OpRemove{block, id});
16}
17
18void ParamOptimizer::commit(bool coalesce) {
19 if (ops_.empty()) return;
20
21 freeze_all_();
22
23 try {
24 const auto plan = coalesce ? coalesce_ops_() : ops_;
25
26 std::unordered_map<std::pair<std::string,std::string>, bool, BAKeyHash> existed;
27 existed.reserve(plan.size());
28 for (const auto& v : plan) {
29 std::visit([&](auto&& op){
30 auto blk = find_block_(op.block);
31 existed[{op.block, op.id.to_string()}] = blk->contains(op.id);
32 }, v);
33 }
34
35 std::unordered_set<std::shared_ptr<Block>> blocks_needing_notify;
36
37 for (const auto& v : plan) {
38 std::visit([&](auto&& op) {
39 using T = std::decay_t<decltype(op)>;
40 auto blk = find_block_(op.block);
41 const bool had = existed.at({op.block, op.id.to_string()});
42
43 if constexpr (std::is_same_v<T, OpSetValue>) {
44 if (had) {
45 blk->assign(op.id, op.value);
46 } else {
47 blk->store(op.id, std::make_shared<Parameter>(ParamId(blk->get_name(), op.id), op.value, 0., 0.));
48 blocks_needing_notify.insert(blk);
49 }
50 } else if constexpr (std::is_same_v<T, OpSetParam>) {
51 if (had) {
52 blk->assign(op.id, op.param);
53 } else {
54 blk->store(op.id, op.param);
55 blocks_needing_notify.insert(blk);
56 }
57 } else if constexpr (std::is_same_v<T, OpRemove>) {
58 if (!had) {
59 return;
60 }
61 blk->remove(op.id);
62 }
63 }, v);
64 }
65
66 for (const auto& blk : blocks_needing_notify) {
67 if (blk) blk->notifyObservers();
68 }
69
70 unfreeze_all_();
71 ops_.clear();
72 } catch (...) {
73 // A failed lookup or assignment must not leave the global parameter
74 // graph frozen, nor replay stale operations on the next likelihood call.
75 try {
76 unfreeze_all_();
77 } catch (...) {
78 // Preserve the original failure.
79 }
80 ops_.clear();
81 throw;
82 }
83}
84
85void ParamOptimizer::clear() { ops_.clear(); }
86
87std::vector<ParamOptimizer::Op> ParamOptimizer::coalesce_ops_() const {
88 std::unordered_map<std::pair<std::string,std::string>, std::size_t, BAKeyHash> last;
89 last.reserve(ops_.size());
90 for (std::size_t i = 0; i < ops_.size(); ++i) {
91 const auto& v = ops_[i];
92 std::visit([&](auto&& op){
93 last[{op.block, op.id.to_string()}] = i;
94 }, v);
95 }
96 std::vector<std::size_t> idx; idx.reserve(last.size());
97 for (auto& kv : last) idx.push_back(kv.second);
98 std::sort(idx.begin(), idx.end());
99 std::vector<Op> res; res.reserve(idx.size());
100 for (auto i : idx) res.push_back(ops_[i]);
101 return res;
102}
103
104std::shared_ptr<Block> ParamOptimizer::find_block_(const BlockName& name) const {
105 std::shared_ptr<Block> found;
106 bool ambiguous = false;
107 for (const auto& ba : scopes_) {
108 if (!ba) continue;
109 if (ba->contains(name)) {
110 auto b = ba->at(name);
111 if (!found) found = b;
112 else if (found.get() != b.get()) ambiguous = true;
113 }
114 }
115 if (!found) throw std::invalid_argument("ParamOptimizer: block not found: " + name);
116 if (ambiguous) throw std::invalid_argument("ParamOptimizer: block '" + name + "' was found in multiple scopes.");
117 return found;
118}
119
120void ParamOptimizer::freeze_all_() {
121 for (auto& ba : scopes_) if (ba) {
122 for (const auto& bn : ba->get_block_names()) ba->at(bn)->freeze();
123 }
124}
125void ParamOptimizer::unfreeze_all_() {
126 for (auto& ba : scopes_) if (ba) {
127 for (const auto& bn : ba->get_block_names()) ba->at(bn)->unfreeze();
128 }
129}
130
Defines the ParamOptimizer class to apply batched updates to parameters.
Block identifier with alias support.
Definition BlockName.h:59
void commit(bool coalesce=true)
Applies all queued operations.
void remove(const BlockName &block, const LhaID &id)
Queue a removal operation for a parameter.
void set_value(const BlockName &block, const LhaID &id, scalar_t v)
Queue a simple numerical value assignment for a parameter.
void clear()
Clears the pending operation queue without applying changes.
ParamOptimizer(std::shared_ptr< BlockAccessor > scope)
Constructs a ParamOptimizer operating on a single BlockAccessor scope.
void set_param(const BlockName &block, const LhaID &id, std::shared_ptr< Parameter > p)
Queue a full Parameter object assignment.
csl::Expr v
Definition sm.h:110
Hash specialization for SymbolId<Tag>.
Definition BlockName.h:353
double T(double x)
Wilson coefficient T(x).
Hash functor for (block name, parameter id string) pairs.
Represents an identifier of a LHA element, possibly containing several sub-ids.
Definition LhaID.h:56
Composite identifier for a single parameter.
Definition ParamID.h:57