glucat 0.12.0
clifford_algebra_imp.h
Go to the documentation of this file.
1#ifndef _GLUCAT_CLIFFORD_ALGEBRA_IMP_H
2#define _GLUCAT_CLIFFORD_ALGEBRA_IMP_H
3/***************************************************************************
4 GluCat : Generic library of universal Clifford algebra templates
5 clifford_algebra_imp.h : Implement common Clifford algebra functions
6 -------------------
7 begin : Sun 2001-12-09
8 copyright : (C) 2001-2021 by Paul C. Leopardi
9 ***************************************************************************
10
11 This library is free software: you can redistribute it and/or modify
12 it under the terms of the GNU Lesser General Public License as published
13 by the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with this library. If not, see <http://www.gnu.org/licenses/>.
23
24 ***************************************************************************
25 This library is based on a prototype written by Arvind Raja and was
26 licensed under the LGPL with permission of the author. See Arvind Raja,
27 "Object-oriented implementations of Clifford algebras in C++: a prototype",
28 in Ablamowicz, Lounesto and Parra (eds.)
29 "Clifford algebras with numeric and symbolic computations", Birkhauser, 1996.
30 ***************************************************************************
31 See also Arvind Raja's original header comments in glucat.h
32 ***************************************************************************/
33
34// References for algorithms:
35// [AS]:
36// Milton Abramowicz and Irene A. Stegun, "Handbook of mathematical functions",
37// Dover 1972, first published 1965.
38// [CHKL]:
39// Sheung Hun Cheng, Nicholas J. Higham, Charles S. Kenney and Alan J. Laub,
40// "Approximating the Logarithm of a Matrix to Specified Accuracy", 1999.
41// ftp://ftp.ma.man.ac.uk/pub/narep/narep353.ps.gz
42// [GL]:
43// Gene H. Golub and Charles F. van Loan,
44// "Matrix Computations", 3rd ed., Johns Hopkins UP, 1996.
45// [GW]:
46// C.F. Gerald and P.O. Wheatley, "Applied Numerical Analysis",
47// 6th Edition, Addison-Wesley, 1999.
48// [H]:
49// Nicholas J. Higham
50// "The Scaling and Squaring Method for the Matrix Exponential Revisited",
51// SIAM Journal on Matrix Analysis and Applications,
52// Vol. 26, Issue 4 (2005), pp. 1179-1193.
53// [Z]:
54// Doron Zeilberger, "PADE" (Maple code), 2002.
55// http://www.math.rutgers.edu/~zeilberg/tokhniot/PADE
58#include "glucat/scalar.h"
59
60#include <array>
61
62namespace glucat
63{
64 template< typename Scalar_T, typename Index_Set_T, typename Multivector_T>
65 auto
67 classname() -> const std::string
68 { return "clifford_algebra"; }
69
71 template< typename Scalar_T, typename Index_Set_T, typename Multivector_T>
72 const
73 Scalar_T
75 default_truncation = std::numeric_limits<Scalar_T>::epsilon();
76
78 template
79 <
80 template<typename, const index_t, const index_t, typename> class Multivector,
81 template<typename, const index_t, const index_t, typename> class RHS,
82 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
83 >
84 inline
85 auto
86 operator!= (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> bool
87 { return !(lhs == rhs); }
88
90 template< template<typename, const index_t, const index_t, typename> class Multivector,
91 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
92 inline
93 auto
94 operator!= (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const Scalar_T& scr) -> bool
95 { return !(lhs == scr); }
96
98 template< template<typename, const index_t, const index_t, typename> class Multivector,
99 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
100 inline
101 auto
102 operator!= (const Scalar_T& scr, const Multivector<Scalar_T,LO,HI,Tune_P>& rhs) -> bool
103 { return !(rhs == scr); }
104
106 template
107 <
108 template<typename, const index_t, const index_t, typename> class Multivector,
109 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
110 >
111 auto
112 error_squared_tol(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
113 {
114 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
115 static const auto scalar_eps = std::numeric_limits<Scalar_T>::epsilon();
116 static const auto nbr_different_bits =
117 std::numeric_limits<Scalar_T>::digits / Tune_P::denom_different_bits + Tune_P::extra_different_bits;
118 static const auto abs_tol = scalar_eps *
119 numeric_traits<Scalar_T>::pow(Scalar_T(2), nbr_different_bits);
120 using framed_multi_t = typename multivector_t::framed_multi_t;
121 const auto nbr_terms = double(framed_multi_t(val).truncated(scalar_eps).nbr_terms());
122 return abs_tol * abs_tol * std::max(Scalar_T(nbr_terms), Scalar_T(1));
123 }
124
126 template
127 <
128 template<typename, const index_t, const index_t, typename> class Multivector,
129 template<typename, const index_t, const index_t, typename> class RHS,
130 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
131 >
132 inline
133 auto
134 error_squared(const Multivector<Scalar_T,LO,HI,Tune_P>& lhs,
135 const RHS<Scalar_T,LO,HI,Tune_P>& rhs,
136 const Scalar_T threshold) -> Scalar_T
137 {
138 const auto relative = norm(rhs) > threshold;
139 const auto abs_norm_diff = norm(rhs-lhs);
140 return (relative)
141 ? abs_norm_diff/norm(rhs)
142 : abs_norm_diff;
143 }
144
146 template
147 <
148 template<typename, const index_t, const index_t, typename> class Multivector,
149 template<typename, const index_t, const index_t, typename> class RHS,
150 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
151 >
152 inline
153 auto
154 approx_equal(const Multivector<Scalar_T,LO,HI,Tune_P>& lhs,
155 const RHS<Scalar_T,LO,HI,Tune_P>& rhs,
156 const Scalar_T threshold,
157 const Scalar_T tolerance) -> bool
158 { return error_squared(lhs, rhs, threshold) < tolerance; }
159
161 template
162 <
163 template<typename, const index_t, const index_t, typename> class Multivector,
164 template<typename, const index_t, const index_t, typename> class RHS,
165 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
166 >
167 inline
168 auto
169 approx_equal(const Multivector<Scalar_T,LO,HI,Tune_P>& lhs,
170 const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> bool
171 {
172 const Scalar_T rhs_tol = error_squared_tol(rhs);
173 return approx_equal(lhs, rhs, rhs_tol, rhs_tol);
174 }
175
177 template< template<typename, const index_t, const index_t, typename> class Multivector,
178 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
179 inline
180 auto
181 operator+ (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const Scalar_T& scr) -> const Multivector<Scalar_T,LO,HI,Tune_P>
182 {
183 auto result = lhs;
184 return result += scr;
185 }
186
188 template< template<typename, const index_t, const index_t, typename> class Multivector,
189 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
190 inline
191 auto
192 operator+ (const Scalar_T& scr, const Multivector<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
193 {
194 return rhs + scr;
195 }
196
198 template
199 <
200 template<typename, const index_t, const index_t, typename> class Multivector,
201 template<typename, const index_t, const index_t, typename> class RHS,
202 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
203 >
204 inline
205 auto
206 operator+ (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
207 {
208 auto result = lhs;
209 return result += rhs;
210 }
211
213 template< template<typename, const index_t, const index_t, typename> class Multivector,
214 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
215 inline
216 auto
217 operator- (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const Scalar_T& scr) -> const Multivector<Scalar_T,LO,HI,Tune_P>
218 {
219 auto result = lhs;
220 return result -= scr;
221 }
222
224 template< template<typename, const index_t, const index_t, typename> class Multivector,
225 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
226 inline
227 auto
228 operator- (const Scalar_T& scr, const Multivector<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
229 { return -rhs + scr; }
230
232 template
233 <
234 template<typename, const index_t, const index_t, typename> class Multivector,
235 template<typename, const index_t, const index_t, typename> class RHS,
236 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
237 >
238 inline
239 auto
240 operator- (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
241 {
242 auto result = lhs;
243 return result -= rhs;
244 }
245
247 template< template<typename, const index_t, const index_t, typename> class Multivector,
248 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
249 inline
250 auto
251 operator* (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const Scalar_T& scr) -> const Multivector<Scalar_T,LO,HI,Tune_P>
252 {
253 auto result = lhs;
254 return result *= scr;
255 }
256
258 template< template<typename, const index_t, const index_t, typename> class Multivector,
259 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
260 inline
261 auto
262 operator* (const Scalar_T& scr, const Multivector<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
263 { // Note: this assumes that scalar commutes with multivector.
264 // This excludes Clifford algebras over non-commuting rings.
265 return rhs * scr;
266 }
267
269 template
270 <
271 template<typename, const index_t, const index_t, typename> class Multivector,
272 template<typename, const index_t, const index_t, typename> class RHS,
273 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
274 >
275 inline
276 auto
277 operator* (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
278 {
279 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
280 return lhs * multivector_t(rhs);
281 }
282
284 template
285 <
286 template<typename, const index_t, const index_t, typename> class Multivector,
287 template<typename, const index_t, const index_t, typename> class RHS,
288 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
289 >
290 inline
291 auto
292 operator^ (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
293 {
294 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
295 return lhs ^ multivector_t(rhs);
296 }
297
299 template
300 <
301 template<typename, const index_t, const index_t, typename> class Multivector,
302 template<typename, const index_t, const index_t, typename> class RHS,
303 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
304 >
305 inline
306 auto
307 operator& (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
308 {
309 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
310 return lhs & multivector_t(rhs);
311 }
312
314 template
315 <
316 template<typename, const index_t, const index_t, typename> class Multivector,
317 template<typename, const index_t, const index_t, typename> class RHS,
318 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
319 >
320 inline
321 auto
322 operator% (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
323 {
324 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
325 return lhs % multivector_t(rhs);
326 }
327
329 template
330 <
331 template<typename, const index_t, const index_t, typename> class Multivector,
332 template<typename, const index_t, const index_t, typename> class RHS,
333 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
334 >
335 inline
336 auto
337 star (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> Scalar_T
338 {
339 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
340 return star(lhs, multivector_t(rhs));
341 }
342
344 template< template<typename, const index_t, const index_t, typename> class Multivector,
345 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
346 inline
347 auto
348 operator/ (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const Scalar_T& scr) -> const Multivector<Scalar_T,LO,HI,Tune_P>
349 {
350 auto result = lhs;
351 return result /= scr;
352 }
353
355 template< template<typename, const index_t, const index_t, typename> class Multivector,
356 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
357 inline
358 auto
359 operator/ (const Scalar_T& scr, const Multivector<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
360 {
361 Multivector<Scalar_T,LO,HI,Tune_P> result = scr;
362 return result /= rhs;
363 }
364
366 template
367 <
368 template<typename, const index_t, const index_t, typename> class Multivector,
369 template<typename, const index_t, const index_t, typename> class RHS,
370 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
371 >
372 inline
373 auto
374 operator/ (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
375 {
376 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
377 return lhs / multivector_t(rhs);
378 }
379
381 template
382 <
383 template<typename, const index_t, const index_t, typename> class Multivector,
384 template<typename, const index_t, const index_t, typename> class RHS,
385 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
386 >
387 inline
388 auto
389 operator| (const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
390 {
391 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
392 return lhs | multivector_t(rhs);
393 }
394
396 template< template<typename, const index_t, const index_t, typename> class Multivector,
397 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
398 inline
399 auto
400 inv(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
401 { return val.inv(); }
402
404 template< template<typename, const index_t, const index_t, typename> class Multivector,
405 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
406 auto
407 pow(const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, int rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
408 {
409 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
410 if (lhs == Scalar_T(0))
411 {
412 using traits_t = numeric_traits<Scalar_T>;
413 return
414 (rhs < 0)
415 ? traits_t::NaN()
416 : (rhs == 0)
417 ? Scalar_T(1)
418 : Scalar_T(0);
419 }
420 auto result = multivector_t(Scalar_T(1));
421 auto power =
422 (rhs < 0)
423 ? lhs.inv()
424 : lhs;
425 for (auto
426 k = std::abs(rhs);
427 k != 0;
428 k /= 2)
429 {
430 if (k % 2)
431 result *= power;
432 power *= power;
433 }
434 return result;
435 }
436
438 template
439 <
440 template<typename, const index_t, const index_t, typename> class Multivector,
441 template<typename, const index_t, const index_t, typename> class RHS,
442 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
443 >
444 inline
445 auto
446 pow(const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, const RHS<Scalar_T,LO,HI,Tune_P>& rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
447 {
448 using traits_t = numeric_traits<Scalar_T>;
449
450 if (lhs == Scalar_T(0))
451 {
452 const Scalar_T m = rhs.scalar();
453 if (rhs == m)
454 return
455 (m < 0)
456 ? traits_t::NaN()
457 : (m == 0)
458 ? Scalar_T(1)
459 : Scalar_T(0);
460 else
461 return Scalar_T(0);
462 }
463 return exp(log(lhs) * rhs);
464 }
465
467 template< template<typename, const index_t, const index_t, typename> class Multivector,
468 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
469 auto
470 outer_pow(const Multivector<Scalar_T,LO,HI,Tune_P>& lhs, int rhs) -> const Multivector<Scalar_T,LO,HI,Tune_P>
471 { return lhs.outer_pow(rhs); }
472
474 template< template<typename, const index_t, const index_t, typename> class Multivector,
475 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
476 inline
477 auto
478 scalar(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
479 { return val.scalar(); }
480
482 template< template<typename, const index_t, const index_t, typename> class Multivector,
483 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
484 inline
485 auto
486 real(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
487 { return val.scalar(); }
488
490 template
491 <
492 template<typename, const index_t, const index_t, typename> class Multivector,
493 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P
494 >
495 inline
496 auto
497 imag(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
498 { return Scalar_T(0); }
499
501 template< template<typename, const index_t, const index_t, typename> class Multivector,
502 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
503 inline
504 auto
505 pure(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
506 { return val - val.scalar(); }
507
509 template< template<typename, const index_t, const index_t, typename> class Multivector,
510 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
511 inline
512 auto
513 even(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
514 { return val.even(); }
515
517 template< template<typename, const index_t, const index_t, typename> class Multivector,
518 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
519 inline
520 auto
521 odd(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
522 { return val.odd(); }
523
525 template< template<typename, const index_t, const index_t, typename> class Multivector,
526 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
527 inline
528 auto
529 vector_part(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const std::vector<Scalar_T>
530 { return val.vector_part(); }
531
533 template< template<typename, const index_t, const index_t, typename> class Multivector,
534 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
535 inline
536 auto
537 involute(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
538 { return val.involute(); }
539
541 template< template<typename, const index_t, const index_t, typename> class Multivector,
542 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
543 inline
544 auto
545 reverse(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
546 { return val.reverse(); }
547
549 template< template<typename, const index_t, const index_t, typename> class Multivector,
550 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
551 inline
552 auto
553 conj(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
554 { return val.conj(); }
555
557 template< template<typename, const index_t, const index_t, typename> class Multivector,
558 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
559 inline
560 auto
561 quad(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
562 { return val.quad(); }
563
565 template< template<typename, const index_t, const index_t, typename> class Multivector,
566 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
567 inline
568 auto
569 norm(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
570 { return val.norm(); }
571
573 template< template<typename, const index_t, const index_t, typename> class Multivector,
574 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
575 inline
576 auto
577 abs(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
578 { return numeric_traits<Scalar_T>::sqrt(val.norm()); }
579
581 template< template<typename, const index_t, const index_t, typename> class Multivector,
582 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
583 inline
584 auto
585 max_abs(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> Scalar_T
586 { return val.max_abs(); }
587
589 template< template<typename, const index_t, const index_t, typename> class Multivector,
590 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
591 auto
592 complexifier(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
593 {
594 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
595 using traits_t = numeric_traits<Scalar_T>;
596
597 auto frm = val.frame();
598 using array_t = std::array<index_t, 4>;
599 auto incp = array_t{0, 2, 1, 0};
600 auto incq = array_t{1, 0, 0, 0};
601 auto bott = pos_mod((frm.count_pos() - frm.count_neg()), 4);
602 for (auto
603 k = index_t(0);
604 k != incp[bott];
605 k++)
606 for (auto
607 idx = index_t(1);
608 idx != HI+1;
609 ++idx)
610 if (!frm[idx])
611 {
612 frm.set(idx);
613 break;
614 }
615 for (auto
616 k = index_t(0);
617 k != incq[bott];
618 k++)
619 for (auto
620 idx = index_t(-1);
621 idx != LO-1;
622 --idx)
623 if (!frm[idx])
624 {
625 frm.set(idx);
626 break;
627 }
628 auto new_bott = pos_mod(frm.count_pos() - frm.count_neg(), 4);
629
630 if ((incp[new_bott] == 0) && (incq[new_bott] == 0))
631 return multivector_t(frm, Scalar_T(1));
632 else
633 // Return IEEE NaN or -Inf
634 return traits_t::NaN();
635 }
636
639 template< template<typename, const index_t, const index_t, typename> class Multivector,
640 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
641 inline
642 auto
643 elliptic(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
644 { return complexifier(val); }
645
647 template< template<typename, const index_t, const index_t, typename> class Multivector,
648 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
649 inline
650 static
651 void
652 check_complex(const Multivector<Scalar_T,LO,HI,Tune_P>& val,
653 const Multivector<Scalar_T,LO,HI,Tune_P>& i, const bool prechecked = false)
654 {
655 if (!prechecked)
656 {
657 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
658 using index_set_t = typename multivector_t::index_set_t;
659 using error_t = typename multivector_t::error_t;
660
661 const auto i_frame = i.frame();
662 // We need i to be a complexifier whose frame is large enough to represent val
663 if (complexifier(i) != i ||
664 (val.frame() | i_frame) != i_frame ||
665 complexifier(val).frame().count() > i_frame.count())
666 throw error_t("check_complex(val, i): i is not a valid complexifier for val");
667 }
668 }
669
671 template< template<typename, const index_t, const index_t, typename> class Multivector,
672 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
673 inline
674 auto
675 sqrt(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
676 { return sqrt(val, i, prechecked); }
677
679 template< template<typename, const index_t, const index_t, typename> class Multivector,
680 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
681 inline
682 auto
683 sqrt(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
684 { return sqrt(val, complexifier(val), true); }
685
687 template< template<typename, const index_t, const index_t, typename> class Multivector,
688 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
689 auto
690 clifford_exp(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
691 {
692 // Scaling and squaring Pade' approximation of matrix exponential
693 // Reference: [GL], Section 11.3, p572-576
694 // Reference: [H]
695
696 using traits_t = numeric_traits<Scalar_T>;
697
698 const auto scalar_val = val.scalar();
699 const auto scalar_exp = traits_t::exp(scalar_val);
700 if (traits_t::isNaN_or_isInf(scalar_exp))
701 return traits_t::NaN();
702 if (val == scalar_val)
703 return scalar_exp;
704
705 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
706 auto A = val - scalar_val;
707 const auto pure_scale2 = A.norm();
708
709 if (traits_t::isNaN_or_isInf(pure_scale2))
710 return traits_t::NaN();
711 if (pure_scale2 == Scalar_T(0))
712 return scalar_exp;
713
714 const auto ilog2_scale =
715 std::max(0, traits_t::to_int(ceil((log2(pure_scale2) + Scalar_T(A.frame().count()))/Scalar_T(2))) - 3);
716 const auto i_scale = traits_t::pow(Scalar_T(2), ilog2_scale);
717 if (traits_t::isNaN_or_isInf(i_scale))
718 return traits_t::NaN();
719
720 A /= i_scale;
721 multivector_t pure_exp;
722 {
723 using limits_t = std::numeric_limits<Scalar_T>;
724 const auto nbr_even_powers = 2*(limits_t::digits / 32) + 4;
725 using nbr_t = decltype(nbr_even_powers);
726
727 // Create an array of coefficients
728 const auto max_power = 2*nbr_even_powers + 1;
729 static std::array<Scalar_T, max_power+1> c;
730 if (c[0] != Scalar_T(1))
731 {
732 c[0] = Scalar_T(1);
733 for (auto
734 k = decltype(max_power)(0);
735 k != max_power;
736 ++k)
737 c[k+1] = c[k]*(max_power-k) / ((2*max_power-k)*(k+1));
738 }
739
740 // Create an array of even powers
741 std::array<multivector_t, nbr_even_powers> AA;
742 AA[0] = A * A;
743 AA[1] = AA[0] * AA[0];
744 for (auto
745 k = nbr_t(2);
746 k != nbr_even_powers;
747 ++k)
748 AA[k] = AA[k-2] * AA[1];
749
750 // Use compensated summation to calculate U and AV
751 auto residual = multivector_t();
752 auto U = multivector_t(c[0]);
753 for (auto
754 k = nbr_t(0);
755 k != nbr_even_powers;
756 ++k)
757 {
758 const auto& term = AA[k]*c[2*k + 2] - residual;
759 const auto& sum = U + term;
760 residual = (sum - U) - term;
761 U = sum;
762 }
763 residual = multivector_t();
764 auto AV = multivector_t(c[1]);
765 for (auto
766 k = nbr_t(0);
767 k != nbr_even_powers;
768 ++k)
769 {
770 const auto& term = AA[k]*c[2*k + 3] - residual;
771 const auto& sum = AV + term;
772 residual = (sum - AV) - term;
773 AV = sum;
774 }
775 AV *= A;
776 pure_exp = (U+AV) / (U-AV);
777 }
778 for (auto
779 k = decltype(ilog2_scale)(0);
780 k != ilog2_scale;
781 ++k)
782 pure_exp *= pure_exp;
783 return pure_exp * scalar_exp;
784 }
785
787 template< template<typename, const index_t, const index_t, typename> class Multivector,
788 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
789 inline
790 auto
791 log(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
792 { return log(val, i, prechecked); }
793
795 template< template<typename, const index_t, const index_t, typename> class Multivector,
796 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
797 inline
798 auto
799 log(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
800 { return log(val, complexifier(val), true); }
801
803 template< template<typename, const index_t, const index_t, typename> class Multivector,
804 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
805 inline
806 auto
807 cosh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
808 {
809 using traits_t = numeric_traits<Scalar_T>;
810 if (val.isnan())
811 return traits_t::NaN();
812
813 const auto& s = val.scalar();
814 if (val == s)
815 return traits_t::cosh(s);
816 return (exp(val)+exp(-val)) / Scalar_T(2);
817 }
818
820 // Reference: [AS], Section 4.6, p86-89
821 template< template<typename, const index_t, const index_t, typename> class Multivector,
822 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
823 inline
824 auto
825 acosh(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
826 {
827 using traits_t = numeric_traits<Scalar_T>;
828 check_complex(val, i, prechecked);
829 if (val.isnan())
830 return traits_t::NaN();
831
832 const auto radical = sqrt(val*val - Scalar_T(1), i, true);
833 return (norm(val + radical) >= norm(val))
834 ? log(val + radical, i, true)
835 : -log(val - radical, i, true);
836 }
837
839 // Reference: [AS], Section 4.6, p86-89
840 template< template<typename, const index_t, const index_t, typename> class Multivector,
841 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
842 inline
843 auto
844 acosh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
845 { return acosh(val, complexifier(val), true); }
846
848 template< template<typename, const index_t, const index_t, typename> class Multivector,
849 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
850 auto
851 cos(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
852 {
853 using traits_t = numeric_traits<Scalar_T>;
854 if (val.isnan())
855 return traits_t::NaN();
856
857 const auto& s = val.scalar();
858 if (val == s)
859 return traits_t::cos(s);
860
861 check_complex(val, i, prechecked);
862
863 static const auto& twopi = Scalar_T(2) * traits_t::pi();
864 const auto& z = i *
865 (val - s + traits_t::fmod(s, twopi));
866 return (exp(z)+exp(-z)) / Scalar_T(2);
867 }
868
870 template< template<typename, const index_t, const index_t, typename> class Multivector,
871 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
872 inline
873 auto
874 cos(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
875 { return cos(val, complexifier(val), true); }
876
878 // Reference: [AS], Section 4.4, p79-83
879 template< template<typename, const index_t, const index_t, typename> class Multivector,
880 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
881 inline
882 auto
883 acos(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
884 {
885 using traits_t = numeric_traits<Scalar_T>;
886 if (val.isnan())
887 return traits_t::NaN();
888
889 const auto& s = val.scalar();
890 if (val == s && traits_t::abs(s) <= Scalar_T(1))
891 return traits_t::acos(s);
892
893 check_complex(val, i, prechecked);
894 return i * acosh(val, i, true);
895 }
896
898 // Reference: [AS], Section 4.4, p79-83
899 template< template<typename, const index_t, const index_t, typename> class Multivector,
900 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
901 inline
902 auto
903 acos(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
904 { return acos(val, complexifier(val), true); }
905
907 template< template<typename, const index_t, const index_t, typename> class Multivector,
908 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
909 inline
910 auto
911 sinh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
912 {
913 using traits_t = numeric_traits<Scalar_T>;
914 if (val.isnan())
915 return traits_t::NaN();
916
917 const auto& s = val.scalar();
918 if (val == s)
919 return traits_t::sinh(s);
920
921 return (exp(val)-exp(-val)) / Scalar_T(2);
922 }
923
925 // Reference: [AS], Section 4.6, p86-89
926 template< template<typename, const index_t, const index_t, typename> class Multivector,
927 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
928 inline
929 auto
930 asinh(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
931 {
932 using traits_t = numeric_traits<Scalar_T>;
933 check_complex(val, i, prechecked);
934 if (val.isnan())
935 return traits_t::NaN();
936
937 const auto radical = sqrt(val*val + Scalar_T(1), i, true);
938 return (norm(val + radical) >= norm(val))
939 ? log( val + radical, i, true)
940 : -log(-val + radical, i, true);
941 }
942
944 // Reference: [AS], Section 4.6, p86-89
945 template< template<typename, const index_t, const index_t, typename> class Multivector,
946 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
947 inline
948 auto
949 asinh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
950 { return asinh(val, complexifier(val), true); }
951
953 template< template<typename, const index_t, const index_t, typename> class Multivector,
954 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
955 auto
956 sin(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
957 {
958 using traits_t = numeric_traits<Scalar_T>;
959 if (val.isnan())
960 return traits_t::NaN();
961
962 const auto& s = val.scalar();
963 if (val == s)
964 return traits_t::sin(s);
965
966 check_complex(val, i, prechecked);
967
968 static const auto& twopi = Scalar_T(2) * traits_t::pi();
969 const auto& z = i *
970 (val - s + traits_t::fmod(s, twopi));
971 return i * (exp(-z)-exp(z)) / Scalar_T(2);
972 }
973
975 template< template<typename, const index_t, const index_t, typename> class Multivector,
976 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
977 inline
978 auto
979 sin(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
980 { return sin(val, complexifier(val), true); }
981
983 // Reference: [AS], Section 4.4, p79-83
984 template< template<typename, const index_t, const index_t, typename> class Multivector,
985 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
986 inline
987 auto
988 asin(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
989 {
990 using traits_t = numeric_traits<Scalar_T>;
991 if (val.isnan())
992 return traits_t::NaN();
993
994 const auto& s = val.scalar();
995 if (val == s && traits_t::abs(s) <= Scalar_T(1))
996 return traits_t::asin(s);
997
998 check_complex(val, i, prechecked);
999 return -i * asinh(i * val, i, true);
1000 }
1001
1003 // Reference: [AS], Section 4.4, p79-83
1004 template< template<typename, const index_t, const index_t, typename> class Multivector,
1005 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1006 inline
1007 auto
1008 asin(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1009 { return asin(val, complexifier(val), true); }
1010
1012 template< template<typename, const index_t, const index_t, typename> class Multivector,
1013 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1014 inline
1015 auto
1016 tanh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1017 {
1018 using traits_t = numeric_traits<Scalar_T>;
1019 if (val.isnan())
1020 return traits_t::NaN();
1021
1022 const auto& s = val.scalar();
1023 if (val == s)
1024 return traits_t::tanh(s);
1025
1026 return sinh(val) / cosh(val);
1027 }
1028
1030 // Reference: [AS], Section 4.6, p86-89
1031 template< template<typename, const index_t, const index_t, typename> class Multivector,
1032 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1033 inline
1034 auto
1035 atanh(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1036 {
1037 using traits_t = numeric_traits<Scalar_T>;
1038 check_complex(val, i, prechecked);
1039 return val.isnan()
1040 ? traits_t::NaN()
1041 : (norm(val + Scalar_T(1)) > norm(val - Scalar_T(1)))
1042 ? (log(val + Scalar_T(1), i, true) - log(-val + Scalar_T(1), i, true)) / Scalar_T(2)
1043 : log((val + Scalar_T(1)) / (-val + Scalar_T(1)), i, true) / Scalar_T(2);
1044 }
1045
1047 // Reference: [AS], Section 4.6, p86-89
1048 template< template<typename, const index_t, const index_t, typename> class Multivector,
1049 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1050 inline
1051 auto
1052 atanh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1053 { return atanh(val, complexifier(val), true); }
1054
1056 template< template<typename, const index_t, const index_t, typename> class Multivector,
1057 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1058 inline
1059 auto
1060 tan(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1061 {
1062 using traits_t = numeric_traits<Scalar_T>;
1063 if (val.isnan())
1064 return traits_t::NaN();
1065
1066 const auto& s = val.scalar();
1067 if (val == s)
1068 return traits_t::tan(s);
1069
1070 check_complex(val, i, prechecked);
1071 return sin(val, i, true) / cos(val, i, true);
1072 }
1073
1075 template< template<typename, const index_t, const index_t, typename> class Multivector,
1076 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1077 inline
1078 auto
1079 tan(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1080 { return tan(val, complexifier(val), true); }
1081
1083 // Reference: [AS], Section 4.4, p79-83
1084 template< template<typename, const index_t, const index_t, typename> class Multivector,
1085 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1086 inline
1087 auto
1088 atan(const Multivector<Scalar_T,LO,HI,Tune_P>& val, const Multivector<Scalar_T,LO,HI,Tune_P>& i, bool prechecked) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1089 {
1090 using traits_t = numeric_traits<Scalar_T>;
1091 if (val.isnan())
1092 return traits_t::NaN();
1093
1094 const auto& s = val.scalar();
1095 if (val == s)
1096 return traits_t::atan(s);
1097
1098 check_complex(val, i, prechecked);
1099 return -i * atanh(i * val, i, true);
1100 }
1101
1103 // Reference: [AS], Section 4.4, p79-83
1104 template< template<typename, const index_t, const index_t, typename> class Multivector,
1105 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1106 inline
1107 auto
1108 atan(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1109 { return atan(val, complexifier(val), true); }
1110
1111}
1112#endif // _GLUCAT_CLIFFORD_ALGEBRA_IMP_H
clifford_algebra<> declares the operations of a Clifford algebra
static auto classname() -> const std::string
Extra traits which extend numeric limits.
Definition scalar.h:48
static auto sqrt(const Scalar_T &val) -> Scalar_T
Square root of scalar.
Definition scalar.h:210
static auto pow(const Scalar_T &val, int n) -> Scalar_T
Integer power.
Definition scalar.h:203
auto operator|(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Transformation via twisted adjoint action.
auto even(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Even part.
auto operator*(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const Scalar_T &scr) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Product of multivector and scalar.
auto operator&(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inner product.
auto exp(const framed_multi< Scalar_T, LO, HI, Tune_P > &val) -> const framed_multi< Scalar_T, LO, HI, Tune_P >
Exponential of multivector.
auto cosh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic cosine of multivector.
auto scalar(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar part.
auto tanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic tangent of multivector.
auto approx_equal(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs, const Scalar_T threshold, const Scalar_T tolerance) -> bool
Test for approximate equality of multivectors.
auto tan(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Tangent of multivector with specified complexifier.
auto error_squared(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs, const Scalar_T threshold) -> Scalar_T
Relative or absolute error using the quadratic norm.
auto elliptic(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
auto sinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic sine of multivector.
auto imag(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Imaginary part: deprecated (always 0)
static void check_complex(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false)
Check that i is a valid complexifier for val.
auto involute(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Main involution, each {i} is replaced by -{i} in each term, eg. {1}*{2} -> (-{2})*(-{1}...
auto operator+(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const Scalar_T &scr) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Geometric sum of multivector and scalar.
auto conj(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Conjugation, rev o invo == invo o rev.
auto operator%(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Left contraction.
auto sin(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Sine of multivector with specified complexifier.
auto pos_mod(LHS_T lhs, RHS_T rhs) -> LHS_T
Modulo function which works reliably for lhs < 0.
Definition global.h:117
auto outer_pow(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, int rhs) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Outer product power of multivector.
auto pow(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, int rhs) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Integer power of multivector.
auto abs(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Absolute value == sqrt(norm)
auto inv(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Geometric multiplicative inverse.
auto asinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic sine of multivector with specified complexifier.
auto pure(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Pure part.
auto atanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic tangent of multivector with specified complexifier.
auto atan(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse tangent of multivector with specified complexifier.
auto log2(const Scalar_T &x) -> Scalar_T
Log base 2 of scalar.
Definition scalar.h:303
int index_t
Size of index_t should be enough to represent LO, HI.
Definition global.h:77
auto clifford_exp(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Exponential of multivector.
auto cos(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Cosine of multivector with specified complexifier.
auto operator/(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const Scalar_T &scr) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Quotient of multivector and scalar.
auto log(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Natural logarithm of multivector with specified complexifier.
auto asin(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse sine of multivector with specified complexifier.
auto real(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Real part: synonym for scalar part.
auto acosh(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic cosine of multivector with specified complexifier.
auto norm(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar_T norm == sum of norm of coordinates.
auto error_squared_tol(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Quadratic norm error tolerance relative to a specific multivector.
auto star(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> Scalar_T
Hestenes scalar product.
auto operator^(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Outer product.
auto max_abs(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Maximum of absolute values of components of multivector: multivector infinity norm.
auto sqrt(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Square root of multivector with specified complexifier.
auto reverse(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Reversion, eg. {1}*{2} -> {2}*{1}.
auto complexifier(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Square root of -1 which commutes with all members of the frame of the given multivector.
auto odd(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Odd part.
auto vector_part(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const std::vector< Scalar_T >
Vector part of multivector, as a vector_t with respect to frame()
auto quad(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar_T quadratic form == (rev(x)*x)(0)
auto operator-(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const Scalar_T &scr) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Geometric difference of multivector and scalar.
auto acos(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse cosine of multivector with specified complexifier.
auto operator!=(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> bool
Test for inequality of multivectors.