glucat  0.12.0
PyClical.pyx
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 # cython: language_level=3
3 # distutils: language = c++
4 #
5 # PyClical: Python interface to GluCat:
6 # Generic library of universal Clifford algebra templates
7 #
8 # PyClical.pyx: Cython definitions visible from Python.
9 #
10 # copyright : (C) 2008-2021 by Paul C. Leopardi
11 #
12 # This library is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU Lesser General Public License as published
14 # by the Free Software Foundation, either version 3 of the License, or
15 # (at your option) any later version.
16 #
17 # This library is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU Lesser General Public License for more details.
21 #
22 # You should have received a copy of the GNU Lesser General Public License
23 # along with this library. If not, see <http://www.gnu.org/licenses/>.
24 
25 # References for definitions:
26 # [DL]:
27 # C. Doran and A. Lasenby, "Geometric algebra for physicists", Cambridge, 2003.
28 
29 import math
30 import numbers
31 import collections
32 
33 from PyClical cimport *
34 
35 __version__ = str(glucat_package_version,'utf-8')
36 
37 # Forward reference
38 cdef class index_set
39 
40 cdef inline IndexSet toIndexSet(obj):
41  """
42  Return the C++ IndexSet instance wrapped by index_set(obj).
43  """
44  return index_set(obj).instance[0]
45 
46 cdef class index_set:
47  """
48  Python class index_set wraps C++ class IndexSet.
49  """
50  cdef IndexSet *instance # Wrapped instance of C++ class IndexSet.
51 
52  cdef inline wrap(index_set self, IndexSet other):
53  """
54  Wrap an instance of the C++ class IndexSet.
55  """
56  self.instance[0] = other
57  return self
58 
59  cdef inline IndexSet unwrap(index_set self):
60  """
61  Return the wrapped C++ IndexSet instance.
62  """
63  return self.instance[0]
64 
65  cpdef copy(index_set self):
66  """
67  Copy this index_set object.
68 
69  >>> s=index_set(1); t=s.copy(); print(t)
70  {1}
71  """
72  return index_set(self)
73 
74  def __cinit__(self, other = 0):
75  """
76  Construct an object of type index_set.
77 
78  >>> print(index_set(1))
79  {1}
80  >>> print(index_set({1,2}))
81  {1,2}
82  >>> print(index_set(index_set({1,2})))
83  {1,2}
84  >>> print(index_set({1,2}))
85  {1,2}
86  >>> print(index_set({1,2,1}))
87  {1,2}
88  >>> print(index_set("{1,2,1}"))
89  {1,2}
90  >>> print(index_set(""))
91  {}
92  """
93  error_msg_prefix = "Cannot initialize index_set object from"
94  if isinstance(other, index_set):
95  self.instance = new IndexSet((<index_set>other).unwrap())
96  elif isinstance(other, numbers.Integral):
97  self.instance = new IndexSet(<int>other)
98  elif isinstance(other, (set, frozenset)):
99  try:
100  self.instance = new IndexSet()
101  for idx in other:
102  self[idx] = True
103  except IndexError:
104  raise IndexError(error_msg_prefix + " invalid " + repr(other) + ".")
105  except (RuntimeError, TypeError):
106  raise ValueError(error_msg_prefix + " invalid " + repr(other) + ".")
107  elif isinstance(other, str):
108  try:
109  bother = other.encode("UTF-8")
110  self.instance = new IndexSet(<char *>bother)
111  except RuntimeError:
112  raise ValueError(error_msg_prefix + " invalid string " + repr(other) + ".")
113  else:
114  raise TypeError(error_msg_prefix + " " + str(type(other)) + ".")
115 
116  def __dealloc__(self):
117  """
118  Clean up by deallocating the instance of C++ class IndexSet.
119  """
120  del self.instance
121 
122  def __richcmp__(lhs, rhs, int op):
123  """
124  Compare two objects of class index_set.
125 
126  >>> index_set(1) == index_set({1})
127  True
128  >>> index_set({1}) != index_set({1})
129  False
130  >>> index_set({1}) != index_set({2})
131  True
132  >>> index_set({1}) == index_set({2})
133  False
134  >>> index_set({1}) < index_set({2})
135  True
136  >>> index_set({1}) <= index_set({2})
137  True
138  >>> index_set({1}) > index_set({2})
139  False
140  >>> index_set({1}) >= index_set({2})
141  False
142  """
143  if (lhs is None) or (rhs is None):
144  eq = bool(lhs is rhs)
145  if op == 2: # ==
146  return eq
147  elif op == 3: # !=
148  return not eq
149  else:
150  if op == 0: # <
151  return False
152  elif op == 1: # <=
153  return eq
154  elif op == 4: # >
155  return False
156  elif op == 5: # >=
157  return eq
158  else:
159  return NotImplemented
160  else:
161  eq = bool( toIndexSet(lhs) == toIndexSet(rhs) )
162  if op == 2: # ==
163  return eq
164  elif op == 3: # !=
165  return not eq
166  else:
167  lt = bool( toIndexSet(lhs) < toIndexSet(rhs) )
168  if op == 0: # <
169  return lt
170  elif op == 1: # <=
171  return lt or eq
172  elif op == 4: # >
173  return not (lt or eq)
174  elif op == 5: # >=
175  return not lt
176  else:
177  return NotImplemented
178 
179  def __setitem__(self, idx, val):
180  """
181  Set the value of an index_set object at index idx to value val.
182 
183  >>> s=index_set({1}); s[2] = True; print(s)
184  {1,2}
185  >>> s=index_set({1,2}); s[1] = False; print(s)
186  {2}
187  """
188  self.instance.set(idx, val)
189  return
190 
191  def __getitem__(self, idx):
192  """
193  Get the value of an index_set object at an index.
194 
195  >>> index_set({1})[1]
196  True
197  >>> index_set({1})[2]
198  False
199  >>> index_set({2})[-1]
200  False
201  >>> index_set({2})[1]
202  False
203  >>> index_set({2})[2]
204  True
205  >>> index_set({2})[33]
206  False
207  """
208  return self.instance.getitem(idx)
209 
210  def __contains__(self, idx):
211  """
212  Check that an index_set object contains the index idx: idx in self.
213 
214  >>> 1 in index_set({1})
215  True
216  >>> 2 in index_set({1})
217  False
218  >>> -1 in index_set({2})
219  False
220  >>> 1 in index_set({2})
221  False
222  >>> 2 in index_set({2})
223  True
224  >>> 33 in index_set({2})
225  False
226  """
227  return self.instance.getitem(idx)
228 
229  def __iter__(self):
230  """
231  Iterate over the indices of an index_set.
232 
233  >>> for i in index_set({-3,4,7}):print(i, end=",")
234  -3,4,7,
235  """
236  for idx in range(self.min(), self.max()+1):
237  if idx in self:
238  yield idx
239 
240  def __invert__(self):
241  """
242  Set complement: not.
243 
244  >>> print(~index_set({-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}))
245  {-32,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-21,-20,-19,-18,-17,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32}
246  """
247  return index_set().wrap( self.instance.invert() )
248 
249  def __xor__(lhs, rhs):
250  """
251  Symmetric set difference: exclusive or.
252 
253  >>> print(index_set({1}) ^ index_set({2}))
254  {1,2}
255  >>> print(index_set({1,2}) ^ index_set({2}))
256  {1}
257  """
258  return index_set().wrap( toIndexSet(lhs) ^ toIndexSet(rhs) )
259 
260  def __ixor__(self, rhs):
261  """
262  Symmetric set difference: exclusive or.
263 
264  >>> x = index_set({1}); x ^= index_set({2}); print(x)
265  {1,2}
266  >>> x = index_set({1,2}); x ^= index_set({2}); print(x)
267  {1}
268  """
269  return self.wrap( self.unwrap() ^ toIndexSet(rhs) )
270 
271  def __and__(lhs, rhs):
272  """
273  Set intersection: and.
274 
275  >>> print(index_set({1}) & index_set({2}))
276  {}
277  >>> print(index_set({1,2}) & index_set({2}))
278  {2}
279  """
280  return index_set().wrap( toIndexSet(lhs) & toIndexSet(rhs) )
281 
282  def __iand__(self, rhs):
283  """
284  Set intersection: and.
285 
286  >>> x = index_set({1}); x &= index_set({2}); print(x)
287  {}
288  >>> x = index_set({1,2}); x &= index_set({2}); print(x)
289  {2}
290  """
291  return self.wrap( self.unwrap() & toIndexSet(rhs) )
292 
293  def __or__(lhs, rhs):
294  """
295  Set union: or.
296 
297  >>> print(index_set({1}) | index_set({2}))
298  {1,2}
299  >>> print(index_set({1,2}) | index_set({2}))
300  {1,2}
301  """
302  return index_set().wrap( toIndexSet(lhs) | toIndexSet(rhs) )
303 
304  def __ior__(self, rhs):
305  """
306  Set union: or.
307 
308  >>> x = index_set({1}); x |= index_set({2}); print(x)
309  {1,2}
310  >>> x = index_set({1,2}); x |= index_set({2}); print(x)
311  {1,2}
312  """
313  return self.wrap( self.unwrap() | toIndexSet(rhs) )
314 
315  def count(self):
316  """
317  Cardinality: Number of indices included in set.
318 
319  >>> index_set({-1,1,2}).count()
320  3
321  """
322  return self.instance.count()
323 
324  def count_neg(self):
325  """
326  Number of negative indices included in set.
327 
328  >>> index_set({-1,1,2}).count_neg()
329  1
330  """
331  return self.instance.count_neg()
332 
333  def count_pos(self):
334  """
335  Number of positive indices included in set.
336 
337  >>> index_set({-1,1,2}).count_pos()
338  2
339  """
340  return self.instance.count_pos()
341 
342  def min(self):
343  """
344  Minimum member.
345 
346  >>> index_set({-1,1,2}).min()
347  -1
348  """
349  return self.instance.min()
350 
351  def max(self):
352  """
353  Maximum member.
354 
355  >>> index_set({-1,1,2}).max()
356  2
357  """
358  return self.instance.max()
359 
360  def hash_fn(self):
361  """
362  Hash function.
363  """
364  return self.instance.hash_fn()
365 
366  def sign_of_mult(self, rhs):
367  """
368  Sign of geometric product of two Clifford basis elements.
369 
370  >>> s = index_set({1,2}); t=index_set({-1}); s.sign_of_mult(t)
371  1
372  """
373  return self.instance.sign_of_mult(toIndexSet(rhs))
374 
375  def sign_of_square(self):
376  """
377  Sign of geometric square of a Clifford basis element.
378 
379  >>> s = index_set({1,2}); s.sign_of_square()
380  -1
381  """
382  return self.instance.sign_of_square()
383 
384  def __repr__(self):
385  """
386  The “official” string representation of self.
387 
388  >>> index_set({1,2}).__repr__()
389  'index_set({1,2})'
390  >>> repr(index_set({1,2}))
391  'index_set({1,2})'
392  """
393  return index_set_to_repr( self.unwrap() ).decode()
394 
395  def __str__(self):
396  """
397  The “informal” string representation of self.
398 
399  >>> index_set({1,2}).__str__()
400  '{1,2}'
401  >>> str(index_set({1,2}))
402  '{1,2}'
403  """
404  return index_set_to_str( self.unwrap() ).decode()
405 
407  """
408  Tests for functions that Doctest cannot see.
409 
410  For index_set.__cinit__: Construct index_set.
411 
412  >>> print(index_set(1))
413  {1}
414  >>> print(index_set({1,2}))
415  {1,2}
416  >>> print(index_set(index_set({1,2})))
417  {1,2}
418  >>> print(index_set({1,2}))
419  {1,2}
420  >>> print(index_set({1,2,1}))
421  {1,2}
422  >>> print(index_set({1,2,1}))
423  {1,2}
424  >>> print(index_set(""))
425  {}
426  >>> print(index_set("{"))
427  Traceback (most recent call last):
428  ...
429  ValueError: Cannot initialize index_set object from invalid string '{'.
430  >>> print(index_set("{1"))
431  Traceback (most recent call last):
432  ...
433  ValueError: Cannot initialize index_set object from invalid string '{1'.
434  >>> print(index_set("{1,2,100}"))
435  Traceback (most recent call last):
436  ...
437  ValueError: Cannot initialize index_set object from invalid string '{1,2,100}'.
438  >>> print(index_set({1,2,100}))
439  Traceback (most recent call last):
440  ...
441  IndexError: Cannot initialize index_set object from invalid {1, 2, 100}.
442  >>> print(index_set([1,2]))
443  Traceback (most recent call last):
444  ...
445  TypeError: Cannot initialize index_set object from <class 'list'>.
446 
447  For index_set.__richcmp__: Compare two objects of class index_set.
448 
449  >>> index_set(1) == index_set({1})
450  True
451  >>> index_set({1}) != index_set({1})
452  False
453  >>> index_set({1}) != index_set({2})
454  True
455  >>> index_set({1}) == index_set({2})
456  False
457  >>> index_set({1}) < index_set({2})
458  True
459  >>> index_set({1}) <= index_set({2})
460  True
461  >>> index_set({1}) > index_set({2})
462  False
463  >>> index_set({1}) >= index_set({2})
464  False
465  >>> None == index_set({1,2})
466  False
467  >>> None != index_set({1,2})
468  True
469  >>> None < index_set({1,2})
470  False
471  >>> None <= index_set({1,2})
472  False
473  >>> None > index_set({1,2})
474  False
475  >>> None >= index_set({1,2})
476  False
477  >>> index_set({1,2}) == None
478  False
479  >>> index_set({1,2}) != None
480  True
481  >>> index_set({1,2}) < None
482  False
483  >>> index_set({1,2}) <= None
484  False
485  >>> index_set({1,2}) > None
486  False
487  >>> index_set({1,2}) >= None
488  False
489  """
490  return
491 
492 cpdef inline compare(lhs,rhs):
493  """
494  "lexicographic compare" eg. {3,4,5} is less than {3,7,8};
495  -1 if a<b, +1 if a>b, 0 if a==b.
496 
497  >>> compare(index_set({1,2}),index_set({-1,3}))
498  -1
499  >>> compare(index_set({-1,4}),index_set({-1,3}))
500  1
501  """
502  return glucat.compare( toIndexSet(lhs), toIndexSet(rhs) )
503 
504 cpdef inline min_neg(obj):
505  """
506  Minimum negative index, or 0 if none.
507 
508  >>> min_neg(index_set({1,2}))
509  0
510  """
511  return glucat.min_neg( toIndexSet(obj) )
512 
513 cpdef inline max_pos(obj):
514  """
515  Maximum positive index, or 0 if none.
516 
517  >>> max_pos(index_set({1,2}))
518  2
519  """
520  return glucat.max_pos( toIndexSet(obj) )
521 
522 cdef inline vector[scalar_t] list_to_vector(lst):
523  """
524  Create a C++ std:vector[scalar_t] from an iterable Python object.
525  """
526  cdef vector[scalar_t] v
527  for s in lst:
528  v.push_back(<scalar_t>s)
529  return v
530 
531 # Forward reference.
532 cdef class clifford
533 
534 cdef inline Clifford toClifford(obj):
535  return clifford(obj).instance[0]
536 
537 cdef class clifford:
538  """
539  Python class clifford wraps C++ class Clifford.
540  """
541  cdef Clifford *instance # Wrapped instance of C++ class Clifford.
542 
543  cdef inline wrap(clifford self, Clifford other):
544  """
545  Wrap an instance of the C++ class Clifford.
546  """
547  self.instance[0] = other
548  return self
549 
550  cdef inline Clifford unwrap(clifford self):
551  """
552  Return the wrapped C++ Clifford instance.
553  """
554  return self.instance[0]
555 
556  cpdef copy(clifford self):
557  """
558  Copy this clifford object.
559 
560  >>> x=clifford("1{2}"); y=x.copy(); print(y)
561  {2}
562  """
563  return clifford(self)
564 
565  def __cinit__(self, other = 0, ixt = None):
566  """
567  Construct an object of type clifford.
568 
569  >>> print(clifford(2))
570  2
571  >>> print(clifford(2.0))
572  2
573  >>> print(clifford(1.0e-1))
574  0.1
575  >>> print(clifford("2"))
576  2
577  >>> print(clifford("2{1,2,3}"))
578  2{1,2,3}
579  >>> print(clifford(clifford("2{1,2,3}")))
580  2{1,2,3}
581  >>> print(clifford("-{1}"))
582  -{1}
583  >>> print(clifford(2,index_set({1,2})))
584  2{1,2}
585  >>> print(clifford([2,3],index_set({1,2})))
586  2{1}+3{2}
587  """
588  error_msg_prefix = "Cannot initialize clifford object from"
589  if ixt is None:
590  try:
591  if isinstance(other, clifford):
592  self.instance = new Clifford((<clifford>other).unwrap())
593  elif isinstance(other, index_set):
594  self.instance = new Clifford((<index_set>other).unwrap(), <scalar_t>1.0)
595  elif isinstance(other, numbers.Real):
596  self.instance = new Clifford(<scalar_t>other)
597  elif isinstance(other, str):
598  try:
599  bother = other.encode("UTF-8")
600  self.instance = new Clifford(<char *>bother)
601  except RuntimeError:
602  raise ValueError(error_msg_prefix + " invalid string " + repr(other) + ".")
603  else:
604  raise TypeError(error_msg_prefix + " " + str(type(other)) + ".")
605  except RuntimeError as err:
606  raise ValueError(error_msg_prefix + " " + str(type(other))
607  + " value " + repr(other) + ":"
608  + "\n\t" + str(err))
609  elif isinstance(ixt, index_set):
610  if isinstance(other, numbers.Real):
611  self.instance = new Clifford((<index_set>ixt).unwrap(), <scalar_t>other)
612  elif isinstance(other, collections.abc.Sequence):
613  self.instance = new Clifford(list_to_vector(other), (<index_set>ixt).unwrap())
614  else:
615  raise TypeError(error_msg_prefix + " (" + str(type(other))
616  + ", " + repr(ixt) + ").")
617  else:
618  raise TypeError(error_msg_prefix + " (" + str(type(other))
619  + ", " + str(type(ixt)) + ").")
620 
621  def __dealloc__(self):
622  """
623  Clean up by deallocating the instance of C++ class Clifford.
624  """
625  del self.instance
626 
627  def __contains__(self, x):
628  """
629  Not applicable.
630 
631  >>> x=clifford(index_set({-3,4,7})); -3 in x
632  Traceback (most recent call last):
633  ...
634  TypeError: Not applicable.
635  """
636  raise TypeError("Not applicable.")
637 
638  def __iter__(self):
639  """
640  Not applicable.
641 
642  >>> for a in clifford(index_set({-3,4,7})):print(a, end=",")
643  Traceback (most recent call last):
644  ...
645  TypeError: Not applicable.
646  """
647  raise TypeError("Not applicable.")
648 
649  def reframe(self, ixt):
650  """
651  Put self into a larger frame, containing the union of self.frame() and index set ixt.
652  This can be used to make multiplication faster, by multiplying within a common frame.
653 
654  >>> clifford("2+3{1}").reframe(index_set({1,2,3}))
655  clifford("2+3{1}")
656  >>> s=index_set({1,2,3});t=index_set({-3,-2,-1});x=random_clifford(s); x.reframe(t).frame() == (s|t);
657  True
658  """
659  error_msg_prefix = "Cannot reframe"
660  if isinstance(ixt, index_set):
661  try:
662  result = clifford()
663  result.instance = new Clifford(self.unwrap(), (<index_set>ixt).unwrap())
664  except RuntimeError as err:
665  raise ValueError(error_msg_prefix + " from " + str(self) + " to frame "
666  + str(ixt) + ":"
667  + "\n\t" + str(err))
668  else:
669  raise TypeError(error_msg_prefix + " using (" + str(type(ixt)) + ").")
670  return result
671 
672  def __richcmp__(lhs, rhs, int op):
673  """
674  Compare objects of type clifford.
675 
676  >>> clifford("{1}") == clifford("1{1}")
677  True
678  >>> clifford("{1}") != clifford("1.0{1}")
679  False
680  >>> clifford("{1}") != clifford("1.0")
681  True
682  >>> clifford("{1,2}") == None
683  False
684  >>> clifford("{1,2}") != None
685  True
686  >>> None == clifford("{1,2}")
687  False
688  >>> None != clifford("{1,2}")
689  True
690  """
691  if op == 2: # ==
692  if (lhs is None) or (rhs is None):
693  return bool(lhs is rhs)
694  else:
695  return bool( toClifford(lhs) == toClifford(rhs) )
696  elif op == 3: # !=
697  if (lhs is None) or (rhs is None):
698  return not bool(lhs is rhs)
699  else:
700  return bool( toClifford(lhs) != toClifford(rhs) )
701  elif isinstance(lhs, clifford) or isinstance(rhs, clifford):
702  raise TypeError("This comparison operator is not implemented for "
703  + str(type(lhs)) + ", " + str(type(rhs)) + ".")
704  else:
705  return NotImplemented
706 
707  def __getitem__(self, ixt):
708  """
709  Subscripting: map from index set to scalar coordinate.
710 
711  >>> clifford("{1}")[index_set(1)]
712  1.0
713  >>> clifford("{1}")[index_set({1})]
714  1.0
715  >>> clifford("{1}")[index_set({1,2})]
716  0.0
717  >>> clifford("2{1,2}")[index_set({1,2})]
718  2.0
719  """
720  return self.instance.getitem(toIndexSet(ixt))
721 
722  def __neg__(self):
723  """
724  Unary -.
725 
726  >>> print(-clifford("{1}"))
727  -{1}
728  """
729  return clifford().wrap( self.instance.neg() )
730 
731  def __pos__(self):
732  """
733  Unary +.
734 
735  >>> print(+clifford("{1}"))
736  {1}
737  """
738  return clifford(self)
739 
740  def __add__(lhs, rhs):
741  """
742  Geometric sum.
743 
744  >>> print(clifford(1) + clifford("{2}"))
745  1+{2}
746  >>> print(clifford("{1}") + clifford("{2}"))
747  {1}+{2}
748  """
749  return clifford().wrap( toClifford(lhs) + toClifford(rhs) )
750 
751  def __iadd__(self, rhs):
752  """
753  Geometric sum.
754 
755  >>> x = clifford(1); x += clifford("{2}"); print(x)
756  1+{2}
757  """
758  return self.wrap( self.unwrap() + toClifford(rhs) )
759 
760  def __sub__(lhs, rhs):
761  """
762  Geometric difference.
763 
764  >>> print(clifford(1) - clifford("{2}"))
765  1-{2}
766  >>> print(clifford("{1}") - clifford("{2}"))
767  {1}-{2}
768  """
769  return clifford().wrap( toClifford(lhs) - toClifford(rhs) )
770 
771  def __isub__(self, rhs):
772  """
773  Geometric difference.
774 
775  >>> x = clifford(1); x -= clifford("{2}"); print(x)
776  1-{2}
777  """
778  return self.wrap( self.unwrap() - toClifford(rhs) )
779 
780  def __mul__(lhs, rhs):
781  """
782  Geometric product.
783 
784  >>> print(clifford("{1}") * clifford("{2}"))
785  {1,2}
786  >>> print(clifford(2) * clifford("{2}"))
787  2{2}
788  >>> print(clifford("{1}") * clifford("{1,2}"))
789  {2}
790  """
791  return clifford().wrap( toClifford(lhs) * toClifford(rhs) )
792 
793  def __imul__(self, rhs):
794  """
795  Geometric product.
796 
797  >>> x = clifford(2); x *= clifford("{2}"); print(x)
798  2{2}
799  >>> x = clifford("{1}"); x *= clifford("{2}"); print(x)
800  {1,2}
801  >>> x = clifford("{1}"); x *= clifford("{1,2}"); print(x)
802  {2}
803  """
804  return self.wrap( self.unwrap() * toClifford(rhs) )
805 
806  def __mod__(lhs, rhs):
807  """
808  Contraction.
809 
810  >>> print(clifford("{1}") % clifford("{2}"))
811  0
812  >>> print(clifford(2) % clifford("{2}"))
813  2{2}
814  >>> print(clifford("{1}") % clifford("{1}"))
815  1
816  >>> print(clifford("{1}") % clifford("{1,2}"))
817  {2}
818  """
819  return clifford().wrap( toClifford(lhs) % toClifford(rhs) )
820 
821  def __imod__(self, rhs):
822  """
823  Contraction.
824 
825  >>> x = clifford("{1}"); x %= clifford("{2}"); print(x)
826  0
827  >>> x = clifford(2); x %= clifford("{2}"); print(x)
828  2{2}
829  >>> x = clifford("{1}"); x %= clifford("{1}"); print(x)
830  1
831  >>> x = clifford("{1}"); x %= clifford("{1,2}"); print(x)
832  {2}
833  """
834  return self.wrap( self.unwrap() % toClifford(rhs) )
835 
836  def __and__(lhs, rhs):
837  """
838  Inner product.
839 
840  >>> print(clifford("{1}") & clifford("{2}"))
841  0
842  >>> print(clifford(2) & clifford("{2}"))
843  0
844  >>> print(clifford("{1}") & clifford("{1}"))
845  1
846  >>> print(clifford("{1}") & clifford("{1,2}"))
847  {2}
848  """
849  return clifford().wrap( toClifford(lhs) & toClifford(rhs) )
850 
851  def __iand__(self, rhs):
852  """
853  Inner product.
854 
855  >>> x = clifford("{1}"); x &= clifford("{2}"); print(x)
856  0
857  >>> x = clifford(2); x &= clifford("{2}"); print(x)
858  0
859  >>> x = clifford("{1}"); x &= clifford("{1}"); print(x)
860  1
861  >>> x = clifford("{1}"); x &= clifford("{1,2}"); print(x)
862  {2}
863  """
864  return self.wrap( self.unwrap() & toClifford(rhs) )
865 
866  def __xor__(lhs, rhs):
867  """
868  Outer product.
869 
870  >>> print(clifford("{1}") ^ clifford("{2}"))
871  {1,2}
872  >>> print(clifford(2) ^ clifford("{2}"))
873  2{2}
874  >>> print(clifford("{1}") ^ clifford("{1}"))
875  0
876  >>> print(clifford("{1}") ^ clifford("{1,2}"))
877  0
878  """
879  return clifford().wrap( toClifford(lhs) ^ toClifford(rhs) )
880 
881  def __ixor__(self, rhs):
882  """
883  Outer product.
884 
885  >>> x = clifford("{1}"); x ^= clifford("{2}"); print(x)
886  {1,2}
887  >>> x = clifford(2); x ^= clifford("{2}"); print(x)
888  2{2}
889  >>> x = clifford("{1}"); x ^= clifford("{1}"); print(x)
890  0
891  >>> x = clifford("{1}"); x ^= clifford("{1,2}"); print(x)
892  0
893  """
894  return self.wrap( self.unwrap() ^ toClifford(rhs) )
895 
896  def __truediv__(lhs, rhs):
897  """
898  Geometric quotient.
899 
900  >>> print(clifford("{1}") / clifford("{2}"))
901  {1,2}
902  >>> print(clifford(2) / clifford("{2}"))
903  2{2}
904  >>> print(clifford("{1}") / clifford("{1}"))
905  1
906  >>> print(clifford("{1}") / clifford("{1,2}"))
907  -{2}
908  """
909  return clifford().wrap( toClifford(lhs) / toClifford(rhs) )
910 
911  def __idiv__(self, rhs):
912  """
913  Geometric quotient.
914 
915  >>> x = clifford("{1}"); x /= clifford("{2}"); print(x)
916  {1,2}
917  >>> x = clifford(2); x /= clifford("{2}"); print(x)
918  2{2}
919  >>> x = clifford("{1}"); x /= clifford("{1}"); print(x)
920  1
921  >>> x = clifford("{1}"); x /= clifford("{1,2}"); print(x)
922  -{2}
923  """
924  return self.wrap( self.unwrap() / toClifford(rhs) )
925 
926  def inv(self):
927  """
928  Geometric multiplicative inverse.
929 
930  >>> x = clifford("{1}"); print(x.inv())
931  {1}
932  >>> x = clifford(2); print(x.inv())
933  0.5
934  >>> x = clifford("{1,2}"); print(x.inv())
935  -{1,2}
936  """
937  return clifford().wrap( self.instance.inv() )
938 
939  def __or__(lhs, rhs):
940  """
941  Transform left hand side, using right hand side as a transformation.
942 
943  >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); print(y|x)
944  -{1}
945  >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); print(y|exp(x))
946  -{1}
947  """
948  return clifford().wrap( toClifford(lhs) | toClifford(rhs) )
949 
950  def __ior__(self, rhs):
951  """
952  Transform left hand side, using right hand side as a transformation.
953 
954  >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); y|=x; print(y)
955  -{1}
956  >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); y|=exp(x); print(y)
957  -{1}
958  """
959  return self.wrap( self.unwrap() | toClifford(rhs) )
960 
961  def __pow__(self, m, dummy):
962  """
963  Power: self to the m.
964 
965  >>> x=clifford("{1}"); print(x ** 2)
966  1
967  >>> x=clifford("2"); print(x ** 2)
968  4
969  >>> x=clifford("2+{1}"); print(x ** 0)
970  1
971  >>> x=clifford("2+{1}"); print(x ** 1)
972  2+{1}
973  >>> x=clifford("2+{1}"); print(x ** 2)
974  5+4{1}
975  >>> i=clifford("{1,2}"); print(exp(pi/2) * (i ** i))
976  1
977  """
978  return pow(self, m)
979 
980  def pow(self, m):
981  """
982  Power: self to the m.
983 
984  >>> x=clifford("{1}"); print(x.pow(2))
985  1
986  >>> x=clifford("2"); print(x.pow(2))
987  4
988  >>> x=clifford("2+{1}"); print(x.pow(0))
989  1
990  >>> x=clifford("2+{1}"); print(x.pow(1))
991  2+{1}
992  >>> x=clifford("2+{1}"); print(x.pow(2))
993  5+4{1}
994  >>> print(clifford("1+{1}+{1,2}").pow(3))
995  1+3{1}+3{1,2}
996  >>> i=clifford("{1,2}"); print(exp(pi/2) * i.pow(i))
997  1
998  """
999  if isinstance(m, numbers.Integral):
1000  return clifford().wrap( self.instance.pow(m) )
1001  else:
1002  return exp(m * log(self))
1003 
1004  def outer_pow(self, m):
1005  """
1006  Outer product power.
1007 
1008  >>> x=clifford("2+{1}"); print(x.outer_pow(0))
1009  1
1010  >>> x=clifford("2+{1}"); print(x.outer_pow(1))
1011  2+{1}
1012  >>> x=clifford("2+{1}"); print(x.outer_pow(2))
1013  4+4{1}
1014  >>> print(clifford("1+{1}+{1,2}").outer_pow(3))
1015  1+3{1}+3{1,2}
1016 
1017  """
1018  return clifford().wrap( self.instance.outer_pow(m) )
1019 
1020  def __call__(self, grade):
1021  """
1022  Pure grade-vector part.
1023 
1024  >>> print(clifford("{1}")(1))
1025  {1}
1026  >>> print(clifford("{1}")(0))
1027  0
1028  >>> print(clifford("1+{1}+{1,2}")(0))
1029  1
1030  >>> print(clifford("1+{1}+{1,2}")(1))
1031  {1}
1032  >>> print(clifford("1+{1}+{1,2}")(2))
1033  {1,2}
1034  >>> print(clifford("1+{1}+{1,2}")(3))
1035  0
1036  """
1037  return clifford().wrap( self.instance.call(grade) )
1038 
1039  def scalar(self):
1040  """
1041  Scalar part.
1042 
1043  >>> clifford("1+{1}+{1,2}").scalar()
1044  1.0
1045  >>> clifford("{1,2}").scalar()
1046  0.0
1047  """
1048  return self.instance.scalar()
1049 
1050  def pure(self):
1051  """
1052  Pure part.
1053 
1054  >>> print(clifford("1+{1}+{1,2}").pure())
1055  {1}+{1,2}
1056  >>> print(clifford("{1,2}").pure())
1057  {1,2}
1058  """
1059  return clifford().wrap( self.instance.pure() )
1060 
1061  def even(self):
1062  """
1063  Even part of multivector, sum of even grade terms.
1064 
1065  >>> print(clifford("1+{1}+{1,2}").even())
1066  1+{1,2}
1067  """
1068  return clifford().wrap( self.instance.even() )
1069 
1070  def odd(self):
1071  """
1072  Odd part of multivector, sum of odd grade terms.
1073 
1074  >>> print(clifford("1+{1}+{1,2}").odd())
1075  {1}
1076  """
1077  return clifford().wrap( self.instance.odd() )
1078 
1079  def vector_part(self, frm = None):
1080  """
1081  Vector part of multivector, as a Python list, with respect to frm.
1082 
1083  >>> print(clifford("1+2{1}+3{2}+4{1,2}").vector_part())
1084  [2.0, 3.0]
1085  >>> print(clifford("1+2{1}+3{2}+4{1,2}").vector_part(index_set({-1,1,2})))
1086  [0.0, 2.0, 3.0]
1087  """
1088  error_msg_prefix = "Cannot take vector part of "
1089  cdef vector[scalar_t] vec
1090  cdef int n
1091  cdef int i
1092  try:
1093  if frm is None:
1094  vec = self.instance.vector_part()
1095  else:
1096  vec = self.instance.vector_part((<index_set>frm).unwrap())
1097  n = vec.size()
1098  lst = [0.0]*n
1099  for i in xrange(n):
1100  lst[i] = vec[i]
1101  return lst
1102  except RuntimeError as err:
1103  raise ValueError(error_msg_prefix + str(self) + " using invalid "
1104  + repr(frm) + " as frame:\n\t"
1105  + str(err))
1106 
1107  def involute(self):
1108  """
1109  Main involution, each {i} is replaced by -{i} in each term,
1110  eg. clifford("{1}") -> -clifford("{1}").
1111 
1112  >>> print(clifford("{1}").involute())
1113  -{1}
1114  >>> print((clifford("{2}") * clifford("{1}")).involute())
1115  -{1,2}
1116  >>> print((clifford("{1}") * clifford("{2}")).involute())
1117  {1,2}
1118  >>> print(clifford("1+{1}+{1,2}").involute())
1119  1-{1}+{1,2}
1120  """
1121  return clifford().wrap( self.instance.involute() )
1122 
1123  def reverse(self):
1124  """
1125  Reversion, eg. clifford("{1}")*clifford("{2}") -> clifford("{2}")*clifford("{1}").
1126 
1127  >>> print(clifford("{1}").reverse())
1128  {1}
1129  >>> print((clifford("{2}") * clifford("{1}")).reverse())
1130  {1,2}
1131  >>> print((clifford("{1}") * clifford("{2}")).reverse())
1132  -{1,2}
1133  >>> print(clifford("1+{1}+{1,2}").reverse())
1134  1+{1}-{1,2}
1135  """
1136  return clifford().wrap( self.instance.reverse() )
1137 
1138  def conj(self):
1139  """
1140  Conjugation, reverse o involute == involute o reverse.
1141 
1142  >>> print((clifford("{1}")).conj())
1143  -{1}
1144  >>> print((clifford("{2}") * clifford("{1}")).conj())
1145  {1,2}
1146  >>> print((clifford("{1}") * clifford("{2}")).conj())
1147  -{1,2}
1148  >>> print(clifford("1+{1}+{1,2}").conj())
1149  1-{1}-{1,2}
1150  """
1151  return clifford().wrap( self.instance.conj() )
1152 
1153  def quad(self):
1154  """
1155  Quadratic form == (rev(x)*x)(0).
1156 
1157  >>> print(clifford("1+{1}+{1,2}").quad())
1158  3.0
1159  >>> print(clifford("1+{-1}+{1,2}+{1,2,3}").quad())
1160  2.0
1161  """
1162  return self.instance.quad()
1163 
1164  def norm(self):
1165  """
1166  Norm == sum of squares of coordinates.
1167 
1168  >>> clifford("1+{1}+{1,2}").norm()
1169  3.0
1170  >>> clifford("1+{-1}+{1,2}+{1,2,3}").norm()
1171  4.0
1172  """
1173  return self.instance.norm()
1174 
1175  def abs(self):
1176  """
1177  Absolute value: square root of norm.
1178 
1179  >>> clifford("1+{-1}+{1,2}+{1,2,3}").abs()
1180  2.0
1181  """
1182  return glucat.abs( self.unwrap() )
1183 
1184  def max_abs(self):
1185  """
1186  Maximum of absolute values of components of multivector: multivector infinity norm.
1187 
1188  >>> clifford("1+{-1}+{1,2}+{1,2,3}").max_abs()
1189  1.0
1190  >>> clifford("3+2{1}+{1,2}").max_abs()
1191  3.0
1192  """
1193  return self.instance.max_abs()
1194 
1195  def truncated(self, limit):
1196  """
1197  Remove all terms of self with relative size smaller than limit.
1198 
1199  >>> clifford("1e8+{1}+1e-8{1,2}").truncated(1.0e-6)
1200  clifford("100000000")
1201  >>> clifford("1e4+{1}+1e-4{1,2}").truncated(1.0e-6)
1202  clifford("10000+{1}")
1203  """
1204  return clifford().wrap( self.instance.truncated(limit) )
1205 
1206  def isinf(self):
1207  """
1208  Check if a multivector contains any infinite values.
1209 
1210  >>> clifford().isinf()
1211  False
1212  """
1213  return self.instance.isnan()
1214 
1215  def isnan(self):
1216  """
1217  Check if a multivector contains any IEEE NaN values.
1218 
1219  >>> clifford().isnan()
1220  False
1221  """
1222  return self.instance.isnan()
1223 
1224  def frame(self):
1225  """
1226  Subalgebra generated by all generators of terms of given multivector.
1227 
1228  >>> print(clifford("1+3{-1}+2{1,2}+4{-2,7}").frame())
1229  {-2,-1,1,2,7}
1230  >>> s=clifford("1+3{-1}+2{1,2}+4{-2,7}").frame(); type(s)
1231  <class 'PyClical.index_set'>
1232  """
1233  return index_set().wrap( self.instance.frame() )
1234 
1235  def __repr__(self):
1236  """
1237  The “official” string representation of self.
1238 
1239  >>> clifford("1+3{-1}+2{1,2}+4{-2,7}").__repr__()
1240  'clifford("1+3{-1}+2{1,2}+4{-2,7}")'
1241  """
1242  return clifford_to_repr( self.unwrap() ).decode()
1243 
1244  def __str__(self):
1245  """
1246  The “informal” string representation of self.
1247 
1248  >>> clifford("1+3{-1}+2{1,2}+4{-2,7}").__str__()
1249  '1+3{-1}+2{1,2}+4{-2,7}'
1250  """
1251  return clifford_to_str( self.unwrap() ).decode()
1252 
1254  """
1255  Tests for functions that Doctest cannot see.
1256 
1257  For clifford.__cinit__: Construct an object of type clifford.
1258 
1259  >>> print(clifford(2))
1260  2
1261  >>> print(clifford(2.0))
1262  2
1263  >>> print(clifford(1.0e-1))
1264  0.1
1265  >>> print(clifford("2"))
1266  2
1267  >>> print(clifford("2{1,2,3}"))
1268  2{1,2,3}
1269  >>> print(clifford(clifford("2{1,2,3}")))
1270  2{1,2,3}
1271  >>> print(clifford("-{1}"))
1272  -{1}
1273  >>> print(clifford(2,index_set({1,2})))
1274  2{1,2}
1275  >>> print(clifford([2,3],index_set({1,2})))
1276  2{1}+3{2}
1277  >>> print(clifford([1,2]))
1278  Traceback (most recent call last):
1279  ...
1280  TypeError: Cannot initialize clifford object from <class 'list'>.
1281  >>> print(clifford(None))
1282  Traceback (most recent call last):
1283  ...
1284  TypeError: Cannot initialize clifford object from <class 'NoneType'>.
1285  >>> print(clifford(None,[1,2]))
1286  Traceback (most recent call last):
1287  ...
1288  TypeError: Cannot initialize clifford object from (<class 'NoneType'>, <class 'list'>).
1289  >>> print(clifford([1,2],[1,2]))
1290  Traceback (most recent call last):
1291  ...
1292  TypeError: Cannot initialize clifford object from (<class 'list'>, <class 'list'>).
1293  >>> print(clifford(""))
1294  Traceback (most recent call last):
1295  ...
1296  ValueError: Cannot initialize clifford object from invalid string ''.
1297  >>> print(clifford("{"))
1298  Traceback (most recent call last):
1299  ...
1300  ValueError: Cannot initialize clifford object from invalid string '{'.
1301  >>> print(clifford("{1"))
1302  Traceback (most recent call last):
1303  ...
1304  ValueError: Cannot initialize clifford object from invalid string '{1'.
1305  >>> print(clifford("+"))
1306  Traceback (most recent call last):
1307  ...
1308  ValueError: Cannot initialize clifford object from invalid string '+'.
1309  >>> print(clifford("-"))
1310  Traceback (most recent call last):
1311  ...
1312  ValueError: Cannot initialize clifford object from invalid string '-'.
1313  >>> print(clifford("{1}+"))
1314  Traceback (most recent call last):
1315  ...
1316  ValueError: Cannot initialize clifford object from invalid string '{1}+'.
1317 
1318  For clifford.__richcmp__: Compare objects of type clifford.
1319 
1320  >>> clifford("{1}") == clifford("1{1}")
1321  True
1322  >>> clifford("{1}") != clifford("1.0{1}")
1323  False
1324  >>> clifford("{1}") != clifford("1.0")
1325  True
1326  >>> clifford("{1,2}") == None
1327  False
1328  >>> clifford("{1,2}") != None
1329  True
1330  >>> None == clifford("{1,2}")
1331  False
1332  >>> None != clifford("{1,2}")
1333  True
1334  """
1335  return
1336 
1337 cpdef inline error_squared_tol(obj):
1338  """
1339  Quadratic norm error tolerance relative to a specific multivector.
1340 
1341  >>> print(error_squared_tol(clifford("{1}")) * 3.0 - error_squared_tol(clifford("1{1}-2{2}+3{3}")))
1342  0.0
1343  """
1344  return glucat.error_squared_tol(toClifford(obj))
1345 
1346 cpdef inline error_squared(lhs, rhs, threshold):
1347  """
1348  Relative or absolute error using the quadratic norm.
1349 
1350  >>> err2=scalar_epsilon*scalar_epsilon
1351 
1352  >>> print(error_squared(clifford("{1}"), clifford("1{1}"), err2))
1353  0.0
1354  >>> print(error_squared(clifford("1{1}-3{2}+4{3}"), clifford("{1}"), err2))
1355  25.0
1356  """
1357  return glucat.error_squared(toClifford(lhs), toClifford(rhs), <scalar_t>threshold)
1358 
1359 cpdef inline approx_equal(lhs, rhs, threshold=None, tol=None):
1360  """
1361  Test for approximate equality of multivectors.
1362 
1363  >>> err2=scalar_epsilon*scalar_epsilon
1364 
1365  >>> print(approx_equal(clifford("{1}"), clifford("1{1}")))
1366  True
1367  >>> print(approx_equal(clifford("1{1}-3{2}+4{3}"), clifford("{1}")))
1368  False
1369  >>> print(approx_equal(clifford("1{1}-3{2}+4{3}+0.001"), clifford("1{1}-3{2}+4{3}"), err2, err2))
1370  False
1371  >>> print(approx_equal(clifford("1{1}-3{2}+4{3}+1.0e-30"), clifford("1{1}-3{2}+4{3}"), err2, err2))
1372  True
1373  """
1374  threshold = error_squared_tol(rhs) if threshold is None else threshold
1375  tol = error_squared_tol(rhs) if tol is None else tol
1376  return glucat.approx_equal(toClifford(lhs), toClifford(rhs), <scalar_t>threshold, <scalar_t>tol)
1377 
1378 cpdef inline inv(obj):
1379  """
1380  Geometric multiplicative inverse.
1381 
1382  >>> print(inv(clifford("{1}")))
1383  {1}
1384  >>> print(inv(clifford("{-1}")))
1385  -{-1}
1386  >>> print(inv(clifford("{-2,-1}")))
1387  -{-2,-1}
1388  >>> print(inv(clifford("{-1}+{1}")))
1389  nan
1390  """
1391  return clifford(obj).inv()
1392 
1393 cpdef inline scalar(obj):
1394  """
1395  Scalar part.
1396 
1397  >>> scalar(clifford("1+{1}+{1,2}"))
1398  1.0
1399  >>> scalar(clifford("{1,2}"))
1400  0.0
1401  """
1402  return clifford(obj).scalar()
1403 
1404 cpdef inline real(obj):
1405  """
1406  Real part: synonym for scalar part.
1407 
1408  >>> real(clifford("1+{1}+{1,2}"))
1409  1.0
1410  >>> real(clifford("{1,2}"))
1411  0.0
1412  """
1413  return clifford(obj).scalar()
1414 
1415 cpdef inline imag(obj):
1416  """
1417  Imaginary part: deprecated (always 0).
1418 
1419  >>> imag(clifford("1+{1}+{1,2}"))
1420  0.0
1421  >>> imag(clifford("{1,2}"))
1422  0.0
1423  """
1424  return 0.0
1425 
1426 cpdef inline pure(obj):
1427  """
1428  Pure part
1429 
1430  >>> print(pure(clifford("1+{1}+{1,2}")))
1431  {1}+{1,2}
1432  >>> print(pure(clifford("{1,2}")))
1433  {1,2}
1434  """
1435  return clifford(obj).pure()
1436 
1437 cpdef inline even(obj):
1438  """
1439  Even part of multivector, sum of even grade terms.
1440 
1441  >>> print(even(clifford("1+{1}+{1,2}")))
1442  1+{1,2}
1443  """
1444  return clifford(obj).even()
1445 
1446 cpdef inline odd(obj):
1447  """
1448  Odd part of multivector, sum of odd grade terms.
1449 
1450  >>> print(odd(clifford("1+{1}+{1,2}")))
1451  {1}
1452  """
1453  return clifford(obj).odd()
1454 
1455 cpdef inline involute(obj):
1456  """
1457  Main involution, each {i} is replaced by -{i} in each term, eg. {1}*{2} -> (-{2})*(-{1})
1458 
1459  >>> print(involute(clifford("{1}")))
1460  -{1}
1461  >>> print(involute(clifford("{2}") * clifford("{1}")))
1462  -{1,2}
1463  >>> print(involute(clifford("{1}") * clifford("{2}")))
1464  {1,2}
1465  >>> print(involute(clifford("1+{1}+{1,2}")))
1466  1-{1}+{1,2}
1467  """
1468  return clifford(obj).involute()
1469 
1470 cpdef inline reverse(obj):
1471  """
1472  Reversion, eg. {1}*{2} -> {2}*{1}
1473 
1474  >>> print(reverse(clifford("{1}")))
1475  {1}
1476  >>> print(reverse(clifford("{2}") * clifford("{1}")))
1477  {1,2}
1478  >>> print(reverse(clifford("{1}") * clifford("{2}")))
1479  -{1,2}
1480  >>> print(reverse(clifford("1+{1}+{1,2}")))
1481  1+{1}-{1,2}
1482  """
1483  return clifford(obj).reverse()
1484 
1485 cpdef inline conj(obj):
1486  """
1487  Conjugation, reverse o involute == involute o reverse.
1488 
1489  >>> print(conj(clifford("{1}")))
1490  -{1}
1491  >>> print(conj(clifford("{2}") * clifford("{1}")))
1492  {1,2}
1493  >>> print(conj(clifford("{1}") * clifford("{2}")))
1494  -{1,2}
1495  >>> print(conj(clifford("1+{1}+{1,2}")))
1496  1-{1}-{1,2}
1497  """
1498  return clifford(obj).conj()
1499 
1500 cpdef inline quad(obj):
1501  """
1502  Quadratic form == (rev(x)*x)(0).
1503 
1504  >>> print(quad(clifford("1+{1}+{1,2}")))
1505  3.0
1506  >>> print(quad(clifford("1+{-1}+{1,2}+{1,2,3}")))
1507  2.0
1508  """
1509  return clifford(obj).quad()
1510 
1511 cpdef inline norm(obj):
1512  """
1513  norm == sum of squares of coordinates.
1514 
1515  >>> norm(clifford("1+{1}+{1,2}"))
1516  3.0
1517  >>> norm(clifford("1+{-1}+{1,2}+{1,2,3}"))
1518  4.0
1519  """
1520  return clifford(obj).norm()
1521 
1522 cpdef inline abs(obj):
1523  """
1524  Absolute value of multivector: multivector 2-norm.
1525 
1526  >>> abs(clifford("1+{-1}+{1,2}+{1,2,3}"))
1527  2.0
1528  """
1529  return glucat.abs(toClifford(obj))
1530 
1531 cpdef inline max_abs(obj):
1532  """
1533  Maximum absolute value of coordinates multivector: multivector infinity-norm.
1534 
1535  >>> max_abs(clifford("1+{-1}+{1,2}+{1,2,3}"))
1536  1.0
1537  >>> max_abs(clifford("3+2{1}+{1,2}"))
1538  3.0
1539 
1540  """
1541  return glucat.max_abs(toClifford(obj))
1542 
1543 cpdef inline pow(obj, m):
1544  """
1545  Integer power of multivector: obj to the m.
1546 
1547  >>> x=clifford("{1}"); print(pow(x,2))
1548  1
1549  >>> x=clifford("2"); print(pow(x,2))
1550  4
1551  >>> x=clifford("2+{1}"); print(pow(x,0))
1552  1
1553  >>> x=clifford("2+{1}"); print(pow(x,1))
1554  2+{1}
1555  >>> x=clifford("2+{1}"); print(pow(x,2))
1556  5+4{1}
1557  >>> print(pow(clifford("1+{1}+{1,2}"),3))
1558  1+3{1}+3{1,2}
1559  >>> i=clifford("{1,2}"); print(exp(pi/2) * pow(i, i))
1560  1
1561  """
1562  try:
1563  math.pow(obj, m)
1564  except:
1565  return clifford(obj).pow(m)
1566 
1567 cpdef inline outer_pow(obj, m):
1568  """
1569  Outer product power of multivector.
1570 
1571  >>> print(outer_pow(clifford("1+{1}+{1,2}"),3))
1572  1+3{1}+3{1,2}
1573  """
1574  return clifford(obj).outer_pow(m)
1575 
1576 cpdef inline complexifier(obj):
1577  """
1578  Square root of -1 which commutes with all members of the frame of the given multivector.
1579 
1580  >>> print(complexifier(clifford(index_set({1}))))
1581  {1,2,3}
1582  >>> print(complexifier(clifford(index_set({-1}))))
1583  {-1}
1584  >>> print(complexifier(index_set({1})))
1585  {1,2,3}
1586  >>> print(complexifier(index_set({-1})))
1587  {-1}
1588  """
1589  return clifford().wrap( glucat.complexifier(toClifford(obj)) )
1590 
1591 cpdef inline sqrt(obj, i = None):
1592  """
1593  Square root of multivector with optional complexifier.
1594 
1595  >>> print(sqrt(-1))
1596  {-1}
1597  >>> print(sqrt(clifford("2{-1}")))
1598  1+{-1}
1599  >>> j=sqrt(-1,complexifier(index_set({1}))); print(j); print(j*j)
1600  {1,2,3}
1601  -1
1602  >>> j=sqrt(-1,"{1,2,3}"); print(j); print(j*j)
1603  {1,2,3}
1604  -1
1605  """
1606  if not (i is None):
1607  return clifford().wrap( glucat.sqrt(toClifford(obj), toClifford(i)) )
1608  else:
1609  try:
1610  return math.sqrt(obj)
1611  except:
1612  return clifford().wrap( glucat.sqrt(toClifford(obj)) )
1613 
1614 cpdef inline exp(obj):
1615  """
1616  Exponential of multivector.
1617 
1618  >>> x=clifford("{1,2}") * pi/4; print(exp(x))
1619  0.7071+0.7071{1,2}
1620  >>> x=clifford("{1,2}") * pi/2; print(exp(x))
1621  {1,2}
1622  """
1623  try:
1624  return math.exp(obj)
1625  except:
1626  return clifford().wrap( glucat.exp(toClifford(obj)) )
1627 
1628 cpdef inline log(obj,i = None):
1629  """
1630  Natural logarithm of multivector with optional complexifier.
1631 
1632  >>> x=clifford("{-1}"); print((log(x,"{-1}") * 2/pi))
1633  {-1}
1634  >>> x=clifford("{1,2}"); print((log(x,"{1,2,3}") * 2/pi))
1635  {1,2}
1636  >>> x=clifford("{1,2}"); print((log(x) * 2/pi))
1637  {1,2}
1638  >>> x=clifford("{1,2}"); print((log(x,"{1,2}") * 2/pi))
1639  Traceback (most recent call last):
1640  ...
1641  RuntimeError: check_complex(val, i): i is not a valid complexifier for val
1642  """
1643  if not (i is None):
1644  return clifford().wrap( glucat.log(toClifford(obj), toClifford(i)) )
1645  else:
1646  try:
1647  return math.log(obj)
1648  except:
1649  return clifford().wrap( glucat.log(toClifford(obj)) )
1650 
1651 cpdef inline cos(obj,i = None):
1652  """
1653  Cosine of multivector with optional complexifier.
1654 
1655  >>> x=clifford("{1,2}"); print(cos(acos(x),"{1,2,3}"))
1656  {1,2}
1657  >>> x=clifford("{1,2}"); print(cos(acos(x)))
1658  {1,2}
1659  """
1660  if not (i is None):
1661  return clifford().wrap( glucat.cos(toClifford(obj), toClifford(i)) )
1662  else:
1663  try:
1664  return math.cos(obj)
1665  except:
1666  return clifford().wrap( glucat.cos(toClifford(obj)) )
1667 
1668 cpdef inline acos(obj,i = None):
1669  """
1670  Inverse cosine of multivector with optional complexifier.
1671 
1672  >>> x=clifford("{1,2}"); print(cos(acos(x),"{1,2,3}"))
1673  {1,2}
1674  >>> x=clifford("{1,2}"); print(cos(acos(x),"{-1,1,2,3,4}"))
1675  {1,2}
1676  >>> print(acos(0) / pi)
1677  0.5
1678  >>> x=clifford("{1,2}"); print(cos(acos(x)))
1679  {1,2}
1680  """
1681  if not (i is None):
1682  return clifford().wrap( glucat.acos(toClifford(obj), toClifford(i)) )
1683  else:
1684  try:
1685  return math.acos(obj)
1686  except:
1687  return clifford().wrap( glucat.acos(toClifford(obj)) )
1688 
1689 cpdef inline cosh(obj):
1690  """
1691  Hyperbolic cosine of multivector.
1692 
1693  >>> x=clifford("{1,2}") * pi; print(cosh(x))
1694  -1
1695  >>> x=clifford("{1,2,3}"); print(cosh(acosh(x)))
1696  {1,2,3}
1697  >>> x=clifford("{1,2}"); print(cosh(acosh(x)))
1698  {1,2}
1699  """
1700  try:
1701  return math.cosh(obj)
1702  except:
1703  return clifford().wrap( glucat.cosh(toClifford(obj)) )
1704 
1705 cpdef inline acosh(obj,i = None):
1706  """
1707  Inverse hyperbolic cosine of multivector with optional complexifier.
1708 
1709  >>> print(acosh(0,"{-2,-1,1}"))
1710  1.571{-2,-1,1}
1711  >>> x=clifford("{1,2,3}"); print(cosh(acosh(x,"{-1,1,2,3,4}")))
1712  {1,2,3}
1713  >>> print(acosh(0))
1714  1.571{-1}
1715  >>> x=clifford("{1,2,3}"); print(cosh(acosh(x)))
1716  {1,2,3}
1717  >>> x=clifford("{1,2}"); print(cosh(acosh(x)))
1718  {1,2}
1719  """
1720  if not (i is None):
1721  return clifford().wrap( glucat.acosh(toClifford(obj), toClifford(i)) )
1722  else:
1723  try:
1724  return math.acosh(obj)
1725  except:
1726  return clifford().wrap( glucat.acosh(toClifford(obj)) )
1727 
1728 cpdef inline sin(obj,i = None):
1729  """
1730  Sine of multivector with optional complexifier.
1731 
1732  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),s))
1733  {-1}
1734  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),"{-2,-1,1}"))
1735  {-1}
1736  >>> x=clifford("{1,2,3}"); print(asin(sin(x)))
1737  {1,2,3}
1738  """
1739  if not (i is None):
1740  return clifford().wrap( glucat.sin(toClifford(obj), toClifford(i)) )
1741  else:
1742  try:
1743  return math.sin(obj)
1744  except:
1745  return clifford().wrap( glucat.sin(toClifford(obj)) )
1746 
1747 cpdef inline asin(obj,i = None):
1748  """
1749  Inverse sine of multivector with optional complexifier.
1750 
1751  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),s))
1752  {-1}
1753  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),"{-2,-1,1}"))
1754  {-1}
1755  >>> print(asin(1) / pi)
1756  0.5
1757  >>> x=clifford("{1,2,3}"); print(asin(sin(x)))
1758  {1,2,3}
1759  """
1760  if not (i is None):
1761  return clifford().wrap( glucat.asin(toClifford(obj), toClifford(i)) )
1762  else:
1763  try:
1764  return math.asin(obj)
1765  except:
1766  return clifford().wrap( glucat.asin(toClifford(obj)) )
1767 
1768 cpdef inline sinh(obj):
1769  """
1770  Hyperbolic sine of multivector.
1771 
1772  >>> x=clifford("{1,2}") * pi/2; print(sinh(x))
1773  {1,2}
1774  >>> x=clifford("{1,2}") * pi/6; print(sinh(x))
1775  0.5{1,2}
1776  """
1777  try:
1778  return math.sinh(obj)
1779  except:
1780  return clifford().wrap( glucat.sinh(toClifford(obj)) )
1781 
1782 cpdef inline asinh(obj,i = None):
1783  """
1784  Inverse hyperbolic sine of multivector with optional complexifier.
1785 
1786  >>> x=clifford("{1,2}"); print(asinh(x,"{1,2,3}") * 2/pi)
1787  {1,2}
1788  >>> x=clifford("{1,2}"); print(asinh(x) * 2/pi)
1789  {1,2}
1790  >>> x=clifford("{1,2}") / 2; print(asinh(x) * 6/pi)
1791  {1,2}
1792  """
1793  if not (i is None):
1794  return clifford().wrap( glucat.asinh(toClifford(obj), toClifford(i)) )
1795  else:
1796  try:
1797  return math.asinh(obj)
1798  except:
1799  return clifford().wrap( glucat.asinh(toClifford(obj)) )
1800 
1801 cpdef inline tan(obj,i = None):
1802  """
1803  Tangent of multivector with optional complexifier.
1804 
1805  >>> x=clifford("{1,2}"); print(tan(x,"{1,2,3}"))
1806  0.7616{1,2}
1807  >>> x=clifford("{1,2}"); print(tan(x))
1808  0.7616{1,2}
1809  """
1810  if not (i is None):
1811  return clifford().wrap( glucat.tan(toClifford(obj), toClifford(i)) )
1812  else:
1813  try:
1814  return math.tan(obj)
1815  except:
1816  return clifford().wrap( glucat.tan(toClifford(obj)) )
1817 
1818 cpdef inline atan(obj,i = None):
1819  """
1820  Inverse tangent of multivector with optional complexifier.
1821 
1822  >>> s=index_set({1,2,3}); x=clifford("{1}"); print(tan(atan(x,s),s))
1823  {1}
1824  >>> x=clifford("{1}"); print(tan(atan(x)))
1825  {1}
1826  """
1827  if not (i is None):
1828  return clifford().wrap( glucat.atan(toClifford(obj), toClifford(i)) )
1829  else:
1830  try:
1831  return math.atan(obj)
1832  except:
1833  return clifford().wrap( glucat.atan(toClifford(obj)) )
1834 
1835 cpdef inline tanh(obj):
1836  """
1837  Hyperbolic tangent of multivector.
1838 
1839  >>> x=clifford("{1,2}") * pi/4; print(tanh(x))
1840  {1,2}
1841  """
1842  try:
1843  return math.tanh(obj)
1844  except:
1845  return clifford().wrap( glucat.tanh(toClifford(obj)) )
1846 
1847 cpdef inline atanh(obj,i = None):
1848  """
1849  Inverse hyperbolic tangent of multivector with optional complexifier.
1850 
1851  >>> s=index_set({1,2,3}); x=clifford("{1,2}"); print(tanh(atanh(x,s)))
1852  {1,2}
1853  >>> x=clifford("{1,2}"); print(tanh(atanh(x)))
1854  {1,2}
1855  """
1856  if not (i is None):
1857  return clifford().wrap( glucat.atanh(toClifford(obj), toClifford(i)) )
1858  else:
1859  try:
1860  return math.atanh(obj)
1861  except:
1862  return clifford().wrap( glucat.atanh(toClifford(obj)) )
1863 
1864 cpdef inline random_clifford(index_set ixt, fill = 1.0):
1865  """
1866  Random multivector within a frame.
1867 
1868  >>> print(random_clifford(index_set({-3,-1,2})).frame())
1869  {-3,-1,2}
1870  """
1871  return clifford().wrap( clifford().instance.random(ixt.unwrap(), <scalar_t>fill) )
1872 
1873 cpdef inline cga3(obj):
1874  """
1875  Convert Euclidean 3D multivector to Conformal Geometric Algebra using Doran and Lasenby definition.
1876 
1877  >>> x=clifford("2{1}+9{2}+{3}"); print(cga3(x))
1878  87{-1}+4{1}+18{2}+2{3}+85{4}
1879  """
1880  return clifford().wrap( glucat.cga3(toClifford(obj)) )
1881 
1882 cpdef inline cga3std(obj):
1883  """
1884  Convert CGA3 null vector to standard conformal null vector using Doran and Lasenby definition.
1885 
1886  >>> x=clifford("2{1}+9{2}+{3}"); print(cga3std(cga3(x)))
1887  87{-1}+4{1}+18{2}+2{3}+85{4}
1888  >>> x=clifford("2{1}+9{2}+{3}"); print(cga3std(cga3(x))-cga3(x))
1889  0
1890  """
1891  return clifford().wrap( glucat.cga3std(toClifford(obj)) )
1892 
1893 cpdef inline agc3(obj):
1894  """
1895  Convert CGA3 null vector to Euclidean 3D vector using Doran and Lasenby definition.
1896 
1897  >>> x=clifford("2{1}+9{2}+{3}"); print(agc3(cga3(x)))
1898  2{1}+9{2}+{3}
1899  >>> x=clifford("2{1}+9{2}+{3}"); print(agc3(cga3(x))-x)
1900  0
1901  """
1902  return clifford().wrap( glucat.agc3(toClifford(obj)) )
1903 
1904 # Some abbreviations.
1905 scalar_epsilon = epsilon
1906 
1907 pi = atan(clifford(1.0)) * 4.0
1908 tau = atan(clifford(1.0)) * 8.0
1909 
1910 cl = clifford
1911 """
1912 Abbreviation for clifford.
1913 
1914 >>> print(cl(2))
1915 2
1916 >>> print(cl(2.0))
1917 2
1918 >>> print(cl(5.0e-1))
1919 0.5
1920 >>> print(cl("2"))
1921 2
1922 >>> print(cl("2{1,2,3}"))
1923 2{1,2,3}
1924 >>> print(cl(cl("2{1,2,3}")))
1925 2{1,2,3}
1926 """
1927 
1928 ist = index_set
1929 """
1930 Abbreviation for index_set.
1931 
1932 >>> print(ist("{1,2,3}"))
1933 {1,2,3}
1934 """
1935 
1936 def e(obj):
1937  """
1938  Abbreviation for clifford(index_set(obj)).
1939 
1940  >>> print(e(1))
1941  {1}
1942  >>> print(e(-1))
1943  {-1}
1944  >>> print(e(0))
1945  1
1946  """
1947  return clifford(index_set(obj))
1948 
1949 def istpq(p, q):
1950  """
1951  Abbreviation for index_set({-q,...p}).
1952 
1953  >>> print(istpq(2,3))
1954  {-3,-2,-1,1,2}
1955  """
1956  return index_set(set(range(-q,p+1)))
1957 
1958 ninf3 = e(4) + e(-1) # Null infinity point in 3D Conformal Geometric Algebra [DL].
1959 nbar3 = e(4) - e(-1) # Null bar point in 3D Conformal Geometric Algebra [DL].
1960 
1961 # Doctest interface.
1962 def _test():
1963  import PyClical, doctest
1964  return doctest.testmod(PyClical)
1965 
1966 if __name__ == "__main__":
1967  _test()
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.
def __ior__(self, rhs)
Definition: PyClical.pyx:304
def __getitem__(self, idx)
Definition: PyClical.pyx:191
def __imul__(self, rhs)
Definition: PyClical.pyx:793
def __invert__(self)
Definition: PyClical.pyx:240
def __iand__(self, rhs)
Definition: PyClical.pyx:282
def involute(self)
Definition: PyClical.pyx:1107
def __pos__(self)
Definition: PyClical.pyx:731
def istpq(p, q)
Definition: PyClical.pyx:1949
String clifford_to_str(const Multivector_T &mv)
The "informal" string representation of Multivector_T mv.
Definition: PyClical.h:86
def count(self)
Definition: PyClical.pyx:315
String index_set_to_repr(const Index_Set_T &ist)
The “official” string representation of Index_Set_T ist.
Definition: PyClical.h:57
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 exp(const matrix_multi< Scalar_T, LO, HI, Tune_P > &val) -> const matrix_multi< Scalar_T, LO, HI, Tune_P >
Exponential of multivector.
auto asin(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse sine of multivector.
def __xor__(lhs, rhs)
Definition: PyClical.pyx:249
auto tan(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Tangent of multivector.
def __sub__(lhs, rhs)
Definition: PyClical.pyx:760
auto max_pos(const index_set< LO, HI > &ist) -> index_t
Maximum positive index, or 0 if none.
auto odd(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Odd part.
auto min_neg(const index_set< LO, HI > &ist) -> index_t
Minimum negative index, or 0 if none.
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.
def __idiv__(self, rhs)
Definition: PyClical.pyx:911
def __mul__(lhs, rhs)
Definition: PyClical.pyx:780
auto norm(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar_T norm == sum of norm of coordinates.
def sign_of_square(self)
Definition: PyClical.pyx:375
auto scalar(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Scalar part.
def reframe(self, ixt)
Definition: PyClical.pyx:649
auto atanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic tangent of multivector.
def count_pos(self)
Definition: PyClical.pyx:333
def outer_pow(self, m)
Definition: PyClical.pyx:1004
def __neg__(self)
Definition: PyClical.pyx:722
def __getitem__(self, ixt)
Definition: PyClical.pyx:707
def __xor__(lhs, rhs)
Definition: PyClical.pyx:866
auto even(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Even part.
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 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.
def __contains__(self, idx)
Definition: PyClical.pyx:210
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 sinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic sine of multivector.
def __truediv__(lhs, rhs)
Definition: PyClical.pyx:896
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.
def __and__(lhs, rhs)
Definition: PyClical.pyx:836
String clifford_to_repr(const Multivector_T &mv)
The “official” string representation of Multivector_T mv.
Definition: PyClical.h:75
def count_neg(self)
Definition: PyClical.pyx:324
def __dealloc__(self)
Definition: PyClical.pyx:621
def __str__(self)
Definition: PyClical.pyx:395
def isnan(self)
Definition: PyClical.pyx:1215
def __or__(lhs, rhs)
Definition: PyClical.pyx:939
def conj(self)
Definition: PyClical.pyx:1138
def __richcmp__(lhs, rhs, int, op)
Definition: PyClical.pyx:672
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.
def __or__(lhs, rhs)
Definition: PyClical.pyx:293
def __mod__(lhs, rhs)
Definition: PyClical.pyx:806
def __iadd__(self, rhs)
Definition: PyClical.pyx:751
auto atan(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse tangent of multivector.
def __imod__(self, rhs)
Definition: PyClical.pyx:821
auto tanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic tangent of multivector.
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 acosh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic cosine of 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 asinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic sine 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 compare(const index_set< LO, HI > &a, const index_set< LO, HI > &b) -> int
"lexicographic compare" eg. {3,4,5} is less than {3,7,8}
def inv(self)
Definition: PyClical.pyx:926
def __richcmp__(lhs, rhs, int, op)
Definition: PyClical.pyx:122
auto acos(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse cosine of multivector.
auto sqrt(const matrix_multi< Scalar_T, LO, HI, Tune_P > &val, const matrix_multi< Scalar_T, LO, HI, Tune_P > &i, bool prechecked) -> const matrix_multi< Scalar_T, LO, HI, Tune_P >
Square root of multivector with specified complexifier.
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.
def __str__(self)
Definition: PyClical.pyx:1244
def isinf(self)
Definition: PyClical.pyx:1206
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.
def sign_of_mult(self, rhs)
Definition: PyClical.pyx:366
def __cinit__(self, other=0)
Definition: PyClical.pyx:74
def __ixor__(self, rhs)
Definition: PyClical.pyx:881
Definitions for 3D Conformal Geometric Algebra [DL].
Definition: PyClical.h:99
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.
def hash_fn(self)
Definition: PyClical.pyx:360
def __repr__(self)
Definition: PyClical.pyx:1235
def __call__(self, grade)
Definition: PyClical.pyx:1020
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.
def __iter__(self)
Definition: PyClical.pyx:638
def truncated(self, limit)
Definition: PyClical.pyx:1195
def reverse(self)
Definition: PyClical.pyx:1123
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.
def scalar(self)
Definition: PyClical.pyx:1039
def __ixor__(self, rhs)
Definition: PyClical.pyx:260
def pure(self)
Definition: PyClical.pyx:1050
def __iter__(self)
Definition: PyClical.pyx:229
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}.
def __pow__(self, m, dummy)
Definition: PyClical.pyx:961
auto sin(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Sine of multivector.
auto approx_equal(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs) -> bool
Test for approximate equality of multivectors.
def max_abs(self)
Definition: PyClical.pyx:1184
def even(self)
Definition: PyClical.pyx:1061
def __dealloc__(self)
Definition: PyClical.pyx:116
def __ior__(self, rhs)
Definition: PyClical.pyx:950
def __setitem__(self, idx, val)
Definition: PyClical.pyx:179
def __contains__(self, x)
Definition: PyClical.pyx:627
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 log(const matrix_multi< Scalar_T, LO, HI, Tune_P > &val, const matrix_multi< Scalar_T, LO, HI, Tune_P > &i, bool prechecked) -> const matrix_multi< Scalar_T, LO, HI, Tune_P >
Natural logarithm of multivector with specified complexifier.
def __isub__(self, rhs)
Definition: PyClical.pyx:771
String index_set_to_str(const Index_Set_T &ist)
The "informal" string representation of Index_Set_T ist.
Definition: PyClical.h:66
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.
def pow(self, m)
Definition: PyClical.pyx:980
def norm(self)
Definition: PyClical.pyx:1164
def __cinit__(self, other=0, ixt=None)
Definition: PyClical.pyx:565
def index_set_hidden_doctests()
Definition: PyClical.pyx:406
def clifford_hidden_doctests()
Definition: PyClical.pyx:1253
def quad(self)
Definition: PyClical.pyx:1153
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.
def __add__(lhs, rhs)
Definition: PyClical.pyx:740
def e(obj)
Definition: PyClical.pyx:1936
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.
def frame(self)
Definition: PyClical.pyx:1224
def __and__(lhs, rhs)
Definition: PyClical.pyx:271
auto cos(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Cosine of multivector.
def _test()
Definition: PyClical.pyx:1962
Multivector_T cga3std(const Multivector_T &X)
Convert CGA3 null vector to standard Conformal Geometric Algebra null vector [DL (10.52)].
Definition: PyClical.h:114
def __repr__(self)
Definition: PyClical.pyx:384
def __iand__(self, rhs)
Definition: PyClical.pyx:851
def vector_part(self, frm=None)
Definition: PyClical.pyx:1079
Multivector_T agc3(const Multivector_T &X)
Convert CGA3 null vector to Euclidean 3D vector [DL (10.50)].
Definition: PyClical.h:126