10#if defined(MPLAPACK_BUILD_WITH_MPFR)
11#include <mplapack_mpfr.h>
13#if defined(MPLAPACK_BUILD_WITH_BINARY80)
14#include <mplapack_binary80.h>
25namespace uni20::mplapack::detail
27inline std::size_t auxiliary_size(std::size_t count, std::size_t factor)
29 if (count > std::numeric_limits<std::size_t>::max() / factor)
30 throw std::length_error(
"MPLAPACK auxiliary workspace size overflow");
31 return std::max<std::size_t>(1, count * factor);
34template <
class Adapter,
class Scalar>
35void orthogonal_factor_impl(
bool lq, std::size_t m, std::size_t n, std::span<Scalar> a, std::span<Scalar> q,
36 std::span<Scalar> triangular, Precision
p)
38 auto k = std::min(m, n);
39 Adapter::check_size(a.size(), m, n);
40 Adapter::check_size(q.size(),
lq ? k : m,
lq ? n : k);
41 Adapter::check_size(triangular.size(),
lq ? m : k,
lq ? k : n);
42 auto pm = Adapter::integer(m), pn = Adapter::integer(n), pk = Adapter::integer(k);
43 typename Adapter::precision_scope scope(
p);
45 using P =
typename Adapter::template scalar<Scalar>;
46 auto av = Adapter::pack_values(std::span<Scalar const>(a));
47 std::vector<P> tau(k);
48 Adapter::template workspace<P>(
lq ?
"gelqf" :
"geqrf", [&](P* work, mplapackint length, mplapackint&
info) {
49 if constexpr (Real<Scalar>)
52 Rgelqf(pm, pn, av.data(), pm, tau.data(), work, length, info);
54 Rgeqrf(pm, pn, av.data(), pm, tau.data(), work, length, info);
59 Cgelqf(pm, pn, av.data(), pm, tau.data(), work, length, info);
61 Cgeqrf(pm, pn, av.data(), pm, tau.data(), work, length, info);
64 auto tr =
lq ? m : k, tc =
lq ? k : n;
65 for (std::size_t j = 0; j < tc; ++j)
66 for (std::size_t i = 0; i < tr; ++i)
67 triangular[i + j * tr] =
69 Adapter::template workspace<P>(
lq ?
"orglq" :
"orgqr", [&](P* work, mplapackint length, mplapackint&
info) {
70 if constexpr (Real<Scalar>)
73 Rorglq(pk, pn, pk, av.data(), pm, tau.data(), work, length, info);
75 Rorgqr(pm, pk, pk, av.data(), pm, tau.data(), work, length, info);
80 Cunglq(pk, pn, pk, av.data(), pm, tau.data(), work, length, info);
82 Cungqr(pm, pk, pk, av.data(), pm, tau.data(), work, length, info);
85 auto qr =
lq ? k : m, qc =
lq ? n : k;
86 for (std::size_t j = 0; j < qc; ++j)
87 for (std::size_t i = 0; i <
qr; ++i)
88 q[i + j *
qr] = Adapter::get_value(av[i + j * m],
p);
89 Adapter::unpack_values(av, a,
p);
92template <
class Adapter,
class Scalar>
93void eigh_impl(std::size_t n, std::span<Scalar> a, std::span<make_real_t<Scalar>> values,
bool vectors,
char triangle,
96 Adapter::check_size(a.size(), n, n);
97 Adapter::check_size(
values.size(), n, 1);
98 if (triangle !=
'U' && triangle !=
'L')
throw std::invalid_argument(
"invalid eigensystem triangle");
99 auto pn = Adapter::integer(n);
100 typename Adapter::precision_scope scope(
p);
102 using P =
typename Adapter::template scalar<Scalar>;
103 auto av = Adapter::pack_values(std::span<Scalar const>(a));
104 std::vector<typename Adapter::real> w(n);
105 char job = vectors ?
'V' :
'N';
106 std::vector<typename Adapter::real> rwork;
107 if constexpr (!Real<Scalar>) rwork.resize(auxiliary_size(n, 3));
108 Adapter::template workspace<P>(
"eigh", [&](P* work, mplapackint length, mplapackint& info) {
109 if constexpr (Real<Scalar>)
110 Rsyev(&job, &triangle, pn, av.data(), pn, w.data(), work, length, info);
112 Cheev(&job, &triangle, pn, av.data(), pn, w.data(), work, length, rwork.data(), info);
114 Adapter::unpack_values(av, a,
p);
115 Adapter::unpack_values(w, values,
p);
118template <
class Adapter,
class Scalar>
119void svd_impl(std::size_t m, std::size_t n, std::span<Scalar> a, std::span<make_real_t<Scalar>> values,
120 std::span<Scalar> u, std::span<Scalar> vh,
char jobu,
char jobvt, Precision
p)
122 auto k = std::min(m, n);
123 auto valid_job = [](
char job) {
return job ==
'A' || job ==
'S' || job ==
'N' || job ==
'O'; };
124 if (!valid_job(jobu) || !valid_job(jobvt) || (jobu ==
'O' && jobvt ==
'O'))
125 throw std::invalid_argument(
"invalid SVD vector request");
126 auto uc = jobu ==
'A' ? m : jobu ==
'S' ? k : 0;
127 auto vr = jobvt ==
'A' ? n : jobvt ==
'S' ? k : 0;
128 Adapter::check_size(a.size(), m, n);
129 Adapter::check_size(
values.size(), k, 1);
130 Adapter::check_size(u.size(), m, uc);
131 Adapter::check_size(vh.size(), vr, n);
132 auto pm = Adapter::integer(m), pn = Adapter::integer(n);
133 auto ldu = std::max<mplapackint>(1, uc ? pm : 1);
134 auto ldvt = std::max<mplapackint>(1, Adapter::integer(vr));
135 typename Adapter::precision_scope scope(
p);
138 for (std::size_t j = 0; j < uc; ++j)
139 for (std::size_t i = 0; i < m; ++i)
140 u[i + j * m] = scalar_at_precision<Scalar>(i == j ? 1 : 0,
p);
141 for (std::size_t j = 0; j < n; ++j)
142 for (std::size_t i = 0; i < vr; ++i)
143 vh[i + j * vr] = scalar_at_precision<Scalar>(i == j ? 1 : 0,
p);
146 using P =
typename Adapter::template scalar<Scalar>;
147 auto av = Adapter::pack_values(std::span<Scalar const>(a));
148 std::vector<P> uv(std::max<std::size_t>(1, u.size())), vv(std::max<std::size_t>(1, vh.size()));
149 std::vector<typename Adapter::real> w(k), rwork;
150 if constexpr (!Real<Scalar>) rwork.resize(auxiliary_size(k, 5));
151 Adapter::template workspace<P>(
"gesvd", [&](P* work, mplapackint length, mplapackint& info) {
152 if constexpr (Real<Scalar>)
153 Rgesvd(&jobu, &jobvt, pm, pn, av.data(), pm, w.data(), uv.data(), ldu, vv.data(), ldvt, work, length, info);
155 Cgesvd(&jobu, &jobvt, pm, pn, av.data(), pm, w.data(), uv.data(), ldu, vv.data(), ldvt, work, length,
158 Adapter::unpack_values(av, a,
p);
159 Adapter::unpack_values(w, values,
p);
161 vv.resize(vh.size());
162 Adapter::unpack_values(uv, u,
p);
163 Adapter::unpack_values(vv, vh,
p);
166template <
class Adapter,
class Scalar>
167void eigen_impl(std::size_t n, std::span<Scalar> a, std::span<
complex<make_real_t<Scalar>>> values,
168 std::span<
complex<make_real_t<Scalar>>> vectors,
bool compute_vectors, Precision
p)
170 Adapter::check_size(a.size(), n, n);
171 Adapter::check_size(
values.size(), n, 1);
172 Adapter::check_size(vectors.size(), compute_vectors ? n : 0, n);
173 auto pn = Adapter::integer(n);
174 typename Adapter::precision_scope scope(
p);
176 using P =
typename Adapter::template scalar<Scalar>;
177 auto av = Adapter::pack_values(std::span<Scalar const>(a));
178 std::vector<P> vl(1), vr(std::max<std::size_t>(1, vectors.size()));
179 char job = compute_vectors ?
'V' :
'N';
180 auto ldvr = compute_vectors ? pn : mplapackint{1};
181 if constexpr (Real<Scalar>)
183 std::vector<P> wr(n), wi(n);
184 Adapter::template workspace<P>(
"geev", [&](P* work, mplapackint length, mplapackint& info) {
185 Rgeev(
"N", &job, pn, av.data(), pn, wr.data(), wi.data(), vl.data(), 1, vr.data(), ldvr, work, length, info);
187 for (std::size_t j = 0; j < n; ++j)
188 values[j] =
complex<make_real_t<Scalar>>(Adapter::get_value(wr[j],
p), Adapter::get_value(wi[j],
p));
190 for (std::size_t j = 0; j < n; ++j)
193 for (std::size_t i = 0; i < n; ++i)
194 vectors[i + j * n] =
complex<make_real_t<Scalar>>(Adapter::get_value(vr[i + j * n],
p),
195 scalar_at_precision<make_real_t<Scalar>>(0,
p));
198 CHECK(wi[j] > 0 && j + 1 < n,
"invalid conjugate eigenvector pair");
199 for (std::size_t i = 0; i < n; ++i)
201 auto v = complex<make_real_t<Scalar>>(Adapter::get_value(vr[i + j * n],
p),
202 Adapter::get_value(vr[i + (j + 1) * n],
p));
203 vectors[i + j * n] = v;
213 std::vector<typename Adapter::real> rwork(auxiliary_size(n, 2));
214 Adapter::template workspace<P>(
"geev", [&](P* work, mplapackint length, mplapackint& info) {
215 Cgeev(
"N", &job, pn, av.data(), pn, w.data(), vl.data(), 1, vr.data(), ldvr, work, length, rwork.data(), info);
217 Adapter::unpack_values(w, values,
p);
218 if (compute_vectors) Adapter::unpack_values(vr, vectors,
p);
220 Adapter::unpack_values(av, a,
p);
uni20::complex< T > conj(detail::standard_complex< T > x)
Returns the complex conjugate for complex-valued scalars.
Definition math.hpp:70
typename detail::complex_type< Real >::type complex
Project-level complex scalar spelling.
Definition types.hpp:66
void info(checked_format_string< Args... > format, Args &&... args)
Emit an informational display message.
Definition display.hpp:393
auto values(Tensor &tensor)
Definition packed_matrix.hpp:29
void lq(std::size_t m, std::size_t n, std::span< float80 > a, std::span< float80 > q, std::span< float80 > triangular, Precision p)
Overwrite m-by-n input work and return Q (k-by-n) and L (m-by-k), k=min(m,n).
Definition binary80.cpp:231
void qr(std::size_t m, std::size_t n, std::span< float80 > a, std::span< float80 > q, std::span< float80 > triangular, Precision p)
Overwrite m-by-n input work and return Q (m-by-k) and R (k-by-n), k=min(m,n).
Definition binary80.cpp:225
Definition data_table.cpp:8
constexpr S scalar_at_precision(V const &value, Precision p)
Construct or convert a scalar at one explicit precision.
Definition runtime_precision.hpp:76
#define CHECK(cond,...)
Definition trace.hpp:299