numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
de_finite_integrator.h
Go to the documentation of this file.
1/*
2 * Copyright 2021 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <cmath> // IWYU pragma: keep
23#include <cstddef>
24#include <type_traits>
25#include <vector>
26
32#include "num_collect/constants/half.h" // IWYU pragma: keep
33#include "num_collect/constants/one.h" // IWYU pragma: keep
34#include "num_collect/constants/pi.h" // IWYU pragma: keep
35#include "num_collect/constants/two.h" // IWYU pragma: keep
36#include "num_collect/constants/zero.h" // IWYU pragma: keep
41
43
46 logging::log_tag_view("num_collect::integration::de_finite_integrator");
47
54template <typename Signature>
56
64template <typename Result, base::concepts::real_scalar Variable>
65class de_finite_integrator<Result(Variable)> : public logging::logging_mixin {
66public:
68 using variable_type = std::decay_t<Variable>;
69
71 using result_type = std::decay_t<Result>;
72
76 de_finite_integrator() : logging::logging_mixin(de_finite_integrator_tag) {
77 calculate_coefficients();
78 }
79
89 template <base::concepts::invocable_as<result_type(variable_type)> Function>
90 [[nodiscard]] auto integrate(const Function& function, variable_type left,
91 variable_type right) const -> result_type {
92 using constants::pi;
93
94 const variable_type center =
95 constants::half<variable_type> * (left + right);
96 const variable_type width = right - left;
97
98 constexpr variable_type center_weight_rate =
99 pi<variable_type> / static_cast<variable_type>(4);
100 const variable_type center_weight = width * center_weight_rate;
102 sum += function(center) * center_weight;
103
104 for (index_type i = 0; i < points_; ++i) {
105 const variable_type variable_distance =
106 width * variable_rate_list_[static_cast<std::size_t>(i)];
107 const variable_type weight =
108 width * weight_rate_list_[static_cast<std::size_t>(i)];
109
110 const variable_type var_plus = right - variable_distance;
111 const variable_type var_minus = left + variable_distance;
112 const result_type function_values =
113 function(var_plus) + function(var_minus);
114 if (!base::isfinite(function_values)) [[unlikely]] {
115 NUM_COLLECT_LOG_WARNING(this->logger(),
116 "A function value was not a finite value. "
117 "Stopped numerical integration.");
118 break;
119 }
120 sum += function_values * weight;
121 }
122
123 return sum.sum() * interval_;
124 }
125
140 template <base::concepts::invocable_as<result_type(variable_type)>
141 LeftBoundaryFunction,
142 base::concepts::invocable_as<result_type(variable_type)>
143 RightBoundaryFunction>
144 [[nodiscard]] auto integrate(
145 const LeftBoundaryFunction& left_boundary_function,
146 const RightBoundaryFunction& right_boundary_function,
147 variable_type left, variable_type right) const -> result_type {
148 using constants::half;
149 using constants::pi;
150
151 const variable_type width = right - left;
152 const variable_type half_width = half<variable_type> * width;
153
154 constexpr variable_type center_weight_rate =
155 pi<variable_type> / static_cast<variable_type>(4);
156 const variable_type center_weight = width * center_weight_rate;
158 sum += left_boundary_function(half_width) * center_weight;
159
160 for (index_type i = 0; i < points_; ++i) {
161 const variable_type variable_distance =
162 width * variable_rate_list_[static_cast<std::size_t>(i)];
163 const variable_type weight =
164 width * weight_rate_list_[static_cast<std::size_t>(i)];
165
166 const result_type function_values =
167 left_boundary_function(variable_distance) +
168 right_boundary_function(-variable_distance);
169 if (!base::isfinite(function_values)) [[unlikely]] {
170 NUM_COLLECT_LOG_WARNING(this->logger(),
171 "A function value was not a finite value. "
172 "Stopped numerical integration.");
173 break;
174 }
175 sum += function_values * weight;
176 }
177
178 return sum.sum() * interval_;
179 }
180
190 template <base::concepts::invocable_as<result_type(variable_type)> Function>
191 [[nodiscard]] auto operator()(const Function& function, variable_type left,
192 variable_type right) const -> result_type {
193 return integrate(function, left, right);
194 }
195
210 template <base::concepts::invocable_as<result_type(variable_type)>
211 LeftBoundaryFunction,
212 base::concepts::invocable_as<result_type(variable_type)>
213 RightBoundaryFunction>
214 [[nodiscard]] auto operator()(
215 const LeftBoundaryFunction& left_boundary_function,
216 const RightBoundaryFunction& right_boundary_function,
217 variable_type left, variable_type right) const -> result_type {
218 return integrate(
219 left_boundary_function, right_boundary_function, left, right);
220 }
221
229 NUM_COLLECT_PRECONDITION(val > static_cast<variable_type>(0),
230 this->logger(), "Maximum point must be a positive value.");
231 max_point_ = val;
232 calculate_coefficients();
233 return *this;
234 }
235
243 NUM_COLLECT_PRECONDITION(val > 0, this->logger(),
244 "Number of points must be a positive integer.");
245 points_ = val;
246 calculate_coefficients();
247 return *this;
248 }
249
250private:
260 [[nodiscard]] static auto diff_coeff(
261 variable_type changed_var, variable_type half_width) -> variable_type {
262 const variable_type exp_value =
263 std::exp(-constants::pi<variable_type> * std::sinh(changed_var));
264 const variable_type exp_value_p1 =
267 half_width * std::cosh(changed_var) * exp_value /
268 (exp_value_p1 * exp_value_p1);
269 }
270
277 using constants::one;
278 using constants::pi;
279
280 variable_rate_list_.clear();
281 variable_rate_list_.reserve(static_cast<std::size_t>(points_));
282 weight_rate_list_.clear();
283 weight_rate_list_.reserve(static_cast<std::size_t>(points_));
284
285 interval_ = max_point_ / static_cast<variable_type>(points_);
286 for (index_type i = 1; i <= points_; ++i) {
287 const variable_type changed_variable =
288 interval_ * static_cast<variable_type>(i);
289 const variable_type exp_value =
290 std::exp(-pi<variable_type> * std::sinh(changed_variable));
291 const variable_type denominator = one<variable_type> + exp_value;
292 variable_rate_list_.push_back(exp_value / denominator);
293 weight_rate_list_.push_back(pi<variable_type> *
294 std::cosh(changed_variable) * exp_value /
295 (denominator * denominator));
296 }
297 }
298
300 static constexpr auto default_max_point = static_cast<variable_type>(4);
301
303 variable_type max_point_{default_max_point};
304
306 static constexpr index_type default_points = 20;
307
309 index_type points_{default_points};
310
312 variable_type interval_{};
313
315 std::vector<variable_type> variable_rate_list_{};
316
318 std::vector<variable_type> weight_rate_list_{};
319};
320
321} // namespace num_collect::integration
auto points(index_type val) -> de_finite_integrator &
Set number of points.
void calculate_coefficients()
Calculate coefficients for integration.
static auto diff_coeff(variable_type changed_var, variable_type half_width) -> variable_type
Calculate differential coefficient for change of variable.
auto operator()(const LeftBoundaryFunction &left_boundary_function, const RightBoundaryFunction &right_boundary_function, variable_type left, variable_type right) const -> result_type
Integrate a function.
auto max_point(variable_type val) -> de_finite_integrator &
Set maximum point in changed variable.
auto operator()(const Function &function, variable_type left, variable_type right) const -> result_type
Integrate a function.
auto integrate(const LeftBoundaryFunction &left_boundary_function, const RightBoundaryFunction &right_boundary_function, variable_type left, variable_type right) const -> result_type
Integrate a function.
auto integrate(const Function &function, variable_type left, variable_type right) const -> result_type
Integrate a function.
Class to perform numerical integration on finite range using double exponential rule.
Class of tags of logs without memory management.
Class to incorporate logging in algorithms.
Class to add numbers using Kahan summation kahan1965.
Definition kahan_adder.h:32
auto sum() const noexcept -> const T &
Get sum.
Definition of half.
Definition of index_type type.
Definition of invocable_as concept.
Definition of isfinite function.
Definition of kahan_adder class.
Definition of log_tag_view class.
Definition of macros for logging.
#define NUM_COLLECT_LOG_WARNING(LOGGER,...)
Write a warning log.
Definition of logging_mixin class.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
auto isfinite(const T &val) -> bool
Check whether a number is finite.
Definition isfinite.h:39
constexpr T pi
Value of pi, .
Definition pi.h:40
constexpr T two
Value 2.
Definition two.h:30
constexpr T half
Value 0.5.
Definition half.h:30
constexpr T one
Value 1.
Definition one.h:30
Namespace of numerical integration.
constexpr auto de_finite_integrator_tag
Tag of de_finite_integrator.
Definition of one.
Definition of pi.
Definition of NUM_COLLECT_PRECONDITION macro.
#define NUM_COLLECT_PRECONDITION(CONDITION,...)
Check whether a precondition is satisfied and throw an exception if not.
Definition of real_scalar concept.
Definition of two.
Definition of zero.