glucat 0.13.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 error_t = typename multivector_t::error_t;
659
660 const auto i_frame = i.frame();
661 // We need i to be a complexifier whose frame is large enough to represent val
662 if (complexifier(i) != i ||
663 (val.frame() | i_frame) != i_frame ||
664 complexifier(val).frame().count() > i_frame.count())
665 throw error_t("check_complex(val, i): i is not a valid complexifier for val");
666 }
667 }
668
670 template< template<typename, const index_t, const index_t, typename> class Multivector,
671 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
672 inline
673 auto
674 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>
675 { return sqrt(val, i, prechecked); }
676
678 template< template<typename, const index_t, const index_t, typename> class Multivector,
679 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
680 inline
681 auto
682 sqrt(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
683 { return sqrt(val, complexifier(val), true); }
684
686 template< template<typename, const index_t, const index_t, typename> class Multivector,
687 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
688 auto
689 clifford_exp(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
690 {
691 // Scaling and squaring Pade' approximation of matrix exponential
692 // Reference: [GL], Section 11.3, p572-576
693 // Reference: [H]
694
695 using traits_t = numeric_traits<Scalar_T>;
696
697 const auto scalar_val = val.scalar();
698 const auto scalar_exp = traits_t::exp(scalar_val);
699 if (traits_t::isNaN_or_isInf(scalar_exp))
700 return traits_t::NaN();
701 if (val == scalar_val)
702 return scalar_exp;
703
704 using multivector_t = Multivector<Scalar_T,LO,HI,Tune_P>;
705 auto A = val - scalar_val;
706 const auto pure_scale2 = A.norm();
707
708 if (traits_t::isNaN_or_isInf(pure_scale2))
709 return traits_t::NaN();
710 if (pure_scale2 == Scalar_T(0))
711 return scalar_exp;
712
713 const auto ilog2_scale =
714 std::max(0, traits_t::to_int(ceil((log2(pure_scale2) + Scalar_T(A.frame().count()))/Scalar_T(2))) - 3);
715 const auto i_scale = traits_t::pow(Scalar_T(2), ilog2_scale);
716 if (traits_t::isNaN_or_isInf(i_scale))
717 return traits_t::NaN();
718
719 A /= i_scale;
720 multivector_t pure_exp;
721 {
722 using limits_t = std::numeric_limits<Scalar_T>;
723 const auto nbr_even_powers = 2*(limits_t::digits / 32) + 4;
724 using nbr_t = decltype(nbr_even_powers);
725
726 // Create an array of coefficients
727 const auto max_power = 2*nbr_even_powers + 1;
728 static std::array<Scalar_T, max_power+1> c;
729 if (c[0] != Scalar_T(1))
730 {
731 c[0] = Scalar_T(1);
732 for (auto
733 k = decltype(max_power)(0);
734 k != max_power;
735 ++k)
736 c[k+1] = c[k]*(max_power-k) / ((2*max_power-k)*(k+1));
737 }
738
739 // Create an array of even powers
740 std::array<multivector_t, nbr_even_powers> AA;
741 AA[0] = A * A;
742 AA[1] = AA[0] * AA[0];
743 for (auto
744 k = nbr_t(2);
745 k != nbr_even_powers;
746 ++k)
747 AA[k] = AA[k-2] * AA[1];
748
749 // Use compensated summation to calculate U and AV
750 auto residual = multivector_t();
751 auto U = multivector_t(c[0]);
752 for (auto
753 k = nbr_t(0);
754 k != nbr_even_powers;
755 ++k)
756 {
757 const auto& term = AA[k]*c[2*k + 2] - residual;
758 const auto& sum = U + term;
759 residual = (sum - U) - term;
760 U = sum;
761 }
762 residual = multivector_t();
763 auto AV = multivector_t(c[1]);
764 for (auto
765 k = nbr_t(0);
766 k != nbr_even_powers;
767 ++k)
768 {
769 const auto& term = AA[k]*c[2*k + 3] - residual;
770 const auto& sum = AV + term;
771 residual = (sum - AV) - term;
772 AV = sum;
773 }
774 AV *= A;
775 pure_exp = (U+AV) / (U-AV);
776 }
777 for (auto
778 k = decltype(ilog2_scale)(0);
779 k != ilog2_scale;
780 ++k)
781 pure_exp *= pure_exp;
782 return pure_exp * scalar_exp;
783 }
784
786 template< template<typename, const index_t, const index_t, typename> class Multivector,
787 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
788 inline
789 auto
790 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>
791 { return log(val, i, prechecked); }
792
794 template< template<typename, const index_t, const index_t, typename> class Multivector,
795 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
796 inline
797 auto
798 log(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
799 { return log(val, complexifier(val), true); }
800
802 template< template<typename, const index_t, const index_t, typename> class Multivector,
803 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
804 inline
805 auto
806 cosh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
807 {
808 using traits_t = numeric_traits<Scalar_T>;
809 if (val.isnan())
810 return traits_t::NaN();
811
812 const auto& s = val.scalar();
813 if (val == s)
814 return traits_t::cosh(s);
815 return (exp(val)+exp(-val)) / Scalar_T(2);
816 }
817
819 // Reference: [AS], Section 4.6, p86-89
820 template< template<typename, const index_t, const index_t, typename> class Multivector,
821 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
822 inline
823 auto
824 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>
825 {
826 using traits_t = numeric_traits<Scalar_T>;
827 check_complex(val, i, prechecked);
828 if (val.isnan())
829 return traits_t::NaN();
830
831 const auto radical = sqrt(val*val - Scalar_T(1), i, true);
832 return (norm(val + radical) >= norm(val))
833 ? log(val + radical, i, true)
834 : -log(val - radical, i, true);
835 }
836
838 // Reference: [AS], Section 4.6, p86-89
839 template< template<typename, const index_t, const index_t, typename> class Multivector,
840 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
841 inline
842 auto
843 acosh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
844 { return acosh(val, complexifier(val), true); }
845
847 template< template<typename, const index_t, const index_t, typename> class Multivector,
848 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
849 auto
850 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>
851 {
852 using traits_t = numeric_traits<Scalar_T>;
853 if (val.isnan())
854 return traits_t::NaN();
855
856 const auto& s = val.scalar();
857 if (val == s)
858 return traits_t::cos(s);
859
860 check_complex(val, i, prechecked);
861
862 static const auto& twopi = Scalar_T(2) * traits_t::pi();
863 const auto& z = i *
864 (val - s + traits_t::fmod(s, twopi));
865 return (exp(z)+exp(-z)) / Scalar_T(2);
866 }
867
869 template< template<typename, const index_t, const index_t, typename> class Multivector,
870 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
871 inline
872 auto
873 cos(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
874 { return cos(val, complexifier(val), true); }
875
877 // Reference: [AS], Section 4.4, p79-83
878 template< template<typename, const index_t, const index_t, typename> class Multivector,
879 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
880 inline
881 auto
882 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>
883 {
884 using traits_t = numeric_traits<Scalar_T>;
885 if (val.isnan())
886 return traits_t::NaN();
887
888 const auto& s = val.scalar();
889 if (val == s && traits_t::abs(s) <= Scalar_T(1))
890 return traits_t::acos(s);
891
892 check_complex(val, i, prechecked);
893 return i * acosh(val, i, true);
894 }
895
897 // Reference: [AS], Section 4.4, p79-83
898 template< template<typename, const index_t, const index_t, typename> class Multivector,
899 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
900 inline
901 auto
902 acos(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
903 { return acos(val, complexifier(val), true); }
904
906 template< template<typename, const index_t, const index_t, typename> class Multivector,
907 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
908 inline
909 auto
910 sinh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
911 {
912 using traits_t = numeric_traits<Scalar_T>;
913 if (val.isnan())
914 return traits_t::NaN();
915
916 const auto& s = val.scalar();
917 if (val == s)
918 return traits_t::sinh(s);
919
920 return (exp(val)-exp(-val)) / Scalar_T(2);
921 }
922
924 // Reference: [AS], Section 4.6, p86-89
925 template< template<typename, const index_t, const index_t, typename> class Multivector,
926 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
927 inline
928 auto
929 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>
930 {
931 using traits_t = numeric_traits<Scalar_T>;
932 check_complex(val, i, prechecked);
933 if (val.isnan())
934 return traits_t::NaN();
935
936 const auto radical = sqrt(val*val + Scalar_T(1), i, true);
937 return (norm(val + radical) >= norm(val))
938 ? log( val + radical, i, true)
939 : -log(-val + radical, i, true);
940 }
941
943 // Reference: [AS], Section 4.6, p86-89
944 template< template<typename, const index_t, const index_t, typename> class Multivector,
945 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
946 inline
947 auto
948 asinh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
949 { return asinh(val, complexifier(val), true); }
950
952 template< template<typename, const index_t, const index_t, typename> class Multivector,
953 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
954 auto
955 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>
956 {
957 using traits_t = numeric_traits<Scalar_T>;
958 if (val.isnan())
959 return traits_t::NaN();
960
961 const auto& s = val.scalar();
962 if (val == s)
963 return traits_t::sin(s);
964
965 check_complex(val, i, prechecked);
966
967 static const auto& twopi = Scalar_T(2) * traits_t::pi();
968 const auto& z = i *
969 (val - s + traits_t::fmod(s, twopi));
970 return i * (exp(-z)-exp(z)) / Scalar_T(2);
971 }
972
974 template< template<typename, const index_t, const index_t, typename> class Multivector,
975 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
976 inline
977 auto
978 sin(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
979 { return sin(val, complexifier(val), true); }
980
982 // Reference: [AS], Section 4.4, p79-83
983 template< template<typename, const index_t, const index_t, typename> class Multivector,
984 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
985 inline
986 auto
987 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>
988 {
989 using traits_t = numeric_traits<Scalar_T>;
990 if (val.isnan())
991 return traits_t::NaN();
992
993 const auto& s = val.scalar();
994 if (val == s && traits_t::abs(s) <= Scalar_T(1))
995 return traits_t::asin(s);
996
997 check_complex(val, i, prechecked);
998 return -i * asinh(i * val, i, true);
999 }
1000
1002 // Reference: [AS], Section 4.4, p79-83
1003 template< template<typename, const index_t, const index_t, typename> class Multivector,
1004 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1005 inline
1006 auto
1007 asin(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1008 { return asin(val, complexifier(val), true); }
1009
1011 template< template<typename, const index_t, const index_t, typename> class Multivector,
1012 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1013 inline
1014 auto
1015 tanh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1016 {
1017 using traits_t = numeric_traits<Scalar_T>;
1018 if (val.isnan())
1019 return traits_t::NaN();
1020
1021 const auto& s = val.scalar();
1022 if (val == s)
1023 return traits_t::tanh(s);
1024
1025 return sinh(val) / cosh(val);
1026 }
1027
1029 // Reference: [AS], Section 4.6, p86-89
1030 template< template<typename, const index_t, const index_t, typename> class Multivector,
1031 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1032 inline
1033 auto
1034 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>
1035 {
1036 using traits_t = numeric_traits<Scalar_T>;
1037 check_complex(val, i, prechecked);
1038 return val.isnan()
1039 ? traits_t::NaN()
1040 : (norm(val + Scalar_T(1)) > norm(val - Scalar_T(1)))
1041 ? (log(val + Scalar_T(1), i, true) - log(-val + Scalar_T(1), i, true)) / Scalar_T(2)
1042 : log((val + Scalar_T(1)) / (-val + Scalar_T(1)), i, true) / Scalar_T(2);
1043 }
1044
1046 // Reference: [AS], Section 4.6, p86-89
1047 template< template<typename, const index_t, const index_t, typename> class Multivector,
1048 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1049 inline
1050 auto
1051 atanh(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1052 { return atanh(val, complexifier(val), true); }
1053
1055 template< template<typename, const index_t, const index_t, typename> class Multivector,
1056 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1057 inline
1058 auto
1059 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>
1060 {
1061 using traits_t = numeric_traits<Scalar_T>;
1062 if (val.isnan())
1063 return traits_t::NaN();
1064
1065 const auto& s = val.scalar();
1066 if (val == s)
1067 return traits_t::tan(s);
1068
1069 check_complex(val, i, prechecked);
1070 return sin(val, i, true) / cos(val, i, true);
1071 }
1072
1074 template< template<typename, const index_t, const index_t, typename> class Multivector,
1075 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1076 inline
1077 auto
1078 tan(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1079 { return tan(val, complexifier(val), true); }
1080
1082 // Reference: [AS], Section 4.4, p79-83
1083 template< template<typename, const index_t, const index_t, typename> class Multivector,
1084 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1085 inline
1086 auto
1087 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>
1088 {
1089 using traits_t = numeric_traits<Scalar_T>;
1090 if (val.isnan())
1091 return traits_t::NaN();
1092
1093 const auto& s = val.scalar();
1094 if (val == s)
1095 return traits_t::atan(s);
1096
1097 check_complex(val, i, prechecked);
1098 return -i * atanh(i * val, i, true);
1099 }
1100
1102 // Reference: [AS], Section 4.4, p79-83
1103 template< template<typename, const index_t, const index_t, typename> class Multivector,
1104 typename Scalar_T, const index_t LO, const index_t HI, typename Tune_P >
1105 inline
1106 auto
1107 atan(const Multivector<Scalar_T,LO,HI,Tune_P>& val) -> const Multivector<Scalar_T,LO,HI,Tune_P>
1108 { return atan(val, complexifier(val), true); }
1109
1110}
1111#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.