20namespace detail::theta_jet_detail
23template <Complex C>
class Sum {
25 explicit Sum(C
const& zero) : sum_(zero), correction_(zero) {}
26 void add(C
const& value)
28 C
const corrected =
value - correction_;
29 C
const next = sum_ + corrected;
30 correction_ = (next - sum_) - corrected;
33 C
value()
const {
return sum_; }
40template <ThetaReal R> std::int64_t integral_value(R
const&
value)
43 if constexpr (std::same_as<R, mpreal>)
44 return mpfr_get_sj(
value.native_handle(), MPFR_RNDN);
47 return static_cast<std::int64_t
>(
value);
49template <ThetaReal R> std::size_t term_count(R
const& t, std::size_t max_terms)
51 R
const one = scalar_at_precision<R>(1,
precision_of(t));
54 if (count > scalar_at_precision<R>(max_terms,
precision_of(t)))
55 throw std::runtime_error(
"theta jet exhausted its term budget");
56 return static_cast<std::size_t
>(integral_value(count));
61template <ThetaReal R> complex<R> phase_cycles(R
const& cycles)
63 R
const twice = 2 * cycles;
66template <ThetaReal R> complex<R> phase_product(R
const& a, R
const& b)
69 auto phase = phase_cycles(
product);
72 if (residual != 0) phase *= phase_cycles(residual);
75template <ThetaReal R> complex<R> phase_quotient(R
const& a, R
const& y, R
const& t)
77 R
const quotient = y / t, residual =
math::fma(-quotient, t, y);
78 auto phase = phase_product(a, quotient);
79 if (residual != 0) phase *= phase_product(a, residual / t);
87template <ThetaReal R> R fourier_exponent(R
const& n,
bool half_series, R
const& t, R
const& y, R
const&
pi)
89 if (!half_series)
return -
pi * (n + 1) * (n * t + (t + 2 * y));
91 if (n == 0)
return -
pi * edge;
92 return -
pi * (n * (n * t + (t + 2 * y)) + edge);
96template <Complex C> theta_jet_result<C> theta1_reduced(C u, make_real_t<C> t,
bool gaussian, std::size_t max_terms)
98 using Real = make_real_t<C>;
101 Real const zero = scalar_at_precision<Real>(0,
p), one = scalar_at_precision<Real>(1,
p);
102 Real const half = one / 2;
103 Complex const zero_complex(zero, zero);
105 auto const terms = term_count(t, max_terms);
106 Real const x = u.real(), y = u.imag();
107 theta_jet_result<C> result{{zero_complex, zero_complex, zero_complex}, zero};
113 std::array<Sum<C>, 3> sums{Sum<C>(zero_complex), Sum<C>(zero_complex), Sum<C>(zero_complex)};
115 Real a = half, n_real = zero;
116 for (
unsigned n = 0; n < terms; ++n, a += one, n_real += one)
118 Real const sign = n % 2 ? -one : one;
125 Real const fall = (n_real * (n_real + one)) * t *
pi;
127 auto const phase = phase_product(a, x);
129 value =
Real{2} * sign * weight *
Complex(phase.imag() * ch, phase.real() * sh);
130 first =
Real{2} * sign * omega * weight *
Complex(phase.real() * ch, -phase.imag() * sh);
134 Real const ep = fourier_exponent(n_real,
true, t, y,
pi),
135 em = fourier_exponent(n_real,
true, t, -y,
pi);
136 auto const phase = phase_product(a, x);
140 first = sign * omega * (positive + negative);
142 second = -omega * omega *
value;
146 Real const omega =
Real{2} *
pi * a / t, fall = n_real * (n_real + one);
151 if (weight == zero_complex)
continue;
152 auto const phase = phase_quotient(a, y, t);
154 difference =
Real{2} * weight *
Complex(sh * phase.real(), ch * phase.imag());
155 sum =
Real{2} * weight *
Complex(ch * phase.real(), sh * phase.imag());
157 value = sign * difference;
158 first = sign * (-
center * difference + omega *
sum);
161 second = sign * (
center * (
center * difference) + omega * (omega * difference) -
167 phase_quotient(a - x, y, t);
169 phase_quotient(-x - a, y, t);
172 auto derivative = [&](
Complex const& term,
Complex const& displacement,
unsigned order) {
173 if (term == zero_complex)
return zero_complex;
175 return order == 1 ? slope * term : slope * (slope * term) - (Real{2} *
pi * term) / t;
177 value = sign * (positive - negative);
178 first = sign * (derivative(positive, u - a, 1) - derivative(negative, u + a, 1));
179 second = sign * (derivative(positive, u - a, 2) - derivative(negative, u + a, 2));
186 for (
unsigned r = 0; r < 3; ++r)
187 result.derivative[r] = sums[r].value();
188 if (u == zero_complex)
190 result.derivative[0] = zero_complex;
191 result.derivative[2] = zero_complex;
198template <Complex C> theta_jet_result<C> even_gaussian(
unsigned kind, C u, make_real_t<C> t, std::size_t max_terms)
200 using R = make_real_t<C>;
202 R
const zero = scalar_at_precision<R>(0,
p), one = scalar_at_precision<R>(1,
p);
204 C
const cz(zero, zero);
206 R
const sx = x / root_t, sy = u.imag() / root_t;
207 theta_jet_result<C> result{{cz, cz, cz},
pi * (sy * sy - sx * sx) -
math::log(t) / 2};
208 std::array<Sum<C>, 3> sums{Sum<C>(cz), Sum<C>(cz), Sum<C>(cz)};
209 auto add = [&](R
const&
center, R
const& exponent, R
const& sign) {
211 if (weight == zero)
return;
212 C
const term = sign * weight * phase_quotient(center - x, u.imag(), t);
213 C
const slope = -2 *
pi * ((u -
center) / t);
215 sums[1].add(slope * term);
216 sums[2].add(slope * (slope * term) - (2 *
pi * term) / t);
218 add(zero, zero, one);
219 auto const terms = term_count(t, max_terms);
221 for (
unsigned n = 1; n <= terms; ++n, a += one)
223 R
const sign = kind == 2 && n % 2 ? -one : one;
224 add(a, -
pi * a * ((a - 2 * x) / t), sign);
225 add(-a, -
pi * a * ((a + 2 * x) / t), sign);
227 for (
unsigned d = 0; d < 3; ++d)
228 result.derivative[d] = sums[d].value();
234template <Complex C> theta_jet_result<C> theta4_gaussian(C u, make_real_t<C> t, std::size_t max_terms)
236 using R = make_real_t<C>;
238 R
const zero = scalar_at_precision<R>(0,
p), one = scalar_at_precision<R>(1,
p);
239 R
const pi = R(4) *
math::atan(one), sign = u.imag() > zero ? -one : one;
240 C
const shifted(u.real(), u.imag() + sign * (t / 2));
241 auto result = theta1_reduced(shifted, t,
true, max_terms);
242 C
const slope(zero, sign *
pi);
243 result.derivative[2] += R(2) * slope * result.derivative[1] + slope * slope * result.derivative[0];
244 result.derivative[1] += slope * result.derivative[0];
245 C
const phase = C(zero, -sign) * phase_product(sign / 2, u.real());
246 for (
auto& d : result.derivative)
248 result.log_scale -=
pi * (t / 4 + sign * u.imag());
249 if (u == C(zero, zero)) result.derivative[1] = C(zero, zero);
253template <Complex C> theta_jet_result<C> even_reduced(
unsigned kind, C u, make_real_t<C> t, std::size_t max_terms)
255 using Real = make_real_t<C>;
258 Real const zero = scalar_at_precision<Real>(0,
p), one = scalar_at_precision<Real>(1,
p);
259 Real const half = one / 2;
260 Complex const zero_complex(zero, zero);
262 theta_jet_result<C> result{{zero_complex, zero_complex, zero_complex}, zero};
263 bool const half_series = kind == 2;
264 result.log_scale = half_series ? -
pi * (t /
Real{4} -
math::abs(u.imag())) : zero;
265 std::array<Sum<C>, 3> sums{Sum<C>(zero_complex), Sum<C>(zero_complex), Sum<C>(zero_complex)};
266 if (!half_series) sums[0].add(
Complex(one, zero));
267 auto const terms = term_count(t, max_terms);
268 Real a = half_series ? half : one, n_real = zero;
269 for (
unsigned n = 0; n < terms; ++n, a += one, n_real += one)
272 Real const sign = kind == 4 && n % 2 == 0 ? -one : one;
276 Real const fall = (half_series ? n_real * (n_real + one) : a * a) * t *
pi,
277 shift = half_series ?
pi * math::
abs(u.
imag()) : zero;
279 auto const phase = phase_product(a, u.real());
281 value = weight *
Complex(phase.real() * ch, -phase.imag() * sh);
282 first = -weight * omega *
Complex(phase.imag() * ch, phase.real() * sh);
286 Real const ep = fourier_exponent(n_real, half_series, t, u.imag(),
pi),
287 em = fourier_exponent(n_real, half_series, t, -u.imag(),
pi);
288 auto const phase = phase_product(a, u.real());
291 value = sign * (aterm + bterm);
292 first =
Complex(zero, sign * omega) * (aterm - bterm);
296 sums[2].add(-omega * omega *
value);
298 for (
unsigned d = 0; d < 3; ++d)
299 result.derivative[d] = sums[d].value();
300 if (kind == 4 && u.real() == zero &&
math::abs(u.imag()) == t /
Real{2})
301 result.derivative[0] = zero_complex;
305template <Complex C> theta_jet_result<C> theta1(C u, make_real_t<C> t,
unsigned kind, std::size_t max_terms)
307 using Real = make_real_t<C>;
310 Real const zero = scalar_at_precision<Real>(0,
p), one = scalar_at_precision<Real>(1,
p);
311 Real const half = one / 2;
313 Real const eps = numeric_limits<Real>::epsilon(t);
314 Real const limit = std::min(one / (Real{16} * eps),
Real(std::numeric_limits<std::int64_t>::max() / 4));
317 throw std::overflow_error(
"theta argument reduction exceeds scalar precision");
318 auto nearest_integer = [&](
Real const&
value) {
320 return value - lower < half ? lower : lower + one;
322 Real const nr = nearest_integer(u.real());
329 else if (ry < -t / 2)
332 auto const n = integral_value(nr), m = integral_value(mr);
333 Complex const reduced(u.real() - nr, ry), cz(zero, zero);
339 unsigned centered_kind = kind;
343 bool const positive = reduced.real() > zero;
344 centered.real(reduced.real() + (positive ? -half : half));
345 centered_kind = kind < 3 ? 3 - kind : 7 - kind;
346 negate = (kind == 1 && !positive) || (kind == 2 && positive);
348 bool const taylor = centered_kind > 1 && t < one && centered != cz &&
350 Complex const at = taylor ? cz : centered;
351 auto result = centered_kind == 1 ? theta1_reduced(at, t, t < one, max_terms)
352 : t < one ? (centered_kind == 4 ? theta4_gaussian(at, t, max_terms)
353 : even_gaussian(centered_kind, at, t, max_terms))
354 : even_reduced(centered_kind, at, t, max_terms);
355 if (centered_kind > 1 && at == cz) result.derivative[1] = cz;
358 result.derivative[0] += result.derivative[2] * centered * centered /
Real(2);
359 result.derivative[1] = result.derivative[2] * centered;
362 for (
auto& d : result.derivative)
365 Complex const slope(zero, -Real{2} *
pi * mr);
366 result.derivative[2] +=
Real{2} * slope * result.derivative[1] + slope * slope * result.derivative[0];
367 result.derivative[1] += slope * result.derivative[0];
368 auto const parity = kind == 1 ? n + m : kind == 2 ? n : kind == 4 ? m : 0;
369 Complex phase = phase_product(-mr, reduced.real());
370 if (parity % 2) phase = -phase;
371 for (
auto& d : result.derivative)
373 result.log_scale =
math::fma(
pi * mr, mr * t + Real{2} * reduced.imag(), result.log_scale);
376template <Complex C> theta_jet_result<C> evaluate(
unsigned kind, C u, make_real_t<C> t, std::size_t max_terms)
378 using Real = make_real_t<C>;
380 Real const zero = scalar_at_precision<Real>(0,
p);
381 if (kind < 1 || kind > 4 || !finite(u) || !
uni20::isfinite(t) || !(t > zero))
382 throw std::invalid_argument(
"theta requires kind 1..4, finite u, and finite t>0");
383 auto result = theta1(u, t, kind, max_terms);
384 if (!
uni20::isfinite(result.log_scale))
throw std::overflow_error(
"theta logarithmic scale exceeds precision");
385 for (
auto d : result.derivative)
386 if (!finite(d)) throw
std::overflow_error(
"theta scaled derivatives exceed precision");
401 requires detail::ThetaReal<make_real_t<C>>
405 if (kind < 1 || kind > 4 || max_terms == 0 ||
p.is_exact() ||
precision_of(u) !=
p)
406 throw std::invalid_argument(
"theta jet requires kind 1..4, a positive budget and matching finite precision");
407 if (!detail::theta_jet_detail::finite(u) || !
uni20::isfinite(t) || !(t > 0))
408 throw std::invalid_argument(
"theta jet requires finite u and finite t>0");
410 if constexpr (std::same_as<make_real_t<C>,
mpreal>)
412 if (
p.bit_count() > std::numeric_limits<Precision::bit_count_type>::max() - 32)
413 throw std::overflow_error(
"theta jet guard precision exceeds supported range");
415 auto result = detail::theta_jet_detail::evaluate(kind, u.at(work), t.at(work), max_terms);
416 for (
auto& d : result.derivative)
419 if (!detail::theta_jet_detail::finite(d))
throw std::overflow_error(
"theta jet derivative exceeds result range");
421 result.log_scale = result.log_scale.at(
p);
422 if (!
uni20::isfinite(result.log_scale))
throw std::overflow_error(
"theta jet scale exceeds result range");
427 return detail::theta_jet_detail::evaluate(kind, u, t, max_terms);
434 requires detail::ThetaReal<make_real_t<C>>
436 std::size_t max_terms = 4096)
438 if (
p.is_exact())
throw std::invalid_argument(
"theta jet requires explicit finite precision");
450 requires detail::ThetaReal<make_real_t<C>>
453 if (da > 2 || db > 2)
throw std::invalid_argument(
"theta derivative order must be 0..2");
458 throw std::invalid_argument(
"theta ratio requires matching finite precision");
460 !detail::theta_jet_detail::finite(a.
derivative[da]) || !detail::theta_jet_detail::finite(b.
derivative[db]))
461 throw std::invalid_argument(
"theta ratio requires finite scales and selected derivatives");
462 R
const zero = scalar_at_precision<R>(0,
p), one = scalar_at_precision<R>(1,
p);
464 if (!(denominator > zero))
throw std::domain_error(
"theta ratio has a zero denominator");
465 if (numerator == zero)
return C(zero, zero);
470 if (detail::theta_jet_detail::finite(direct) &&
math::abs(direct) > zero)
return direct;
472 auto log_norm_and_phase = [&](C
const& z) -> std::pair<R, C> {
476 C
const scaled = z /
scale;
480 auto const [ln_a, phase_a] = log_norm_and_phase(a.
derivative[da]);
481 auto const [ln_b, phase_b] = log_norm_and_phase(b.
derivative[db]);
484 throw std::overflow_error(
"theta ratio magnitude is outside scalar range");
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
static constexpr Precision bits(bit_count_type count)
Select a positive binary significand size.
Definition core/precision.hpp:21
Owning exact rational or finite-precision MPFR real, with eager arithmetic.
Definition mpreal.hpp:74
locale_t value
Definition data_table.cpp:49
uni20::complex< T > conj(detail::standard_complex< T > x)
Returns the complex conjugate for complex-valued scalars.
Definition math.hpp:70
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
T product(std::vector< T > const &values)
Definition mpreal_exact_example.cpp:13
constexpr detail::scalar_math::exp_fn exp
Natural exponential with scalar-specific precision handling.
Definition math.hpp:465
constexpr detail::scalar_math::cosh_fn cosh
Hyperbolic cosine.
Definition math.hpp:491
constexpr detail::scalar_math::sinpi_fn sinpi
Sine of pi times x, with argument reduction before multiplication by pi.
Definition math.hpp:640
constexpr detail::scalar_math::sinh_fn sinh
Hyperbolic sine.
Definition math.hpp:489
constexpr detail::scalar_math::ceil_fn ceil
Least integral value not less than the argument, in the scalar's result type.
Definition math.hpp:509
constexpr detail::scalar_math::atan_fn atan
Inverse tangent in radians.
Definition math.hpp:503
constexpr detail::scalar_math::sqrt_fn sqrt
Square root; exact inputs requiring approximation need an explicit finite precision.
Definition math.hpp:461
constexpr detail::scalar_math::floor_fn floor
Round toward negative infinity.
Definition math.hpp:513
constexpr detail::scalar_math::abs_fn abs
Absolute value or complex magnitude, preserving the selected scalar implementation.
Definition math.hpp:459
constexpr detail::scalar_math::fma_fn fma
Fused multiplication and addition with one final rounding.
Definition math.hpp:555
constexpr detail::scalar_math::imag_fn imag
Read the imaginary component by value; real zero retains the input's type and precision.
Definition math.hpp:673
constexpr detail::scalar_math::log_fn log
Natural logarithm with scalar-specific precision handling.
Definition math.hpp:467
constexpr detail::scalar_math::cospi_fn cospi
Cosine of pi times x, with argument reduction before multiplication by pi.
Definition math.hpp:642
Definition data_table.cpp:8
Definition async/async.hpp:26
constexpr auto pi
Pi as a native constant or a precision-aware MPFR descriptor.
Definition math_constants.hpp:37
void sum(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a full sum into an explicit async scalar tensor.
Definition linalg/async/reductions.hpp:309
theta_jet_result< C > elliptic_theta_jet(unsigned kind, C const &u, make_real_t< C > const &t, std::size_t max_terms=4096)
Evaluate theta_kind(pi*u | i*t) and its first two u derivatives.
Definition elliptic_theta_jet.hpp:402
constexpr Precision precision_of(T const &value)
Read scalar precision without changing any scalar or provider state.
Definition runtime_precision.hpp:53
constexpr auto abs(basic_half_int< T > value) -> basic_half_int< T >
Return the absolute value of a half-integer.
Definition half_int.hpp:431
constexpr S scalar_at_precision(V const &value, Precision p)
Construct or convert a scalar at one explicit precision.
Definition runtime_precision.hpp:76
C elliptic_theta_ratio(theta_jet_result< C > const &a, unsigned da, theta_jet_result< C > const &b, unsigned db)
Ratio of two scaled theta derivatives without reconstructing either jet.
Definition elliptic_theta_jet.hpp:451
void scale(Tensor &tensor, Scalar factor)
Multiply every stored numerical block by a scalar in place.
Definition block_tensor_linear.hpp:400
int add(int a, int b)
Definition dummy.cpp:6
semantic_glyph vertical
Definition presentation.cpp:1933
Theta value and first two u derivatives with a shared real exponential scale.
Definition elliptic_theta_jet.hpp:16
std::array< C, 3 > derivative
Definition elliptic_theta_jet.hpp:17
make_real_t< C > log_scale
Definition elliptic_theta_jet.hpp:18