scirs2_linalg/matrix_functions/
hyperbolic.rs1use scirs2_core::ndarray::{Array2, ArrayView2};
4use scirs2_core::numeric::{Float, NumAssign, One};
5use std::iter::Sum;
6
7use crate::error::{LinalgError, LinalgResult};
8use crate::validation::validate_decomposition;
9
10#[allow(dead_code)]
36pub fn coshm<F>(a: &ArrayView2<F>) -> LinalgResult<Array2<F>>
37where
38 F: Float + NumAssign + Sum + One + Send + Sync + scirs2_core::ndarray::ScalarOperand + 'static,
39{
40 validate_decomposition(a, "Matrix hyperbolic cosine computation", true)?;
41
42 let n = a.nrows();
43
44 let mut is_zero = true;
46 for i in 0..n {
47 for j in 0..n {
48 if a[[i, j]].abs() > F::epsilon() {
49 is_zero = false;
50 break;
51 }
52 }
53 if !is_zero {
54 break;
55 }
56 }
57
58 if is_zero {
59 return Ok(Array2::eye(n)); }
61
62 let mut is_diagonal = true;
64 for i in 0..n {
65 for j in 0..n {
66 if i != j && a[[i, j]].abs() > F::epsilon() {
67 is_diagonal = false;
68 break;
69 }
70 }
71 if !is_diagonal {
72 break;
73 }
74 }
75
76 if is_diagonal {
77 let mut result = Array2::<F>::zeros((n, n));
78 for i in 0..n {
79 result[[i, i]] = a[[i, i]].cosh();
80 }
81 return Ok(result);
82 }
83
84 let mut a2 = Array2::<F>::zeros((n, n));
89 for i in 0..n {
90 for j in 0..n {
91 for k in 0..n {
92 a2[[i, j]] += a[[i, k]] * a[[k, j]];
93 }
94 }
95 }
96
97 let mut a4 = Array2::<F>::zeros((n, n));
98 for i in 0..n {
99 for j in 0..n {
100 for k in 0..n {
101 a4[[i, j]] += a2[[i, k]] * a2[[k, j]];
102 }
103 }
104 }
105
106 let mut a6 = Array2::<F>::zeros((n, n));
107 for i in 0..n {
108 for j in 0..n {
109 for k in 0..n {
110 a6[[i, j]] += a4[[i, k]] * a2[[k, j]];
111 }
112 }
113 }
114
115 let mut result = Array2::eye(n);
117
118 let two_factorial = F::from(2.0).unwrap();
120 for i in 0..n {
121 for j in 0..n {
122 result[[i, j]] += a2[[i, j]] / two_factorial;
123 }
124 }
125
126 let four_factorial = F::from(24.0).unwrap();
128 for i in 0..n {
129 for j in 0..n {
130 result[[i, j]] += a4[[i, j]] / four_factorial;
131 }
132 }
133
134 let six_factorial = F::from(720.0).unwrap();
136 for i in 0..n {
137 for j in 0..n {
138 result[[i, j]] += a6[[i, j]] / six_factorial;
139 }
140 }
141
142 Ok(result)
143}
144
145#[allow(dead_code)]
171pub fn sinhm<F>(a: &ArrayView2<F>) -> LinalgResult<Array2<F>>
172where
173 F: Float + NumAssign + Sum + One + Send + Sync + scirs2_core::ndarray::ScalarOperand + 'static,
174{
175 validate_decomposition(a, "Matrix hyperbolic sine computation", true)?;
176
177 let n = a.nrows();
178
179 let mut is_zero = true;
181 for i in 0..n {
182 for j in 0..n {
183 if a[[i, j]].abs() > F::epsilon() {
184 is_zero = false;
185 break;
186 }
187 }
188 if !is_zero {
189 break;
190 }
191 }
192
193 if is_zero {
194 return Ok(Array2::<F>::zeros((n, n))); }
196
197 let mut is_diagonal = true;
199 for i in 0..n {
200 for j in 0..n {
201 if i != j && a[[i, j]].abs() > F::epsilon() {
202 is_diagonal = false;
203 break;
204 }
205 }
206 if !is_diagonal {
207 break;
208 }
209 }
210
211 if is_diagonal {
212 let mut result = Array2::<F>::zeros((n, n));
213 for i in 0..n {
214 result[[i, i]] = a[[i, i]].sinh();
215 }
216 return Ok(result);
217 }
218
219 let mut a2 = Array2::<F>::zeros((n, n));
224 for i in 0..n {
225 for j in 0..n {
226 for k in 0..n {
227 a2[[i, j]] += a[[i, k]] * a[[k, j]];
228 }
229 }
230 }
231
232 let mut a3 = Array2::<F>::zeros((n, n));
233 for i in 0..n {
234 for j in 0..n {
235 for k in 0..n {
236 a3[[i, j]] += a2[[i, k]] * a[[k, j]];
237 }
238 }
239 }
240
241 let mut a5 = Array2::<F>::zeros((n, n));
242 for i in 0..n {
243 for j in 0..n {
244 for k in 0..n {
245 a5[[i, j]] += a3[[i, k]] * a2[[k, j]];
246 }
247 }
248 }
249
250 let mut a7 = Array2::<F>::zeros((n, n));
251 for i in 0..n {
252 for j in 0..n {
253 for k in 0..n {
254 a7[[i, j]] += a5[[i, k]] * a2[[k, j]];
255 }
256 }
257 }
258
259 let mut result = a.to_owned();
261
262 let three_factorial = F::from(6.0).unwrap();
264 for i in 0..n {
265 for j in 0..n {
266 result[[i, j]] += a3[[i, j]] / three_factorial;
267 }
268 }
269
270 let five_factorial = F::from(120.0).unwrap();
272 for i in 0..n {
273 for j in 0..n {
274 result[[i, j]] += a5[[i, j]] / five_factorial;
275 }
276 }
277
278 let seven_factorial = F::from(5040.0).unwrap();
280 for i in 0..n {
281 for j in 0..n {
282 result[[i, j]] += a7[[i, j]] / seven_factorial;
283 }
284 }
285
286 Ok(result)
287}
288
289#[allow(dead_code)]
311pub fn tanhm<F>(a: &ArrayView2<F>) -> LinalgResult<Array2<F>>
312where
313 F: Float + NumAssign + Sum + One + Send + Sync + scirs2_core::ndarray::ScalarOperand + 'static,
314{
315 use crate::solve::solve_multiple;
316
317 let sinh_a = sinhm(a)?;
318 let cosh_a = coshm(a)?;
319
320 solve_multiple(&cosh_a.view(), &sinh_a.view(), None)
323}