glucat  0.8.4
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-2020 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 __version__ = "0.8.4"
34 
35 from PyClical cimport *
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 isnan(self):
1207  """
1208  Check if a multivector contains any IEEE NaN values.
1209 
1210  >>> clifford().isnan()
1211  False
1212  """
1213  return self.instance.isnan()
1214 
1215  def frame(self):
1216  """
1217  Subalgebra generated by all generators of terms of given multivector.
1218 
1219  >>> print(clifford("1+3{-1}+2{1,2}+4{-2,7}").frame())
1220  {-2,-1,1,2,7}
1221  >>> s=clifford("1+3{-1}+2{1,2}+4{-2,7}").frame(); type(s)
1222  <class 'PyClical.index_set'>
1223  """
1224  return index_set().wrap( self.instance.frame() )
1225 
1226  def __repr__(self):
1227  """
1228  The “official” string representation of self.
1229 
1230  >>> clifford("1+3{-1}+2{1,2}+4{-2,7}").__repr__()
1231  'clifford("1+3{-1}+2{1,2}+4{-2,7}")'
1232  """
1233  return clifford_to_repr( self.unwrap() ).decode()
1234 
1235  def __str__(self):
1236  """
1237  The “informal” string representation of self.
1238 
1239  >>> clifford("1+3{-1}+2{1,2}+4{-2,7}").__str__()
1240  '1+3{-1}+2{1,2}+4{-2,7}'
1241  """
1242  return clifford_to_str( self.unwrap() ).decode()
1243 
1245  """
1246  Tests for functions that Doctest cannot see.
1247 
1248  For clifford.__cinit__: Construct an object of type clifford.
1249 
1250  >>> print(clifford(2))
1251  2
1252  >>> print(clifford(2.0))
1253  2
1254  >>> print(clifford(1.0e-1))
1255  0.1
1256  >>> print(clifford("2"))
1257  2
1258  >>> print(clifford("2{1,2,3}"))
1259  2{1,2,3}
1260  >>> print(clifford(clifford("2{1,2,3}")))
1261  2{1,2,3}
1262  >>> print(clifford("-{1}"))
1263  -{1}
1264  >>> print(clifford(2,index_set({1,2})))
1265  2{1,2}
1266  >>> print(clifford([2,3],index_set({1,2})))
1267  2{1}+3{2}
1268  >>> print(clifford([1,2]))
1269  Traceback (most recent call last):
1270  ...
1271  TypeError: Cannot initialize clifford object from <class 'list'>.
1272  >>> print(clifford(None))
1273  Traceback (most recent call last):
1274  ...
1275  TypeError: Cannot initialize clifford object from <class 'NoneType'>.
1276  >>> print(clifford(None,[1,2]))
1277  Traceback (most recent call last):
1278  ...
1279  TypeError: Cannot initialize clifford object from (<class 'NoneType'>, <class 'list'>).
1280  >>> print(clifford([1,2],[1,2]))
1281  Traceback (most recent call last):
1282  ...
1283  TypeError: Cannot initialize clifford object from (<class 'list'>, <class 'list'>).
1284  >>> print(clifford(""))
1285  Traceback (most recent call last):
1286  ...
1287  ValueError: Cannot initialize clifford object from invalid string ''.
1288  >>> print(clifford("{"))
1289  Traceback (most recent call last):
1290  ...
1291  ValueError: Cannot initialize clifford object from invalid string '{'.
1292  >>> print(clifford("{1"))
1293  Traceback (most recent call last):
1294  ...
1295  ValueError: Cannot initialize clifford object from invalid string '{1'.
1296  >>> print(clifford("+"))
1297  Traceback (most recent call last):
1298  ...
1299  ValueError: Cannot initialize clifford object from invalid string '+'.
1300  >>> print(clifford("-"))
1301  Traceback (most recent call last):
1302  ...
1303  ValueError: Cannot initialize clifford object from invalid string '-'.
1304  >>> print(clifford("{1}+"))
1305  Traceback (most recent call last):
1306  ...
1307  ValueError: Cannot initialize clifford object from invalid string '{1}+'.
1308 
1309  For clifford.__richcmp__: Compare objects of type clifford.
1310 
1311  >>> clifford("{1}") == clifford("1{1}")
1312  True
1313  >>> clifford("{1}") != clifford("1.0{1}")
1314  False
1315  >>> clifford("{1}") != clifford("1.0")
1316  True
1317  >>> clifford("{1,2}") == None
1318  False
1319  >>> clifford("{1,2}") != None
1320  True
1321  >>> None == clifford("{1,2}")
1322  False
1323  >>> None != clifford("{1,2}")
1324  True
1325  """
1326  return
1327 
1328 cpdef inline inv(obj):
1329  """
1330  Geometric multiplicative inverse.
1331 
1332  >>> print(inv(clifford("{1}")))
1333  {1}
1334  >>> print(inv(clifford("{-1}")))
1335  -{-1}
1336  >>> print(inv(clifford("{-2,-1}")))
1337  -{-2,-1}
1338  >>> print(inv(clifford("{-1}+{1}")))
1339  nan
1340  """
1341  return clifford(obj).inv()
1342 
1343 cpdef inline scalar(obj):
1344  """
1345  Scalar part.
1346 
1347  >>> scalar(clifford("1+{1}+{1,2}"))
1348  1.0
1349  >>> scalar(clifford("{1,2}"))
1350  0.0
1351  """
1352  return clifford(obj).scalar()
1353 
1354 cpdef inline real(obj):
1355  """
1356  Real part: synonym for scalar part.
1357 
1358  >>> real(clifford("1+{1}+{1,2}"))
1359  1.0
1360  >>> real(clifford("{1,2}"))
1361  0.0
1362  """
1363  return clifford(obj).scalar()
1364 
1365 cpdef inline imag(obj):
1366  """
1367  Imaginary part: deprecated (always 0).
1368 
1369  >>> imag(clifford("1+{1}+{1,2}"))
1370  0.0
1371  >>> imag(clifford("{1,2}"))
1372  0.0
1373  """
1374  return 0.0
1375 
1376 cpdef inline pure(obj):
1377  """
1378  Pure part
1379 
1380  >>> print(pure(clifford("1+{1}+{1,2}")))
1381  {1}+{1,2}
1382  >>> print(pure(clifford("{1,2}")))
1383  {1,2}
1384  """
1385  return clifford(obj).pure()
1386 
1387 cpdef inline even(obj):
1388  """
1389  Even part of multivector, sum of even grade terms.
1390 
1391  >>> print(even(clifford("1+{1}+{1,2}")))
1392  1+{1,2}
1393  """
1394  return clifford(obj).even()
1395 
1396 cpdef inline odd(obj):
1397  """
1398  Odd part of multivector, sum of odd grade terms.
1399 
1400  >>> print(odd(clifford("1+{1}+{1,2}")))
1401  {1}
1402  """
1403  return clifford(obj).odd()
1404 
1405 cpdef inline involute(obj):
1406  """
1407  Main involution, each {i} is replaced by -{i} in each term, eg. {1}*{2} -> (-{2})*(-{1})
1408 
1409  >>> print(involute(clifford("{1}")))
1410  -{1}
1411  >>> print(involute(clifford("{2}") * clifford("{1}")))
1412  -{1,2}
1413  >>> print(involute(clifford("{1}") * clifford("{2}")))
1414  {1,2}
1415  >>> print(involute(clifford("1+{1}+{1,2}")))
1416  1-{1}+{1,2}
1417  """
1418  return clifford(obj).involute()
1419 
1420 cpdef inline reverse(obj):
1421  """
1422  Reversion, eg. {1}*{2} -> {2}*{1}
1423 
1424  >>> print(reverse(clifford("{1}")))
1425  {1}
1426  >>> print(reverse(clifford("{2}") * clifford("{1}")))
1427  {1,2}
1428  >>> print(reverse(clifford("{1}") * clifford("{2}")))
1429  -{1,2}
1430  >>> print(reverse(clifford("1+{1}+{1,2}")))
1431  1+{1}-{1,2}
1432  """
1433  return clifford(obj).reverse()
1434 
1435 cpdef inline conj(obj):
1436  """
1437  Conjugation, reverse o involute == involute o reverse.
1438 
1439  >>> print(conj(clifford("{1}")))
1440  -{1}
1441  >>> print(conj(clifford("{2}") * clifford("{1}")))
1442  {1,2}
1443  >>> print(conj(clifford("{1}") * clifford("{2}")))
1444  -{1,2}
1445  >>> print(conj(clifford("1+{1}+{1,2}")))
1446  1-{1}-{1,2}
1447  """
1448  return clifford(obj).conj()
1449 
1450 cpdef inline quad(obj):
1451  """
1452  Quadratic form == (rev(x)*x)(0).
1453 
1454  >>> print(quad(clifford("1+{1}+{1,2}")))
1455  3.0
1456  >>> print(quad(clifford("1+{-1}+{1,2}+{1,2,3}")))
1457  2.0
1458  """
1459  return clifford(obj).quad()
1460 
1461 cpdef inline norm(obj):
1462  """
1463  norm == sum of squares of coordinates.
1464 
1465  >>> norm(clifford("1+{1}+{1,2}"))
1466  3.0
1467  >>> norm(clifford("1+{-1}+{1,2}+{1,2,3}"))
1468  4.0
1469  """
1470  return clifford(obj).norm()
1471 
1472 cpdef inline abs(obj):
1473  """
1474  Absolute value of multivector: multivector 2-norm.
1475 
1476  >>> abs(clifford("1+{-1}+{1,2}+{1,2,3}"))
1477  2.0
1478  """
1479  return glucat.abs(toClifford(obj))
1480 
1481 cpdef inline max_abs(obj):
1482  """
1483  Maximum absolute value of coordinates multivector: multivector infinity-norm.
1484 
1485  >>> max_abs(clifford("1+{-1}+{1,2}+{1,2,3}"))
1486  1.0
1487  >>> max_abs(clifford("3+2{1}+{1,2}"))
1488  3.0
1489 
1490  """
1491  return glucat.max_abs(toClifford(obj))
1492 
1493 cpdef inline pow(obj, m):
1494  """
1495  Integer power of multivector: obj to the m.
1496 
1497  >>> x=clifford("{1}"); print(pow(x,2))
1498  1
1499  >>> x=clifford("2"); print(pow(x,2))
1500  4
1501  >>> x=clifford("2+{1}"); print(pow(x,0))
1502  1
1503  >>> x=clifford("2+{1}"); print(pow(x,1))
1504  2+{1}
1505  >>> x=clifford("2+{1}"); print(pow(x,2))
1506  5+4{1}
1507  >>> print(pow(clifford("1+{1}+{1,2}"),3))
1508  1+3{1}+3{1,2}
1509  >>> i=clifford("{1,2}"); print(exp(pi/2) * pow(i, i))
1510  1
1511  """
1512  try:
1513  math.pow(obj, m)
1514  except:
1515  return clifford(obj).pow(m)
1516 
1517 cpdef inline outer_pow(obj, m):
1518  """
1519  Outer product power of multivector.
1520 
1521  >>> print(outer_pow(clifford("1+{1}+{1,2}"),3))
1522  1+3{1}+3{1,2}
1523  """
1524  return clifford(obj).outer_pow(m)
1525 
1526 cpdef inline complexifier(obj):
1527  """
1528  Square root of -1 which commutes with all members of the frame of the given multivector.
1529 
1530  >>> print(complexifier(clifford(index_set({1}))))
1531  {1,2,3}
1532  >>> print(complexifier(clifford(index_set({-1}))))
1533  {-1}
1534  >>> print(complexifier(index_set({1})))
1535  {1,2,3}
1536  >>> print(complexifier(index_set({-1})))
1537  {-1}
1538  """
1539  return clifford().wrap( glucat.complexifier(toClifford(obj)) )
1540 
1541 cpdef inline sqrt(obj, i = None):
1542  """
1543  Square root of multivector with optional complexifier.
1544 
1545  >>> print(sqrt(-1))
1546  {-1}
1547  >>> print(sqrt(clifford("2{-1}")))
1548  1+{-1}
1549  >>> j=sqrt(-1,complexifier(index_set({1}))); print(j); print(j*j)
1550  {1,2,3}
1551  -1
1552  >>> j=sqrt(-1,"{1,2,3}"); print(j); print(j*j)
1553  {1,2,3}
1554  -1
1555  """
1556  if not (i is None):
1557  return clifford().wrap( glucat.sqrt(toClifford(obj), toClifford(i)) )
1558  else:
1559  try:
1560  return math.sqrt(obj)
1561  except:
1562  return clifford().wrap( glucat.sqrt(toClifford(obj)) )
1563 
1564 cpdef inline exp(obj):
1565  """
1566  Exponential of multivector.
1567 
1568  >>> x=clifford("{1,2}") * pi/4; print(exp(x))
1569  0.7071+0.7071{1,2}
1570  >>> x=clifford("{1,2}") * pi/2; print(exp(x))
1571  {1,2}
1572  """
1573  try:
1574  return math.exp(obj)
1575  except:
1576  return clifford().wrap( glucat.exp(toClifford(obj)) )
1577 
1578 cpdef inline log(obj,i = None):
1579  """
1580  Natural logarithm of multivector with optional complexifier.
1581 
1582  >>> x=clifford("{-1}"); print((log(x,"{-1}") * 2/pi))
1583  {-1}
1584  >>> x=clifford("{1,2}"); print((log(x,"{1,2,3}") * 2/pi))
1585  {1,2}
1586  >>> x=clifford("{1,2}"); print((log(x) * 2/pi))
1587  {1,2}
1588  >>> x=clifford("{1,2}"); print((log(x,"{1,2}") * 2/pi))
1589  Traceback (most recent call last):
1590  ...
1591  RuntimeError: check_complex(val, i): i is not a valid complexifier for val
1592  """
1593  if not (i is None):
1594  return clifford().wrap( glucat.log(toClifford(obj), toClifford(i)) )
1595  else:
1596  try:
1597  return math.log(obj)
1598  except:
1599  return clifford().wrap( glucat.log(toClifford(obj)) )
1600 
1601 cpdef inline cos(obj,i = None):
1602  """
1603  Cosine of multivector with optional complexifier.
1604 
1605  >>> x=clifford("{1,2}"); print(cos(acos(x),"{1,2,3}"))
1606  {1,2}
1607  >>> x=clifford("{1,2}"); print(cos(acos(x)))
1608  {1,2}
1609  """
1610  if not (i is None):
1611  return clifford().wrap( glucat.cos(toClifford(obj), toClifford(i)) )
1612  else:
1613  try:
1614  return math.cos(obj)
1615  except:
1616  return clifford().wrap( glucat.cos(toClifford(obj)) )
1617 
1618 cpdef inline acos(obj,i = None):
1619  """
1620  Inverse cosine of multivector with optional complexifier.
1621 
1622  >>> x=clifford("{1,2}"); print(cos(acos(x),"{1,2,3}"))
1623  {1,2}
1624  >>> x=clifford("{1,2}"); print(cos(acos(x),"{-1,1,2,3,4}"))
1625  {1,2}
1626  >>> print(acos(0) / pi)
1627  0.5
1628  >>> x=clifford("{1,2}"); print(cos(acos(x)))
1629  {1,2}
1630  """
1631  if not (i is None):
1632  return clifford().wrap( glucat.acos(toClifford(obj), toClifford(i)) )
1633  else:
1634  try:
1635  return math.acos(obj)
1636  except:
1637  return clifford().wrap( glucat.acos(toClifford(obj)) )
1638 
1639 cpdef inline cosh(obj):
1640  """
1641  Hyperbolic cosine of multivector.
1642 
1643  >>> x=clifford("{1,2}") * pi; print(cosh(x))
1644  -1
1645  >>> x=clifford("{1,2,3}"); print(cosh(acosh(x)))
1646  {1,2,3}
1647  >>> x=clifford("{1,2}"); print(cosh(acosh(x)))
1648  {1,2}
1649  """
1650  try:
1651  return math.cosh(obj)
1652  except:
1653  return clifford().wrap( glucat.cosh(toClifford(obj)) )
1654 
1655 cpdef inline acosh(obj,i = None):
1656  """
1657  Inverse hyperbolic cosine of multivector with optional complexifier.
1658 
1659  >>> print(acosh(0,"{-2,-1,1}"))
1660  1.571{-2,-1,1}
1661  >>> x=clifford("{1,2,3}"); print(cosh(acosh(x,"{-1,1,2,3,4}")))
1662  {1,2,3}
1663  >>> print(acosh(0))
1664  1.571{-1}
1665  >>> x=clifford("{1,2,3}"); print(cosh(acosh(x)))
1666  {1,2,3}
1667  >>> x=clifford("{1,2}"); print(cosh(acosh(x)))
1668  {1,2}
1669  """
1670  if not (i is None):
1671  return clifford().wrap( glucat.acosh(toClifford(obj), toClifford(i)) )
1672  else:
1673  try:
1674  return math.acosh(obj)
1675  except:
1676  return clifford().wrap( glucat.acosh(toClifford(obj)) )
1677 
1678 cpdef inline sin(obj,i = None):
1679  """
1680  Sine of multivector with optional complexifier.
1681 
1682  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),s))
1683  {-1}
1684  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),"{-2,-1,1}"))
1685  {-1}
1686  >>> x=clifford("{1,2,3}"); print(asin(sin(x)))
1687  {1,2,3}
1688  """
1689  if not (i is None):
1690  return clifford().wrap( glucat.sin(toClifford(obj), toClifford(i)) )
1691  else:
1692  try:
1693  return math.sin(obj)
1694  except:
1695  return clifford().wrap( glucat.sin(toClifford(obj)) )
1696 
1697 cpdef inline asin(obj,i = None):
1698  """
1699  Inverse sine of multivector with optional complexifier.
1700 
1701  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),s))
1702  {-1}
1703  >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),"{-2,-1,1}"))
1704  {-1}
1705  >>> print(asin(1) / pi)
1706  0.5
1707  >>> x=clifford("{1,2,3}"); print(asin(sin(x)))
1708  {1,2,3}
1709  """
1710  if not (i is None):
1711  return clifford().wrap( glucat.asin(toClifford(obj), toClifford(i)) )
1712  else:
1713  try:
1714  return math.asin(obj)
1715  except:
1716  return clifford().wrap( glucat.asin(toClifford(obj)) )
1717 
1718 cpdef inline sinh(obj):
1719  """
1720  Hyperbolic sine of multivector.
1721 
1722  >>> x=clifford("{1,2}") * pi/2; print(sinh(x))
1723  {1,2}
1724  >>> x=clifford("{1,2}") * pi/6; print(sinh(x))
1725  0.5{1,2}
1726  """
1727  try:
1728  return math.sinh(obj)
1729  except:
1730  return clifford().wrap( glucat.sinh(toClifford(obj)) )
1731 
1732 cpdef inline asinh(obj,i = None):
1733  """
1734  Inverse hyperbolic sine of multivector with optional complexifier.
1735 
1736  >>> x=clifford("{1,2}"); print(asinh(x,"{1,2,3}") * 2/pi)
1737  {1,2}
1738  >>> x=clifford("{1,2}"); print(asinh(x) * 2/pi)
1739  {1,2}
1740  >>> x=clifford("{1,2}") / 2; print(asinh(x) * 6/pi)
1741  {1,2}
1742  """
1743  if not (i is None):
1744  return clifford().wrap( glucat.asinh(toClifford(obj), toClifford(i)) )
1745  else:
1746  try:
1747  return math.asinh(obj)
1748  except:
1749  return clifford().wrap( glucat.asinh(toClifford(obj)) )
1750 
1751 cpdef inline tan(obj,i = None):
1752  """
1753  Tangent of multivector with optional complexifier.
1754 
1755  >>> x=clifford("{1,2}"); print(tan(x,"{1,2,3}"))
1756  0.7616{1,2}
1757  >>> x=clifford("{1,2}"); print(tan(x))
1758  0.7616{1,2}
1759  """
1760  if not (i is None):
1761  return clifford().wrap( glucat.tan(toClifford(obj), toClifford(i)) )
1762  else:
1763  try:
1764  return math.tan(obj)
1765  except:
1766  return clifford().wrap( glucat.tan(toClifford(obj)) )
1767 
1768 cpdef inline atan(obj,i = None):
1769  """
1770  Inverse tangent of multivector with optional complexifier.
1771 
1772  >>> s=index_set({1,2,3}); x=clifford("{1}"); print(tan(atan(x,s),s))
1773  {1}
1774  >>> x=clifford("{1}"); print(tan(atan(x)))
1775  {1}
1776  """
1777  if not (i is None):
1778  return clifford().wrap( glucat.atan(toClifford(obj), toClifford(i)) )
1779  else:
1780  try:
1781  return math.atan(obj)
1782  except:
1783  return clifford().wrap( glucat.atan(toClifford(obj)) )
1784 
1785 cpdef inline tanh(obj):
1786  """
1787  Hyperbolic tangent of multivector.
1788 
1789  >>> x=clifford("{1,2}") * pi/4; print(tanh(x))
1790  {1,2}
1791  """
1792  try:
1793  return math.tanh(obj)
1794  except:
1795  return clifford().wrap( glucat.tanh(toClifford(obj)) )
1796 
1797 cpdef inline atanh(obj,i = None):
1798  """
1799  Inverse hyperbolic tangent of multivector with optional complexifier.
1800 
1801  >>> s=index_set({1,2,3}); x=clifford("{1,2}"); print(tanh(atanh(x,s)))
1802  {1,2}
1803  >>> x=clifford("{1,2}"); print(tanh(atanh(x)))
1804  {1,2}
1805  """
1806  if not (i is None):
1807  return clifford().wrap( glucat.atanh(toClifford(obj), toClifford(i)) )
1808  else:
1809  try:
1810  return math.atanh(obj)
1811  except:
1812  return clifford().wrap( glucat.atanh(toClifford(obj)) )
1813 
1814 cpdef inline random_clifford(index_set ixt, fill = 1.0):
1815  """
1816  Random multivector within a frame.
1817 
1818  >>> print(random_clifford(index_set({-3,-1,2})).frame())
1819  {-3,-1,2}
1820  """
1821  return clifford().wrap( clifford().instance.random(ixt.unwrap(), <scalar_t>fill) )
1822 
1823 cpdef inline cga3(obj):
1824  """
1825  Convert Euclidean 3D multivector to Conformal Geometric Algebra using Doran and Lasenby definition.
1826 
1827  >>> x=clifford("2{1}+9{2}+{3}"); print(cga3(x))
1828  87{-1}+4{1}+18{2}+2{3}+85{4}
1829  """
1830  return clifford().wrap( glucat.cga3(toClifford(obj)) )
1831 
1832 cpdef inline cga3std(obj):
1833  """
1834  Convert CGA3 null vector to standard conformal null vector using Doran and Lasenby definition.
1835 
1836  >>> x=clifford("2{1}+9{2}+{3}"); print(cga3std(cga3(x)))
1837  87{-1}+4{1}+18{2}+2{3}+85{4}
1838  >>> x=clifford("2{1}+9{2}+{3}"); print(cga3std(cga3(x))-cga3(x))
1839  0
1840  """
1841  return clifford().wrap( glucat.cga3std(toClifford(obj)) )
1842 
1843 cpdef inline agc3(obj):
1844  """
1845  Convert CGA3 null vector to Euclidean 3D vector using Doran and Lasenby definition.
1846 
1847  >>> x=clifford("2{1}+9{2}+{3}"); print(agc3(cga3(x)))
1848  2{1}+9{2}+{3}
1849  >>> x=clifford("2{1}+9{2}+{3}"); print(agc3(cga3(x))-x)
1850  0
1851  """
1852  return clifford().wrap( glucat.agc3(toClifford(obj)) )
1853 
1854 # Some abbreviations.
1855 scalar_epsilon = epsilon
1856 
1857 pi = atan(clifford(1.0)) * 4.0
1858 tau = atan(clifford(1.0)) * 8.0
1859 
1860 cl = clifford
1861 """
1862 Abbreviation for clifford.
1863 
1864 >>> print(cl(2))
1865 2
1866 >>> print(cl(2.0))
1867 2
1868 >>> print(cl(5.0e-1))
1869 0.5
1870 >>> print(cl("2"))
1871 2
1872 >>> print(cl("2{1,2,3}"))
1873 2{1,2,3}
1874 >>> print(cl(cl("2{1,2,3}")))
1875 2{1,2,3}
1876 """
1877 
1878 ist = index_set
1879 """
1880 Abbreviation for index_set.
1881 
1882 >>> print(ist("{1,2,3}"))
1883 {1,2,3}
1884 """
1885 
1886 def e(obj):
1887  """
1888  Abbreviation for clifford(index_set(obj)).
1889 
1890  >>> print(e(1))
1891  {1}
1892  >>> print(e(-1))
1893  {-1}
1894  >>> print(e(0))
1895  1
1896  """
1897  return clifford(index_set(obj))
1898 
1899 def istpq(p, q):
1900  """
1901  Abbreviation for index_set({-q,...p}).
1902 
1903  >>> print(istpq(2,3))
1904  {-3,-2,-1,1,2}
1905  """
1906  return index_set(set(range(-q,p+1)))
1907 
1908 ninf3 = e(4) + e(-1) # Null infinity point in 3D Conformal Geometric Algebra [DL].
1909 nbar3 = e(4) - e(-1) # Null bar point in 3D Conformal Geometric Algebra [DL].
1910 
1911 # Doctest interface.
1912 def _test():
1913  import PyClical, doctest
1914  return doctest.testmod(PyClical)
1915 
1916 if __name__ == "__main__":
1917  _test()
PyClical.index_set.__contains__
def __contains__(self, idx)
Definition: PyClical.pyx:210
glucat::inv
const Multivector< Scalar_T, LO, HI > inv(const Multivector< Scalar_T, LO, HI > &val)
Geometric multiplicative inverse.
Definition: clifford_algebra_imp.h:350
PyClical.clifford.__iadd__
def __iadd__(self, rhs)
Definition: PyClical.pyx:751
glucat::acos
const Multivector< Scalar_T, LO, HI > acos(const Multivector< Scalar_T, LO, HI > &val)
Inverse cosine of multivector.
Definition: clifford_algebra_imp.h:847
glucat::asin
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.
Definition: clifford_algebra_imp.h:934
glucat::min_neg
index_t min_neg(const index_set< LO, HI > &ist)
Minimum negative index, or 0 if none.
Definition: index_set_imp.h:996
PyClical.index_set.max
def max(self)
Definition: PyClical.pyx:351
PyClical.clifford_hidden_doctests
def clifford_hidden_doctests()
Definition: PyClical.pyx:1244
PyClical.clifford.__mod__
def __mod__(lhs, rhs)
Definition: PyClical.pyx:806
PyClical.e
def e(obj)
Definition: PyClical.pyx:1886
PyClical.clifford.__ixor__
def __ixor__(self, rhs)
Definition: PyClical.pyx:881
PyClical.clifford.__pow__
def __pow__(self, m, dummy)
Definition: PyClical.pyx:961
PyClical.clifford.scalar
def scalar(self)
Definition: PyClical.pyx:1039
clifford_to_repr
String clifford_to_repr(const Multivector_T &mv)
The “official” string representation of Multivector_T mv.
Definition: PyClical.h:88
PyClical.clifford.__repr__
def __repr__(self)
Definition: PyClical.pyx:1226
glucat::atan
const Multivector< Scalar_T, LO, HI > atan(const Multivector< Scalar_T, LO, HI > &val)
Inverse tangent of multivector.
Definition: clifford_algebra_imp.h:1054
PyClical.clifford.__call__
def __call__(self, grade)
Definition: PyClical.pyx:1020
glucat::scalar
Scalar_T scalar(const Multivector< Scalar_T, LO, HI > &val)
Scalar part.
Definition: clifford_algebra_imp.h:421
PyClical.index_set.sign_of_mult
def sign_of_mult(self, rhs)
Definition: PyClical.pyx:366
PyClical.clifford.__richcmp__
def __richcmp__(lhs, rhs, int, op)
Definition: PyClical.pyx:672
PyClical.index_set.__cinit__
def __cinit__(self, other=0)
Definition: PyClical.pyx:74
PyClical.clifford.odd
def odd(self)
Definition: PyClical.pyx:1070
PyClical.clifford.norm
def norm(self)
Definition: PyClical.pyx:1164
PyClical.index_set.__iter__
def __iter__(self)
Definition: PyClical.pyx:229
glucat::atan
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.
Definition: clifford_algebra_imp.h:1034
PyClical.clifford.truncated
def truncated(self, limit)
Definition: PyClical.pyx:1195
glucat::sin
const Multivector< Scalar_T, LO, HI > sin(const Multivector< Scalar_T, LO, HI > &val)
Sine of multivector.
Definition: clifford_algebra_imp.h:925
PyClical.index_set.hash_fn
def hash_fn(self)
Definition: PyClical.pyx:360
glucat::sqrt
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.
Definition: matrix_multi_imp.h:1603
glucat::complexifier
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.
Definition: clifford_algebra_imp.h:535
PyClical.index_set.instance
instance
Definition: PyClical.pyx:95
PyClical.clifford.__iand__
def __iand__(self, rhs)
Definition: PyClical.pyx:851
glucat::involute
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})
Definition: clifford_algebra_imp.h:480
PyClical.clifford.max_abs
def max_abs(self)
Definition: PyClical.pyx:1184
PyClical.clifford.frame
def frame(self)
Definition: PyClical.pyx:1215
index_set_to_str
String index_set_to_str(const Index_Set_T &ist)
The "informal" string representation of Index_Set_T ist.
Definition: PyClical.h:79
glucat::cos
const Multivector< Scalar_T, LO, HI > cos(const Multivector< Scalar_T, LO, HI > &val)
Cosine of multivector.
Definition: clifford_algebra_imp.h:818
glucat::max_pos
index_t max_pos(const index_set< LO, HI > &ist)
Maximum positive index, or 0 if none.
Definition: index_set_imp.h:1003
glucat::tan
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.
Definition: clifford_algebra_imp.h:1006
glucat::real
Scalar_T real(const Multivector< Scalar_T, LO, HI > &val)
Real part: synonym for scalar part.
Definition: clifford_algebra_imp.h:429
PyClical.clifford.__contains__
def __contains__(self, x)
Definition: PyClical.pyx:627
PyClical.index_set.__setitem__
def __setitem__(self, idx, val)
Definition: PyClical.pyx:179
PyClical._test
def _test()
Definition: PyClical.pyx:1912
PyClical.clifford.__cinit__
def __cinit__(self, other=0, ixt=None)
Definition: PyClical.pyx:565
glucat::acos
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.
Definition: clifford_algebra_imp.h:827
PyClical.index_set
Definition: PyClical.pyx:40
cga3
Definitions for 3D Conformal Geometric Algebra [DL].
Definition: PyClical.h:113
glucat::log
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.
Definition: matrix_multi_imp.h:2026
PyClical.index_set.__ixor__
def __ixor__(self, rhs)
Definition: PyClical.pyx:260
PyClical.clifford.pow
def pow(self, m)
Definition: PyClical.pyx:980
PyClical.clifford.even
def even(self)
Definition: PyClical.pyx:1061
PyClical.clifford.__str__
def __str__(self)
Definition: PyClical.pyx:1235
glucat::asinh
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.
Definition: clifford_algebra_imp.h:874
PyClical.clifford.__isub__
def __isub__(self, rhs)
Definition: PyClical.pyx:771
glucat::even
const Multivector< Scalar_T, LO, HI > even(const Multivector< Scalar_T, LO, HI > &val)
Even part.
Definition: clifford_algebra_imp.h:456
PyClical.clifford.__iter__
def __iter__(self)
Definition: PyClical.pyx:638
PyClical.clifford.__ior__
def __ior__(self, rhs)
Definition: PyClical.pyx:950
glucat::max_abs
Scalar_T max_abs(const Multivector< Scalar_T, LO, HI > &val)
Maximum of absolute values of components of multivector: multivector infinity norm.
Definition: clifford_algebra_imp.h:528
PyClical.clifford.instance
instance
Definition: PyClical.pyx:592
PyClical.clifford.__neg__
def __neg__(self)
Definition: PyClical.pyx:722
PyClical.index_set.__dealloc__
def __dealloc__(self)
Definition: PyClical.pyx:116
PyClical.clifford.pure
def pure(self)
Definition: PyClical.pyx:1050
glucat::pure
const Multivector< Scalar_T, LO, HI > pure(const Multivector< Scalar_T, LO, HI > &val)
Pure part.
Definition: clifford_algebra_imp.h:448
glucat::cosh
const Multivector< Scalar_T, LO, HI > cosh(const Multivector< Scalar_T, LO, HI > &val)
Hyperbolic cosine of multivector.
Definition: clifford_algebra_imp.h:749
PyClical.clifford.involute
def involute(self)
Definition: PyClical.pyx:1107
PyClical.clifford.__add__
def __add__(lhs, rhs)
Definition: PyClical.pyx:740
PyClical.index_set.__xor__
def __xor__(lhs, rhs)
Definition: PyClical.pyx:249
PyClical.index_set.__iand__
def __iand__(self, rhs)
Definition: PyClical.pyx:282
PyClical.clifford.quad
def quad(self)
Definition: PyClical.pyx:1153
PyClical.index_set.min
def min(self)
Definition: PyClical.pyx:342
PyClical.index_set.count
def count(self)
Definition: PyClical.pyx:315
glucat::acosh
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.
Definition: clifford_algebra_imp.h:767
PyClical.clifford.__sub__
def __sub__(lhs, rhs)
Definition: PyClical.pyx:760
PyClical.index_set.__and__
def __and__(lhs, rhs)
Definition: PyClical.pyx:271
cga3::cga3std
Multivector_T cga3std(const Multivector_T &X)
Convert CGA3 null vector to standard Conformal Geometric Algebra null vector [DL (10....
Definition: PyClical.h:127
glucat::sinh
const Multivector< Scalar_T, LO, HI > sinh(const Multivector< Scalar_T, LO, HI > &val)
Hyperbolic sine of multivector.
Definition: clifford_algebra_imp.h:855
glucat::exp
const matrix_multi< Scalar_T, LO, HI > exp(const matrix_multi< Scalar_T, LO, HI > &val)
Exponential of multivector.
Definition: matrix_multi_imp.h:2143
PyClical.index_set.__getitem__
def __getitem__(self, idx)
Definition: PyClical.pyx:191
glucat::compare
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}
Definition: index_set_imp.h:602
glucat::abs
Scalar_T abs(const Multivector< Scalar_T, LO, HI > &val)
Absolute value == sqrt(norm)
Definition: clifford_algebra_imp.h:520
PyClical.clifford.isnan
def isnan(self)
Definition: PyClical.pyx:1206
PyClical.clifford.__mul__
def __mul__(lhs, rhs)
Definition: PyClical.pyx:780
glucat::asinh
const Multivector< Scalar_T, LO, HI > asinh(const Multivector< Scalar_T, LO, HI > &val)
Inverse hyperbolic sine of multivector.
Definition: clifford_algebra_imp.h:894
PyClical.index_set.__repr__
def __repr__(self)
Definition: PyClical.pyx:384
PyClical.clifford.__getitem__
def __getitem__(self, ixt)
Definition: PyClical.pyx:707
glucat::sqrt
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.
Definition: clifford_algebra_imp.h:618
PyClical.index_set.__ior__
def __ior__(self, rhs)
Definition: PyClical.pyx:304
PyClical.clifford.vector_part
def vector_part(self, frm=None)
Definition: PyClical.pyx:1079
glucat::norm
Scalar_T norm(const Multivector< Scalar_T, LO, HI > &val)
Scalar_T norm == sum of norm of coordinates.
Definition: clifford_algebra_imp.h:512
PyClical.clifford.__pos__
def __pos__(self)
Definition: PyClical.pyx:731
glucat::log
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.
Definition: clifford_algebra_imp.h:733
PyClical.index_set.__invert__
def __invert__(self)
Definition: PyClical.pyx:240
glucat::quad
Scalar_T quad(const Multivector< Scalar_T, LO, HI > &val)
Scalar_T quadratic form == (rev(x)*x)(0)
Definition: clifford_algebra_imp.h:504
glucat::odd
const Multivector< Scalar_T, LO, HI > odd(const Multivector< Scalar_T, LO, HI > &val)
Odd part.
Definition: clifford_algebra_imp.h:464
clifford_to_str
String clifford_to_str(const Multivector_T &mv)
The "informal" string representation of Multivector_T mv.
Definition: PyClical.h:99
PyClical.index_set_hidden_doctests
def index_set_hidden_doctests()
Definition: PyClical.pyx:406
glucat::conj
const Multivector< Scalar_T, LO, HI > conj(const Multivector< Scalar_T, LO, HI > &val)
Conjugation, rev o invo == invo o rev.
Definition: clifford_algebra_imp.h:496
index_set_to_repr
String index_set_to_repr(const Index_Set_T &ist)
The “official” string representation of Index_Set_T ist.
Definition: PyClical.h:70
PyClical.clifford.__idiv__
def __idiv__(self, rhs)
Definition: PyClical.pyx:911
cga3::agc3
Multivector_T agc3(const Multivector_T &X)
Convert CGA3 null vector to Euclidean 3D vector [DL (10.50)].
Definition: PyClical.h:139
glucat::acosh
const Multivector< Scalar_T, LO, HI > acosh(const Multivector< Scalar_T, LO, HI > &val)
Inverse hyperbolic cosine of multivector.
Definition: clifford_algebra_imp.h:787
glucat::atanh
const Multivector< Scalar_T, LO, HI > atanh(const Multivector< Scalar_T, LO, HI > &val)
Inverse hyperbolic tangent of multivector.
Definition: clifford_algebra_imp.h:998
PyClical.clifford
Definition: PyClical.pyx:534
PyClical.index_set.__str__
def __str__(self)
Definition: PyClical.pyx:395
PyClical.clifford.__and__
def __and__(lhs, rhs)
Definition: PyClical.pyx:836
PyClical.clifford.__dealloc__
def __dealloc__(self)
Definition: PyClical.pyx:621
glucat::tan
const Multivector< Scalar_T, LO, HI > tan(const Multivector< Scalar_T, LO, HI > &val)
Tangent of multivector.
Definition: clifford_algebra_imp.h:1025
PyClical.clifford.inv
def inv(self)
Definition: PyClical.pyx:926
PyClical.clifford.__imul__
def __imul__(self, rhs)
Definition: PyClical.pyx:793
glucat::asin
const Multivector< Scalar_T, LO, HI > asin(const Multivector< Scalar_T, LO, HI > &val)
Inverse sine of multivector.
Definition: clifford_algebra_imp.h:954
glucat::pow
const Multivector< Scalar_T, LO, HI > pow(const Multivector< Scalar_T, LO, HI > &lhs, int rhs)
Integer power of multivector.
Definition: clifford_algebra_imp.h:357
PyClical.clifford.abs
def abs(self)
Definition: PyClical.pyx:1175
glucat::sin
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.
Definition: clifford_algebra_imp.h:901
PyClical.index_set.sign_of_square
def sign_of_square(self)
Definition: PyClical.pyx:375
glucat::atanh
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.
Definition: clifford_algebra_imp.h:981
PyClical.clifford.__imod__
def __imod__(self, rhs)
Definition: PyClical.pyx:821
PyClical.clifford.__truediv__
def __truediv__(lhs, rhs)
Definition: PyClical.pyx:896
glucat::reverse
const Multivector< Scalar_T, LO, HI > reverse(const Multivector< Scalar_T, LO, HI > &val)
Reversion, eg. {1}*{2} -> {2}*{1}.
Definition: clifford_algebra_imp.h:488
PyClical.clifford.reverse
def reverse(self)
Definition: PyClical.pyx:1123
PyClical.index_set.count_pos
def count_pos(self)
Definition: PyClical.pyx:333
PyClical.istpq
def istpq(p, q)
Definition: PyClical.pyx:1899
PyClical.clifford.__xor__
def __xor__(lhs, rhs)
Definition: PyClical.pyx:866
glucat::cos
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.
Definition: clifford_algebra_imp.h:794
glucat::exp
const framed_multi< Scalar_T, LO, HI > exp(const framed_multi< Scalar_T, LO, HI > &val)
Exponential of multivector.
Definition: framed_multi_imp.h:1977
PyClical.clifford.__or__
def __or__(lhs, rhs)
Definition: PyClical.pyx:939
PyClical.clifford.conj
def conj(self)
Definition: PyClical.pyx:1138
glucat::imag
Scalar_T imag(const Multivector< Scalar_T, LO, HI > &val)
Imaginary part: deprecated (always 0)
Definition: clifford_algebra_imp.h:440
glucat::tanh
const Multivector< Scalar_T, LO, HI > tanh(const Multivector< Scalar_T, LO, HI > &val)
Hyperbolic tangent of multivector.
Definition: clifford_algebra_imp.h:962
PyClical.clifford.outer_pow
def outer_pow(self, m)
Definition: PyClical.pyx:1004
PyClical.index_set.count_neg
def count_neg(self)
Definition: PyClical.pyx:324
glucat::outer_pow
const Multivector< Scalar_T, LO, HI > outer_pow(const Multivector< Scalar_T, LO, HI > &lhs, int rhs)
Outer product power of multivector.
Definition: clifford_algebra_imp.h:413
PyClical.clifford.reframe
def reframe(self, ixt)
Definition: PyClical.pyx:649
PyClical.index_set.__richcmp__
def __richcmp__(lhs, rhs, int, op)
Definition: PyClical.pyx:122
PyClical.index_set.__or__
def __or__(lhs, rhs)
Definition: PyClical.pyx:293