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
56 
58 #include "glucat/scalar.h"
59 
60 #include <array>
61 
62 namespace 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
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 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 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 exp(const framed_multi< Scalar_T, LO, HI, Tune_P > &val) -> const framed_multi< Scalar_T, LO, HI, Tune_P >
Exponential of multivector.
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.
auto odd(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Odd part.
clifford_algebra<> declares the operations of a Clifford algebra
float pi
Definition: PyClical.pyx:1907
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 elliptic(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
auto norm(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar_T norm == sum of norm of coordinates.
auto scalar(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar part.
Extra traits which extend numeric limits.
Definition: scalar.h:47
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 pos_mod(LHS_T lhs, RHS_T rhs) -> LHS_T
Modulo function which works reliably for lhs < 0.
Definition: global.h:117
auto even(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Even part.
static auto pow(const Scalar_T &val, int n) -> Scalar_T
Integer power.
Definition: scalar.h:203
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 clifford_exp(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Exponential of multivector.
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 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.
const scalar_t epsilon
Definition: PyClical.h:150
auto sinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic sine 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.
static auto classname() -> const std::string
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 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 tanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic tangent of multivector.
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 error_squared_tol(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Quadratic norm error tolerance relative to a specific multivector.
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 pure(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Pure part.
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 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 log2(const Scalar_T &x) -> Scalar_T
Log base 2 of scalar.
Definition: scalar.h:303
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 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 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 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 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 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.
int index_t
Size of index_t should be enough to represent LO, HI.
Definition: global.h:77
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 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.
static auto sqrt(const Scalar_T &val) -> Scalar_T
Square root of scalar.
Definition: scalar.h:210
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 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 real(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Real part: synonym for scalar part.
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 cosh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic cosine of multivector.
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 imag(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Imaginary part: deprecated (always 0)
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 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 quad(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar_T quadratic form == (rev(x)*x)(0)
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) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Transformation via twisted adjoint action.