LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
complex_number.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_NUM_COMPLEX_NUMBER_H
6#define LINE_NUM_COMPLEX_NUMBER_H
7
8/**
9 * @file
10 * @ingroup line_num
11 * `std::complex<double>` as a number type for the generic linear algebra.
12 *
13 * WHY THIS EXISTS. One algorithm in the port needs complex arithmetic: the
14 * Laplace-domain transient QBD (`mam_transient2`, `mam_transient2_open`),
15 * whose level blocks are shifted by `-s I` at a COMPLEX quadrature node s and
16 * whose fundamental matrices G and R are therefore complex. Everything it needs
17 * -- products, identity, inverse, integer powers, LU with partial pivoting --
18 * already exists in `util/linalg.h` and `util/lu.h` templated on the element
19 * type, so declaring the traits here makes the whole stack available at complex
20 * argument instead of duplicating it.
21 *
22 * WHAT IS DELIBERATELY NARROW. `to_double` returns the REAL PART, because the
23 * only consumer is a Laplace inversion whose quadrature sums `Re(eta_k F(s_k))`
24 * and discards the imaginary part by construction. `log_as_double` is the log
25 * of the MODULUS. Neither is a faithful "convert to double"; both are the
26 * meaning the transient QBD needs, and no other algorithm instantiates this
27 * type. Do not reach for it as a general complex facility without revisiting
28 * those two.
29 *
30 * `is_exact` is false and `has_transcendental` is true, so any algorithm gated
31 * on exact arithmetic refuses at complex argument, as it should.
32 */
33
34#include <cmath>
35#include <complex>
36#include <string>
37
38#include "line/num/number.h"
39#include "line/util/lu.h"
40
41namespace line {
42
43using Complex = std::complex<double>;
44
45template <>
47 using type = Complex;
48 static constexpr bool is_exact = false;
49 static constexpr bool has_transcendental = true;
50 static const char* name() { return "complex"; }
51
52 static Complex from_int(long v) { return Complex(static_cast<double>(v), 0.0); }
53 static Complex from_rational(long num, long den) {
54 return Complex(static_cast<double>(num) / static_cast<double>(den), 0.0);
55 }
56 static Complex from_double(double v) { return Complex(v, 0.0); }
57 /** The real part: the Laplace quadrature keeps Re and discards Im. */
58 static double to_double(const Complex& v) { return v.real(); }
59 /** Log of the modulus. */
60 static double log_as_double(const Complex& v) { return std::log(std::abs(v)); }
61 static std::string to_string(const Complex& v) {
62 return std::to_string(v.real()) + (v.imag() < 0.0 ? "-" : "+") +
63 std::to_string(std::fabs(v.imag())) + "i";
64 }
65};
66
67/** Partial pivoting compares moduli, since the complex field is unordered. */
68template <class R>
69struct pivot_mag<std::complex<R>> {
70 using type = R;
71 static R of(const std::complex<R>& x) { return std::abs(x); }
72};
73
74} // namespace line
75
76#endif // LINE_NUM_COMPLEX_NUMBER_H
LU factorization with partial pivoting, templated on the number type.
std::complex< double > Complex
Number-type abstraction for the templated API port.
static Complex from_double(double v)
static std::string to_string(const Complex &v)
static double log_as_double(const Complex &v)
Log of the modulus.
static constexpr bool is_exact
static const char * name()
static Complex from_rational(long num, long den)
static double to_double(const Complex &v)
The real part: the Laplace quadrature keeps Re and discards Im.
static Complex from_int(long v)
static constexpr bool has_transcendental
static R of(const std::complex< R > &x)
The ordered type the pivot search compares in.
Definition lu.h:38