sigma  1.0.0
Loading...
Searching...
No Matches
setter.hpp
Go to the documentation of this file.
1#pragma once
2#include "sigma/uncertain.hpp"
3#include <vector>
4
8
9namespace sigma::detail_ {
10
19template<typename UncertainType>
20class Setter {
21public:
24
26 using uncertain_t = UncertainType;
27
29 using value_t = typename uncertain_t::value_t;
30
32 using dep_sd_t = typename uncertain_t::dep_sd_t;
33
35 using dep_sd_ptr = typename uncertain_t::dep_sd_ptr;
36
38 using deps_map_t = typename uncertain_t::deps_map_t;
39
46 Setter(uncertain_t& u) : m_x_(u) {}
47
54 void update_mean(value_t mean) { m_x_.m_mean_ = mean; }
55
63 // If the derivative is one, we don't need to do anything since the
64 // derivatives are unchanged
65 if(dxda == 1.0) return;
66 // If the derivative is zero, we can just clear the dependencies and set
67 // the standard deviation to zero
68 if(dxda == 0.0) {
69 m_x_.m_deps_.clear();
70 m_x_.m_sd_ = 0.0;
71 return;
72 }
73 // Update the derivatives in place
74 for(const auto& [dep, deriv] : m_x_.m_deps_) {
75 m_x_.m_deps_[dep] *= dxda;
76 }
77 // If the derivative is not negative one, we need to update the
78 // standard deviation as well.
79 if(dxda != -1.0) { m_x_.m_sd_ *= std::abs(dxda); }
80 }
81
90 void update_derivatives(const deps_map_t& deps, value_t dxda) {
91 // If the derivative is zero, we can skip the update since it won't
92 // change anything
93 if(dxda == 0.0) { return; }
94
95 // Update the map of contributions and their derivatives, keeping track
96 // of any that are reduced to zero and will need to be removed.
97 std::vector<dep_sd_ptr> zero_contributions{};
98 size_t n_updated = 0;
99 for(const auto& [dep, deriv] : deps) {
100 if(m_x_.m_deps_.count(dep)) {
101 m_x_.m_deps_[dep] += dxda * deriv;
102 if(m_x_.m_deps_[dep] == 0.0) {
103 zero_contributions.emplace_back(dep);
104 }
105 n_updated++;
106 } else {
107 m_x_.m_deps_.emplace(dep, dxda * deriv);
108 }
109 }
110
111 // If more than half of the existing dependencies are being updated,
112 // it's more efficient to update the derivatives and then recalculate
113 // the standard deviation from scratch. Otherwise, we can update the
114 // standard deviation in place by removing the contribution of the
115 // zeroed and updated dependencies and then adding the new contribution
116 // of the updated dependencies.
117 if(n_updated > (m_x_.m_deps_.size() / 2)) {
118 // Remove from m_deps_ any dependency that was reduced to zero.
119 for(const auto& dep : zero_contributions) {
120 m_x_.m_deps_.erase(dep);
121 }
122
123 // Recalculate the variance.
124 m_x_.m_sd_ = 0.0;
125 for(const auto& [dep, deriv] : m_x_.m_deps_) {
126 m_x_.m_sd_ += std::pow(*dep.get() * deriv, 2.0);
127 }
128 } else {
129 // Return to the variance so we can update the sum.
130 m_x_.m_sd_ = std::pow(m_x_.m_sd_, 2.0);
131
132 // Step through the updated dependencies and update the variance
133 // accordingly.
134 for(const auto& [dep, deriv] : deps) {
135 auto old_deriv = m_x_.m_deps_[dep] - dxda * deriv;
136 // As long as the dependency hasn't been reduce to zero, we need
137 // to add its contribution to the variance.
138 if(m_x_.m_deps_[dep] != 0.0) {
139 m_x_.m_sd_ += std::pow(*dep.get() * m_x_.m_deps_[dep], 2.0);
140 }
141 // As long as the dependency isn't new, we need to remove its
142 // previous contribution to the variance.
143 if(old_deriv != 0.0) {
144 m_x_.m_sd_ -= std::pow(*dep.get() * old_deriv, 2.0);
145 }
146 }
147
148 // Remove from m_deps_ any dependency that was reduced to zero.
149 for(const auto& dep : zero_contributions) {
150 m_x_.m_deps_.erase(dep);
151 }
152 }
153 // Take the square root of the variance to get the standard deviation.
154 m_x_.m_sd_ = std::sqrt(m_x_.m_sd_);
155 }
156
157private:
159 uncertain_t& m_x_;
160};
161
162} // namespace sigma::detail_
UncertainType uncertain_t
The numeric type of the variable.
Definition setter.hpp:26
void update_derivatives(value_t dxda)
Update of existing derivatives.
Definition setter.hpp:62
typename uncertain_t::dep_sd_ptr dep_sd_ptr
A pointer to a dependency of this variable.
Definition setter.hpp:35
void update_derivatives(const deps_map_t &deps, value_t dxda)
Update/addition of derivatives.
Definition setter.hpp:90
Setter(uncertain_t &u)
Construct a Setter for a variable.
Definition setter.hpp:46
Setter< UncertainType > my_t
Type of the instance.
Definition setter.hpp:23
void update_mean(value_t mean)
Update the mean of the wrapped variable.
Definition setter.hpp:54
typename uncertain_t::value_t value_t
The type of the values of the variable.
Definition setter.hpp:29
typename uncertain_t::dep_sd_t dep_sd_t
The type of a standard deviation that this instance depends on.
Definition setter.hpp:32
typename uncertain_t::deps_map_t deps_map_t
The type of the map holding the variable's dependencies.
Definition setter.hpp:38
The namespace that contains the implementation details of the library.
Definition operation_common.hpp:10
Defines the Uncertain class.