1use super::blas::{Op, Side, Uplo, gemm, trsm};
4use super::eigen::real_to_complex_schur;
5use super::element::sealed::{Element as _, Scalar as _};
6use super::schur::schur;
7use super::{Matrix, Norm, Scalar};
8use crate::math::complex::Float;
9
10const PADE: [(&[f64], f64); 5] = [
14 (&[120.0, 60.0, 12.0, 1.0], 1.495_585_217_958_292e-2),
15 (
16 &[30240.0, 15120.0, 3360.0, 420.0, 30.0, 1.0],
17 2.539_398_330_063_23e-1,
18 ),
19 (
20 &[
21 17_297_280.0,
22 8_648_640.0,
23 1_995_840.0,
24 277_200.0,
25 25200.0,
26 1512.0,
27 56.0,
28 1.0,
29 ],
30 9.504_178_996_162_932e-1,
31 ),
32 (
33 &[
34 17_643_225_600.0,
35 8_821_612_800.0,
36 2_075_673_600.0,
37 302_702_400.0,
38 30_270_240.0,
39 2_162_160.0,
40 110_880.0,
41 3960.0,
42 90.0,
43 1.0,
44 ],
45 2.097_847_961_257_068,
46 ),
47 (
48 &[
49 64_764_752_532_480_000.0,
50 32_382_376_266_240_000.0,
51 7_771_770_303_897_600.0,
52 1_187_353_796_428_800.0,
53 129_060_195_264_000.0,
54 10_559_470_521_600.0,
55 670_442_572_800.0,
56 33_522_128_640.0,
57 1_323_241_920.0,
58 40_840_800.0,
59 960_960.0,
60 16380.0,
61 182.0,
62 1.0,
63 ],
64 5.371_920_351_148_152,
65 ),
66];
67
68const PADE_DOUBLE: [(usize, f64); 4] = [
71 (0, PADE[0].1),
72 (1, PADE[1].1),
73 (2, PADE[2].1),
74 (3, PADE[3].1),
75];
76
77const PADE_SINGLE: [(usize, f64); 3] = [
79 (0, 4.258_730_016_922_831e-1),
80 (1, 1.880_152_677_804_762),
81 (2, 3.925_724_783_138_66),
82];
83
84const GAUSS: [(f64, f64); 7] = [
86 (0.025_446_043_828_620_74, 0.064_742_483_084_434_85),
87 (0.129_234_407_200_302_78, 0.139_852_695_744_638_33),
88 (0.297_077_424_311_301_4, 0.190_915_025_252_559_47),
89 (0.5, 0.208_979_591_836_734_7),
90 (0.702_922_575_688_698_6, 0.190_915_025_252_559_47),
91 (0.870_765_592_799_697_2, 0.139_852_695_744_638_33),
92 (0.974_553_956_171_379_3, 0.064_742_483_084_434_85),
93];
94
95const LOG_THETA: f64 = 0.264;
98
99impl<T: Scalar> Matrix<T> {
100 #[track_caller]
120 pub fn exp(&self) -> Self {
121 assert!(self.is_square(), "the matrix is not square");
122 let n = self.rows();
123 if self.data.iter().any(|x| !x.is_finite()) {
124 let nan = T::from_parts(T::Real::NAN, T::Real::NAN);
125 return Matrix::from_fn(n, n, |_, _| nan);
126 }
127 let norm = self.norm(Norm::One).to_f64();
128 let single = T::Real::MANTISSA_DIGITS <= 24;
129 let (table, top): (&[(usize, f64)], usize) = if single {
130 (&PADE_SINGLE, 2)
131 } else {
132 (&PADE_DOUBLE, 4)
133 };
134 for &(d, theta) in table {
135 if norm <= theta {
136 return pade(self, PADE[d].0);
137 }
138 }
139 let theta = if single { PADE_SINGLE[2].1 } else { PADE[4].1 };
140 let log2 = if norm.is_finite() {
144 (norm / theta).log2()
145 } else {
146 let big = self.data.iter().fold(0.0f64, |s, x| {
147 s.max(x.re().abs().to_f64().max(x.im().abs().to_f64()))
148 });
149 (n as f64).log2() + big.log2() + 0.5 - theta.log2()
150 };
151 let s = log2.ceil().max(0.0) as i32;
152 let scaled = self.map(|&x| x.scale(T::Real::from_f64(0.5f64.powi(s))));
153 let mut x = pade(&scaled, PADE[top].0);
154 for _ in 0..s {
155 x = &x * &x;
156 }
157 x
158 }
159
160 #[track_caller]
180 pub fn sqrt(&self) -> Option<Self> {
181 assert!(self.is_square(), "the matrix is not square");
182 let n = self.rows();
183 let (t, q) = self.complex_schur(|w| w.re < T::Real::ZERO)?;
184 let r = triangular_sqrt(&t, n)?;
185 Some(self.back_from_schur(&r, &q))
186 }
187
188 #[track_caller]
210 pub fn log(&self) -> Option<Self> {
211 assert!(self.is_square(), "the matrix is not square");
212 let n = self.rows();
213 let zero = T::Real::ZERO;
214 let (t, q) = self.complex_schur(|w| w.re <= zero)?;
215 if (0..n).any(|i| t[i + i * n] == T::C::zero()) {
216 return None;
217 }
218 let mut r = t;
220 let mut k = 0;
221 loop {
222 let mut x = r.clone();
223 for i in 0..n {
224 x[i + i * n] -= T::C::one();
225 }
226 let norm = Matrix::from_column_major(n, n, x).norm(Norm::One).to_f64();
227 if norm <= LOG_THETA || k >= 64 {
228 break;
229 }
230 r = triangular_sqrt(&r, n)?;
231 k += 1;
232 }
233 let mut x = r;
235 for i in 0..n {
236 x[i + i * n] = root_minus_one(q.1[i], k);
237 }
238 let mut sum = vec![T::C::zero(); n * n];
240 for &(node, weight) in &GAUSS {
241 let node = T::Real::from_f64(node);
242 let mut m = x.clone();
243 for v in m.iter_mut() {
244 *v = v.scale(node);
245 }
246 for i in 0..n {
247 m[i + i * n] += T::C::one();
248 }
249 let mut y = x.clone();
250 trsm(
251 Side::Left,
252 Uplo::Upper,
253 Op::N,
254 false,
255 n,
256 n,
257 &m,
258 n,
259 &mut y,
260 n,
261 );
262 let w = T::Real::from_f64(weight);
263 for (s, y) in sum.iter_mut().zip(&y) {
264 *s += y.scale(w);
265 }
266 }
267 let two_k = T::Real::from_f64(2f64.powi(k));
268 for s in &mut sum {
269 *s = s.scale(two_k);
270 }
271 Some(self.back_from_schur(&sum, &q))
272 }
273
274 #[allow(clippy::type_complexity)]
278 fn complex_schur(
279 &self,
280 excluded: impl Fn(crate::math::complex::Complex<T::Real>) -> bool,
281 ) -> Option<(Vec<T::C>, (Vec<T::C>, Vec<T::C>))> {
282 let n = self.rows();
283 if self.data.iter().any(|x| !x.is_finite()) {
284 return None;
285 }
286 let (t, q, w) = schur(self, true, true);
287 if !T::IS_COMPLEX && w.iter().any(|&w| w.im == T::Real::ZERO && excluded(w)) {
288 return None;
289 }
290 let mut tc: Vec<T::C> = t.data.iter().map(|x| x.to_c()).collect();
291 let mut qc: Vec<T::C> = q
292 .unwrap_or_default()
293 .data
294 .iter()
295 .map(|x| x.to_c())
296 .collect();
297 if !T::IS_COMPLEX {
298 real_to_complex_schur(&mut tc, &mut qc, n);
299 }
300 let diagonal = (0..n).map(|i| tc[i + i * n]).collect();
301 Some((tc, (qc, diagonal)))
302 }
303
304 fn back_from_schur(&self, r: &[T::C], q: &(Vec<T::C>, Vec<T::C>)) -> Self {
306 let n = self.rows();
307 let q = &q.0;
308 let mut qr = vec![T::C::zero(); n * n];
309 gemm(
310 n,
311 n,
312 n,
313 T::C::one(),
314 q,
315 n,
316 Op::N,
317 r,
318 n,
319 Op::N,
320 T::C::zero(),
321 &mut qr,
322 n,
323 );
324 let mut x = vec![T::C::zero(); n * n];
325 gemm(
326 n,
327 n,
328 n,
329 T::C::one(),
330 &qr,
331 n,
332 Op::N,
333 q,
334 n,
335 Op::C,
336 T::C::zero(),
337 &mut x,
338 n,
339 );
340 Matrix::from_column_major(n, n, x.into_iter().map(T::from_c).collect())
341 }
342}
343
344fn pade<T: Scalar>(a: &Matrix<T>, b: &[f64]) -> Matrix<T> {
348 let n = a.rows();
349 let c = |k: usize| T::from_real(T::Real::from_f64(b[k]));
350 let identity = Matrix::<T>::identity(n);
351 let a2 = a * a;
352 let (u, v) = if b.len() == 14 {
353 let a4 = &a2 * &a2;
354 let a6 = &a4 * &a2;
355 let inner_u = &(&(&a6 * c(13)) + &(&a4 * c(11))) + &(&a2 * c(9));
356 let u = &(&(&(&a6 * &inner_u) + &(&a6 * c(7))) + &(&(&a4 * c(5)) + &(&a2 * c(3))))
357 + &(&identity * c(1));
358 let inner_v = &(&(&a6 * c(12)) + &(&a4 * c(10))) + &(&a2 * c(8));
359 let v = &(&(&(&a6 * &inner_v) + &(&a6 * c(6))) + &(&(&a4 * c(4)) + &(&a2 * c(2))))
360 + &(&identity * c(0));
361 (a * &u, v)
362 } else {
363 let mut odd = &identity * c(1);
365 let mut even = &identity * c(0);
366 let mut power = identity.clone();
367 for k in 1..b.len() / 2 {
368 power = &power * &a2;
369 odd += &power * c(2 * k + 1);
370 even += &power * c(2 * k);
371 }
372 (a * &odd, even)
373 };
374 (&v - &u)
375 .solve(&(&v + &u))
376 .unwrap_or_else(|| Matrix::from_fn(n, n, |_, _| T::from_parts(T::Real::NAN, T::Real::NAN)))
377}
378
379fn triangular_sqrt<C: Scalar>(t: &[C], n: usize) -> Option<Vec<C>> {
383 let at = |i: usize, j: usize| i + j * n;
384 let mut r = vec![C::zero(); n * n];
385 for j in 0..n {
386 r[at(j, j)] = t[at(j, j)].sqrt();
387 for i in (0..j).rev() {
388 let mut s = t[at(i, j)];
389 for k in i + 1..j {
390 s -= r[at(i, k)] * r[at(k, j)];
391 }
392 let d = r[at(i, i)] + r[at(j, j)];
393 if d == C::zero() {
394 if s != C::zero() {
395 return None;
396 }
397 continue;
398 }
399 r[at(i, j)] = s / d;
400 }
401 }
402 Some(r)
403}
404
405fn root_minus_one<C: Scalar>(a: C, k: i32) -> C {
408 if k == 0 {
409 return a - C::one();
410 }
411 let mut a = a;
412 let mut k = k;
413 if a.re() < C::Real::ZERO {
415 a = a.sqrt();
416 k -= 1;
417 if k == 0 {
418 return a - C::one();
419 }
420 }
421 let z0 = a - C::one();
422 a = a.sqrt();
423 let mut r = C::one() + a;
424 for _ in 1..k {
425 a = a.sqrt();
426 r *= C::one() + a;
427 }
428 z0 / r
429}