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