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
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]] {
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]] {
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;
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;
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
304
306 static constexpr index_type default_points = 20;
307
310
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.
std::vector< variable_type > weight_rate_list_
List of rates of weights of points.
variable_type max_point_
Maximum point in changed variable.
std::vector< variable_type > variable_rate_list_
List of rates of distances of points from the upper bound.
static constexpr index_type default_points
Default 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.
static constexpr auto default_max_point
Default maximum point in changed variable.
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.
logging_mixin(log_tag_view tag)
Constructor.
auto logger() const noexcept -> const num_collect::logging::logger &
Access to the logger.
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.