sigma  1.0.0
Loading...
Searching...
No Matches
exponents.ipp
1#pragma once
2#include <cmath>
4
5namespace sigma {
6
7template<typename T>
9 if(a.empty()) { return a; }
10 auto a_range = a.range();
11 auto lo = a_range.lower();
12 auto hi = a_range.upper();
13 if(lo < 0) { throw std::domain_error("Affine form has negative values."); }
14
15 auto sqrt_lower = std::sqrt(lo);
16 auto sqrt_upper = std::sqrt(hi);
17
18 auto sqrt_sum = sqrt_upper + sqrt_lower;
19 auto sqrt_diff = sqrt_upper - sqrt_lower;
20 auto sqrt_prod = sqrt_upper * sqrt_lower;
21
22 auto alpha = T(1.0) / (sqrt_sum);
23 auto zeta = sqrt_sum / T(8.0) + T(0.5) * sqrt_prod / sqrt_sum;
24 auto delta = sqrt_diff * sqrt_diff / (T(8.0) * sqrt_sum);
25
26 return a.apply_affine_transform(alpha, zeta, delta);
27}
28
29template<typename T>
31 auto a_range = a.range();
32 auto hi = a_range.upper();
33 auto lo = a_range.lower();
34 if(hi - lo == 0) { return Affine<T>(std::exp(lo)); }
35
36 T one(1.0);
37 T two(2.0);
38 auto exp_lower = std::exp(lo);
39 auto exp_upper = std::exp(hi);
40 auto alpha = (exp_upper - exp_lower) / (hi - lo);
41 auto log_alpha = std::log(alpha);
42 auto c_chord = exp_lower - alpha * lo;
43 auto c_tangent = alpha * (one - log_alpha);
44 auto zeta = (c_chord + c_tangent) / two;
45 auto delta = (c_chord - c_tangent) / two;
46 return a.apply_affine_transform(alpha, zeta, delta);
47}
48
49template<typename T>
51 auto a_range = a.range();
52 auto hi = a_range.upper();
53 auto lo = a_range.lower();
54 if(lo <= 0) {
55 throw std::domain_error("Affine form has non-positive values.");
56 }
57 if(hi - lo == 0) { return Affine<T>(std::log(lo)); }
58
59 auto log_lo = std::log(lo);
60 auto alpha = (std::log(hi) - log_lo) / (hi - lo);
61 auto xs = T(1.0) / alpha;
62 auto ys = alpha * (xs - lo) + log_lo;
63 auto log_xs = std::log(xs);
64 auto zeta = (log_xs + ys) / 2 - alpha * xs;
65 auto delta = (log_xs - ys) / 2;
66
67 return a.apply_affine_transform(alpha, zeta, delta);
68}
69
70template<typename T, typename U>
71Affine<T> pow(const Affine<T>& a, const U& exp) {
72 U zero(0);
73 if(a.empty()) { return a; }
74 if(exp == zero) { return Affine<T>(T(1.0)); }
75
76 // Handle cases where the affine form contains 0
77 if(a.contains(zero) && exp < zero) {
78 throw std::domain_error(
79 "Can not raise an affine form containing 0 to a negative power.");
80 } else if(a.contains(zero) && exp > zero) {
81 return Affine<T>(zero);
82 }
83
84 // Handle cases where affine form is strictly negative
85 if(a.range().upper() < zero) {
86 using clean_u_t = std::decay_t<U>;
87 if constexpr(std::is_floating_point_v<clean_u_t>) {
88 clean_u_t exp_int;
89 if(std::modf(exp, &exp_int) != zero) {
90 throw std::domain_error(
91 "Can not raise an affine form with negative values to a "
92 "non-integer power.");
93 }
94 }
95
96 auto abs_log = sigma::log(-a);
97 auto pow_abs = sigma::exp(T(exp) * abs_log);
98 const bool exp_is_even = static_cast<long long>(exp) % 2 == 0;
99 return exp_is_even ? pow_abs : -pow_abs;
100 }
101
102 // Handle cases where affine form is strictly positive
103 auto loga = sigma::log(a);
104 return sigma::exp(loga * exp);
105}
106
107} // namespace sigma
Defines the Affine class.
Implements affine arithmetic.
Definition affine.hpp:48
Affine apply_affine_transform(value_t alpha, value_t zeta, value_t delta) const
Applies an affine transformation to *this.
Definition affine.hpp:673
bool empty() const noexcept
Checks if this affine form is representing an empty interval.
Definition affine.hpp:313
interval_t range() const
Returns the interval represented by the affine form.
Definition affine.hpp:824
bool contains(value_t value) const
Checks if the interval represented by *this contains value.
Definition affine.hpp:841
value_t upper() const
Returns the upper bound of the interval.
Definition interval.hpp:157
value_t lower() const
Returns the lower bound of the interval.
Definition interval.hpp:146
The primary namespace for the sigma library.
Definition affine.hpp:12
Affine< T > exp(const Affine< T > &a)
Calculate the exponential of an affine form.
Definition exponents.ipp:30
Affine< T > pow(const Affine< T > &a, const U &exp)
Calculate the power of an affine form.
Definition exponents.ipp:71
Affine< T > log(const Affine< T > &a)
Calculate the natural logarithm of an affine form.
Definition exponents.ipp:50
Affine< T > sqrt(const Affine< T > &a)
Calculate the square root of an affine form.
Definition exponents.ipp:8