33from PyClical cimport *
35__version__ = str(glucat_package_version,
'utf-8')
40cdef inline IndexSet toIndexSet(obj):
42 Return the C++ IndexSet instance wrapped by index_set(obj).
48 Python class index_set wraps C++ class IndexSet.
50 cdef IndexSet *instance
52 cdef inline wrap(index_set self, IndexSet other):
54 Wrap an instance of the C++ class IndexSet.
59 cdef inline IndexSet unwrap(index_set self):
61 Return the wrapped C++ IndexSet instance.
65 cpdef copy(index_set self):
67 Copy this index_set object.
69 >>> s=index_set(1); t=s.copy(); print(t)
76 Construct an object of type index_set.
78 >>> print(index_set(1))
80 >>> print(index_set({1,2}))
82 >>> print(index_set(index_set({1,2})))
84 >>> print(index_set({1,2}))
86 >>> print(index_set({1,2,1}))
88 >>> print(index_set("{1,2,1}"))
90 >>> print(index_set(""))
93 error_msg_prefix =
"Cannot initialize index_set object from"
94 if isinstance(other, index_set):
96 elif isinstance(other, numbers.Integral):
98 elif isinstance(other, (set, frozenset)):
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):
109 bother = other.encode(
"UTF-8")
112 raise ValueError(error_msg_prefix +
" invalid string " + repr(other) +
".")
114 raise TypeError(error_msg_prefix +
" " + str(type(other)) +
".")
118 Clean up by deallocating the instance of C++ class IndexSet.
124 Compare two objects of class index_set.
126 >>> index_set(1) == index_set({1})
128 >>> index_set({1}) != index_set({1})
130 >>> index_set({1}) != index_set({2})
132 >>> index_set({1}) == index_set({2})
134 >>> index_set({1}) < index_set({2})
136 >>> index_set({1}) <= index_set({2})
138 >>> index_set({1}) > index_set({2})
140 >>> index_set({1}) >= index_set({2})
143 if (lhs
is None)
or (rhs
is None):
144 eq = bool(lhs
is rhs)
159 return NotImplemented
161 eq = bool( toIndexSet(lhs) == toIndexSet(rhs) )
167 lt = bool( toIndexSet(lhs) < toIndexSet(rhs) )
173 return not (lt
or eq)
177 return NotImplemented
181 Set the value of an index_set object at index idx to value val.
183 >>> s=index_set({1}); s[2] = True; print(s)
185 >>> s=index_set({1,2}); s[1] = False; print(s)
193 Get the value of an index_set object at an index.
195 >>> index_set({1})[1]
197 >>> index_set({1})[2]
199 >>> index_set({2})[-1]
201 >>> index_set({2})[1]
203 >>> index_set({2})[2]
205 >>> index_set({2})[33]
212 Check that an index_set object contains the index idx: idx in self.
214 >>> 1 in index_set({1})
216 >>> 2 in index_set({1})
218 >>> -1 in index_set({2})
220 >>> 1 in index_set({2})
222 >>> 2 in index_set({2})
224 >>> 33 in index_set({2})
231 Iterate over the indices of an index_set.
233 >>> for i in index_set({-3,4,7}):print(i, end=",")
236 for idx
in range(self.
min(), self.
max()+1):
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}
251 Symmetric set difference: exclusive or.
253 >>> print(index_set({1}) ^ index_set({2}))
255 >>> print(index_set({1,2}) ^ index_set({2}))
258 return index_set().wrap( toIndexSet(lhs) ^ toIndexSet(rhs) )
262 Symmetric set difference: exclusive or.
264 >>> x = index_set({1}); x ^= index_set({2}); print(x)
266 >>> x = index_set({1,2}); x ^= index_set({2}); print(x)
269 return self.wrap( self.unwrap() ^ toIndexSet(rhs) )
273 Set intersection: and.
275 >>> print(index_set({1}) & index_set({2}))
277 >>> print(index_set({1,2}) & index_set({2}))
280 return index_set().wrap( toIndexSet(lhs) & toIndexSet(rhs) )
284 Set intersection: and.
286 >>> x = index_set({1}); x &= index_set({2}); print(x)
288 >>> x = index_set({1,2}); x &= index_set({2}); print(x)
291 return self.wrap( self.unwrap() & toIndexSet(rhs) )
297 >>> print(index_set({1}) | index_set({2}))
299 >>> print(index_set({1,2}) | index_set({2}))
302 return index_set().wrap( toIndexSet(lhs) | toIndexSet(rhs) )
308 >>> x = index_set({1}); x |= index_set({2}); print(x)
310 >>> x = index_set({1,2}); x |= index_set({2}); print(x)
313 return self.wrap( self.unwrap() | toIndexSet(rhs) )
317 Cardinality: Number of indices included in set.
319 >>> index_set({-1,1,2}).count()
326 Number of negative indices included in set.
328 >>> index_set({-1,1,2}).count_neg()
335 Number of positive indices included in set.
337 >>> index_set({-1,1,2}).count_pos()
346 >>> index_set({-1,1,2}).min()
355 >>> index_set({-1,1,2}).max()
368 Sign of geometric product of two Clifford basis elements.
370 >>> s = index_set({1,2}); t=index_set({-1}); s.sign_of_mult(t)
377 Sign of geometric square of a Clifford basis element.
379 >>> s = index_set({1,2}); s.sign_of_square()
386 The “official” string representation of self.
388 >>> index_set({1,2}).__repr__()
390 >>> repr(index_set({1,2}))
397 The “informal” string representation of self.
399 >>> index_set({1,2}).__str__()
401 >>> str(index_set({1,2}))
408 Tests for functions that Doctest cannot see.
410 For index_set.__cinit__: Construct index_set.
412 >>> print(index_set(1))
414 >>> print(index_set({1,2}))
416 >>> print(index_set(index_set({1,2})))
418 >>> print(index_set({1,2}))
420 >>> print(index_set({1,2,1}))
422 >>> print(index_set({1,2,1}))
424 >>> print(index_set(""))
426 >>> print(index_set("{"))
427 Traceback (most recent call last):
429 ValueError: Cannot initialize index_set object from invalid string '{'.
430 >>> print(index_set("{1"))
431 Traceback (most recent call last):
433 ValueError: Cannot initialize index_set object from invalid string '{1'.
434 >>> print(index_set("{1,2,100}"))
435 Traceback (most recent call last):
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):
441 IndexError: Cannot initialize index_set object from invalid {1, 2, 100}.
442 >>> print(index_set([1,2]))
443 Traceback (most recent call last):
445 TypeError: Cannot initialize index_set object from <class 'list'>.
447 For index_set.__richcmp__: Compare two objects of class index_set.
449 >>> index_set(1) == index_set({1})
451 >>> index_set({1}) != index_set({1})
453 >>> index_set({1}) != index_set({2})
455 >>> index_set({1}) == index_set({2})
457 >>> index_set({1}) < index_set({2})
459 >>> index_set({1}) <= index_set({2})
461 >>> index_set({1}) > index_set({2})
463 >>> index_set({1}) >= index_set({2})
465 >>> None == index_set({1,2})
467 >>> None != index_set({1,2})
469 >>> None < index_set({1,2})
471 >>> None <= index_set({1,2})
473 >>> None > index_set({1,2})
475 >>> None >= index_set({1,2})
477 >>> index_set({1,2}) == None
479 >>> index_set({1,2}) != None
481 >>> index_set({1,2}) < None
483 >>> index_set({1,2}) <= None
485 >>> index_set({1,2}) > None
487 >>> index_set({1,2}) >= None
492cpdef inline compare(lhs,rhs):
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.
497 >>> compare(index_set({1,2}),index_set({-1,3}))
499 >>> compare(index_set({-1,4}),index_set({-1,3}))
504cpdef inline min_neg(obj):
506 Minimum negative index, or 0 if none.
508 >>> min_neg(index_set({1,2}))
513cpdef inline max_pos(obj):
515 Maximum positive index, or 0 if none.
517 >>> max_pos(index_set({1,2}))
522cdef inline vector[scalar_t] list_to_vector(lst):
524 Create a C++ std:vector[scalar_t] from an iterable Python object.
526 cdef vector[scalar_t] v
528 v.push_back(<scalar_t>s)
534cdef inline Clifford toClifford(obj):
535 return clifford(obj).instance[0]
539 Python class clifford wraps C++ class Clifford.
541 cdef Clifford *instance
543 cdef inline wrap(clifford self, Clifford other):
545 Wrap an instance of the C++ class Clifford.
550 cdef inline Clifford unwrap(clifford self):
552 Return the wrapped C++ Clifford instance.
556 cpdef copy(clifford self):
558 Copy this clifford object.
560 >>> x=clifford("1{2}"); y=x.copy(); print(y)
567 Construct an object of type clifford.
569 >>> print(clifford(2))
571 >>> print(clifford(2.0))
573 >>> print(clifford(1.0e-1))
575 >>> print(clifford("2"))
577 >>> print(clifford("2{1,2,3}"))
579 >>> print(clifford(clifford("2{1,2,3}")))
581 >>> print(clifford("-{1}"))
583 >>> print(clifford(2,index_set({1,2})))
585 >>> print(clifford([2,3],index_set({1,2})))
588 error_msg_prefix =
"Cannot initialize clifford object from"
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):
599 bother = other.encode(
"UTF-8")
600 self.
instance = new Clifford(<char *>bother)
602 raise ValueError(error_msg_prefix +
" invalid string " + repr(other) +
".")
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) +
":"
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())
615 raise TypeError(error_msg_prefix +
" (" + str(type(other))
616 +
", " + repr(ixt) +
").")
618 raise TypeError(error_msg_prefix +
" (" + str(type(other))
619 +
", " + str(type(ixt)) +
").")
623 Clean up by deallocating the instance of C++ class Clifford.
631 >>> x=clifford(index_set({-3,4,7})); -3 in x
632 Traceback (most recent call last):
634 TypeError: Not applicable.
636 raise TypeError(
"Not applicable.")
642 >>> for a in clifford(index_set({-3,4,7})):print(a, end=",")
643 Traceback (most recent call last):
645 TypeError: Not applicable.
647 raise TypeError(
"Not applicable.")
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.
654 >>> clifford("2+3{1}").reframe(index_set({1,2,3}))
656 >>> s=index_set({1,2,3});t=index_set({-3,-2,-1});x=random_clifford(s); x.reframe(t).frame() == (s|t);
659 error_msg_prefix =
"Cannot reframe"
660 if isinstance(ixt, index_set):
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 "
669 raise TypeError(error_msg_prefix +
" using (" + str(type(ixt)) +
").")
674 Compare objects of type clifford.
676 >>> clifford("{1}") == clifford("1{1}")
678 >>> clifford("{1}") != clifford("1.0{1}")
680 >>> clifford("{1}") != clifford("1.0")
682 >>> clifford("{1,2}") == None
684 >>> clifford("{1,2}") != None
686 >>> None == clifford("{1,2}")
688 >>> None != clifford("{1,2}")
692 if (lhs
is None)
or (rhs
is None):
693 return bool(lhs
is rhs)
695 return bool( toClifford(lhs) == toClifford(rhs) )
697 if (lhs
is None)
or (rhs
is None):
698 return not bool(lhs
is rhs)
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)) +
".")
705 return NotImplemented
709 Subscripting: map from index set to scalar coordinate.
711 >>> clifford("{1}")[index_set(1)]
713 >>> clifford("{1}")[index_set({1})]
715 >>> clifford("{1}")[index_set({1,2})]
717 >>> clifford("2{1,2}")[index_set({1,2})]
720 return self.
instance.getitem(toIndexSet(ixt))
726 >>> print(-clifford("{1}"))
735 >>> print(+clifford("{1}"))
744 >>> print(clifford(1) + clifford("{2}"))
746 >>> print(clifford("{1}") + clifford("{2}"))
749 return clifford().wrap( toClifford(lhs) + toClifford(rhs) )
755 >>> x = clifford(1); x += clifford("{2}"); print(x)
758 return self.wrap( self.unwrap() + toClifford(rhs) )
762 Geometric difference.
764 >>> print(clifford(1) - clifford("{2}"))
766 >>> print(clifford("{1}") - clifford("{2}"))
769 return clifford().wrap( toClifford(lhs) - toClifford(rhs) )
773 Geometric difference.
775 >>> x = clifford(1); x -= clifford("{2}"); print(x)
778 return self.wrap( self.unwrap() - toClifford(rhs) )
784 >>> print(clifford("{1}") * clifford("{2}"))
786 >>> print(clifford(2) * clifford("{2}"))
788 >>> print(clifford("{1}") * clifford("{1,2}"))
791 return clifford().wrap( toClifford(lhs) * toClifford(rhs) )
797 >>> x = clifford(2); x *= clifford("{2}"); print(x)
799 >>> x = clifford("{1}"); x *= clifford("{2}"); print(x)
801 >>> x = clifford("{1}"); x *= clifford("{1,2}"); print(x)
804 return self.wrap( self.unwrap() * toClifford(rhs) )
810 >>> print(clifford("{1}") % clifford("{2}"))
812 >>> print(clifford(2) % clifford("{2}"))
814 >>> print(clifford("{1}") % clifford("{1}"))
816 >>> print(clifford("{1}") % clifford("{1,2}"))
819 return clifford().wrap( toClifford(lhs) % toClifford(rhs) )
825 >>> x = clifford("{1}"); x %= clifford("{2}"); print(x)
827 >>> x = clifford(2); x %= clifford("{2}"); print(x)
829 >>> x = clifford("{1}"); x %= clifford("{1}"); print(x)
831 >>> x = clifford("{1}"); x %= clifford("{1,2}"); print(x)
834 return self.wrap( self.unwrap() % toClifford(rhs) )
840 >>> print(clifford("{1}") & clifford("{2}"))
842 >>> print(clifford(2) & clifford("{2}"))
844 >>> print(clifford("{1}") & clifford("{1}"))
846 >>> print(clifford("{1}") & clifford("{1,2}"))
849 return clifford().wrap( toClifford(lhs) & toClifford(rhs) )
855 >>> x = clifford("{1}"); x &= clifford("{2}"); print(x)
857 >>> x = clifford(2); x &= clifford("{2}"); print(x)
859 >>> x = clifford("{1}"); x &= clifford("{1}"); print(x)
861 >>> x = clifford("{1}"); x &= clifford("{1,2}"); print(x)
864 return self.wrap( self.unwrap() & toClifford(rhs) )
870 >>> print(clifford("{1}") ^ clifford("{2}"))
872 >>> print(clifford(2) ^ clifford("{2}"))
874 >>> print(clifford("{1}") ^ clifford("{1}"))
876 >>> print(clifford("{1}") ^ clifford("{1,2}"))
879 return clifford().wrap( toClifford(lhs) ^ toClifford(rhs) )
885 >>> x = clifford("{1}"); x ^= clifford("{2}"); print(x)
887 >>> x = clifford(2); x ^= clifford("{2}"); print(x)
889 >>> x = clifford("{1}"); x ^= clifford("{1}"); print(x)
891 >>> x = clifford("{1}"); x ^= clifford("{1,2}"); print(x)
894 return self.wrap( self.unwrap() ^ toClifford(rhs) )
900 >>> print(clifford("{1}") / clifford("{2}"))
902 >>> print(clifford(2) / clifford("{2}"))
904 >>> print(clifford("{1}") / clifford("{1}"))
906 >>> print(clifford("{1}") / clifford("{1,2}"))
909 return clifford().wrap( toClifford(lhs) / toClifford(rhs) )
915 >>> x = clifford("{1}"); x /= clifford("{2}"); print(x)
917 >>> x = clifford(2); x /= clifford("{2}"); print(x)
919 >>> x = clifford("{1}"); x /= clifford("{1}"); print(x)
921 >>> x = clifford("{1}"); x /= clifford("{1,2}"); print(x)
924 return self.wrap( self.unwrap() / toClifford(rhs) )
928 Geometric multiplicative inverse.
930 >>> x = clifford("{1}"); print(x.inv())
932 >>> x = clifford(2); print(x.inv())
934 >>> x = clifford("{1,2}"); print(x.inv())
941 Transform left hand side, using right hand side as a transformation.
943 >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); print(y|x)
945 >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); print(y|exp(x))
948 return clifford().wrap( toClifford(lhs) | toClifford(rhs) )
952 Transform left hand side, using right hand side as a transformation.
954 >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); y|=x; print(y)
956 >>> x=clifford("{1,2}") * pi/2; y=clifford("{1}"); y|=exp(x); print(y)
959 return self.wrap( self.unwrap() | toClifford(rhs) )
963 Power: self to the m.
965 >>> x=clifford("{1}"); print(x ** 2)
967 >>> x=clifford("2"); print(x ** 2)
969 >>> x=clifford("2+{1}"); print(x ** 0)
971 >>> x=clifford("2+{1}"); print(x ** 1)
973 >>> x=clifford("2+{1}"); print(x ** 2)
975 >>> i=clifford("{1,2}"); print(exp(pi/2) * (i ** i))
982 Power: self to the m.
984 >>> x=clifford("{1}"); print(x.pow(2))
986 >>> x=clifford("2"); print(x.pow(2))
988 >>> x=clifford("2+{1}"); print(x.pow(0))
990 >>> x=clifford("2+{1}"); print(x.pow(1))
992 >>> x=clifford("2+{1}"); print(x.pow(2))
994 >>> print(clifford("1+{1}+{1,2}").pow(3))
996 >>> i=clifford("{1,2}"); print(exp(pi/2) * i.pow(i))
999 if isinstance(m, numbers.Integral):
1002 return exp(m * log(self))
1006 Outer product power.
1008 >>> x=clifford("2+{1}"); print(x.outer_pow(0))
1010 >>> x=clifford("2+{1}"); print(x.outer_pow(1))
1012 >>> x=clifford("2+{1}"); print(x.outer_pow(2))
1014 >>> print(clifford("1+{1}+{1,2}").outer_pow(3))
1022 Pure grade-vector part.
1024 >>> print(clifford("{1}")(1))
1026 >>> print(clifford("{1}")(0))
1028 >>> print(clifford("1+{1}+{1,2}")(0))
1030 >>> print(clifford("1+{1}+{1,2}")(1))
1032 >>> print(clifford("1+{1}+{1,2}")(2))
1034 >>> print(clifford("1+{1}+{1,2}")(3))
1043 >>> clifford("1+{1}+{1,2}").scalar()
1045 >>> clifford("{1,2}").scalar()
1054 >>> print(clifford("1+{1}+{1,2}").pure())
1056 >>> print(clifford("{1,2}").pure())
1063 Even part of multivector, sum of even grade terms.
1065 >>> print(clifford("1+{1}+{1,2}").even())
1072 Odd part of multivector, sum of odd grade terms.
1074 >>> print(clifford("1+{1}+{1,2}").odd())
1081 Vector part of multivector, as a Python list, with respect to frm.
1083 >>> print(clifford("1+2{1}+3{2}+4{1,2}").vector_part())
1085 >>> print(clifford("1+2{1}+3{2}+4{1,2}").vector_part(index_set({-1,1,2})))
1088 error_msg_prefix =
"Cannot take vector part of "
1089 cdef vector[scalar_t] vec
1102 except RuntimeError
as err:
1103 raise ValueError(error_msg_prefix + str(self) +
" using invalid "
1104 + repr(frm) +
" as frame:\n\t"
1109 Main involution, each {i} is replaced by -{i} in each term,
1110 eg. clifford("{1}") -> -clifford("{1}").
1112 >>> print(clifford("{1}").involute())
1114 >>> print((clifford("{2}") * clifford("{1}")).involute())
1116 >>> print((clifford("{1}") * clifford("{2}")).involute())
1118 >>> print(clifford("1+{1}+{1,2}").involute())
1125 Reversion, eg. clifford("{1}")*clifford("{2}") -> clifford("{2}")*clifford("{1}").
1127 >>> print(clifford("{1}").reverse())
1129 >>> print((clifford("{2}") * clifford("{1}")).reverse())
1131 >>> print((clifford("{1}") * clifford("{2}")).reverse())
1133 >>> print(clifford("1+{1}+{1,2}").reverse())
1140 Conjugation, reverse o involute == involute o reverse.
1142 >>> print((clifford("{1}")).conj())
1144 >>> print((clifford("{2}") * clifford("{1}")).conj())
1146 >>> print((clifford("{1}") * clifford("{2}")).conj())
1148 >>> print(clifford("1+{1}+{1,2}").conj())
1155 Quadratic form == (rev(x)*x)(0).
1157 >>> print(clifford("1+{1}+{1,2}").quad())
1159 >>> print(clifford("1+{-1}+{1,2}+{1,2,3}").quad())
1166 Norm == sum of squares of coordinates.
1168 >>> clifford("1+{1}+{1,2}").norm()
1170 >>> clifford("1+{-1}+{1,2}+{1,2,3}").norm()
1177 Absolute value: square root of norm.
1179 >>> clifford("1+{-1}+{1,2}+{1,2,3}").abs()
1186 Maximum of absolute values of components of multivector: multivector infinity norm.
1188 >>> clifford("1+{-1}+{1,2}+{1,2,3}").max_abs()
1190 >>> clifford("3+2{1}+{1,2}").max_abs()
1197 Remove all terms of self with relative size smaller than limit.
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}")
1208 Check if a multivector contains any infinite values.
1210 >>> clifford().isinf()
1217 Check if a multivector contains any IEEE NaN values.
1219 >>> clifford().isnan()
1226 Subalgebra generated by all generators of terms of given multivector.
1228 >>> print(clifford("1+3{-1}+2{1,2}+4{-2,7}").frame())
1230 >>> s=clifford("1+3{-1}+2{1,2}+4{-2,7}").frame(); type(s)
1231 <class 'PyClical.index_set'>
1237 The “official” string representation of self.
1239 >>> clifford("1+3{-1}+2{1,2}+4{-2,7}").__repr__()
1240 'clifford("1+3{-1}+2{1,2}+4{-2,7}")'
1246 The “informal” string representation of self.
1248 >>> clifford("1+3{-1}+2{1,2}+4{-2,7}").__str__()
1249 '1+3{-1}+2{1,2}+4{-2,7}'
1255 Tests for functions that Doctest cannot see.
1257 For clifford.__cinit__: Construct an object of type clifford.
1259 >>> print(clifford(2))
1261 >>> print(clifford(2.0))
1263 >>> print(clifford(1.0e-1))
1265 >>> print(clifford("2"))
1267 >>> print(clifford("2{1,2,3}"))
1269 >>> print(clifford(clifford("2{1,2,3}")))
1271 >>> print(clifford("-{1}"))
1273 >>> print(clifford(2,index_set({1,2})))
1275 >>> print(clifford([2,3],index_set({1,2})))
1277 >>> print(clifford([1,2]))
1278 Traceback (most recent call last):
1280 TypeError: Cannot initialize clifford object from <class 'list'>.
1281 >>> print(clifford(None))
1282 Traceback (most recent call last):
1284 TypeError: Cannot initialize clifford object from <class 'NoneType'>.
1285 >>> print(clifford(None,[1,2]))
1286 Traceback (most recent call last):
1288 TypeError: Cannot initialize clifford object from (<class 'NoneType'>, <class 'list'>).
1289 >>> print(clifford([1,2],[1,2]))
1290 Traceback (most recent call last):
1292 TypeError: Cannot initialize clifford object from (<class 'list'>, <class 'list'>).
1293 >>> print(clifford(""))
1294 Traceback (most recent call last):
1296 ValueError: Cannot initialize clifford object from invalid string ''.
1297 >>> print(clifford("{"))
1298 Traceback (most recent call last):
1300 ValueError: Cannot initialize clifford object from invalid string '{'.
1301 >>> print(clifford("{1"))
1302 Traceback (most recent call last):
1304 ValueError: Cannot initialize clifford object from invalid string '{1'.
1305 >>> print(clifford("+"))
1306 Traceback (most recent call last):
1308 ValueError: Cannot initialize clifford object from invalid string '+'.
1309 >>> print(clifford("-"))
1310 Traceback (most recent call last):
1312 ValueError: Cannot initialize clifford object from invalid string '-'.
1313 >>> print(clifford("{1}+"))
1314 Traceback (most recent call last):
1316 ValueError: Cannot initialize clifford object from invalid string '{1}+'.
1318 For clifford.__richcmp__: Compare objects of type clifford.
1320 >>> clifford("{1}") == clifford("1{1}")
1322 >>> clifford("{1}") != clifford("1.0{1}")
1324 >>> clifford("{1}") != clifford("1.0")
1326 >>> clifford("{1,2}") == None
1328 >>> clifford("{1,2}") != None
1330 >>> None == clifford("{1,2}")
1332 >>> None != clifford("{1,2}")
1337cpdef inline error_squared_tol(obj):
1339 Quadratic norm error tolerance relative to a specific multivector.
1341 >>> print(error_squared_tol(clifford("{1}")) * 3.0 - error_squared_tol(clifford("1{1}-2{2}+3{3}")))
1346cpdef inline error_squared(lhs, rhs, threshold):
1348 Relative or absolute error using the quadratic norm.
1350 >>> err2=scalar_epsilon*scalar_epsilon
1352 >>> print(error_squared(clifford("{1}"), clifford("1{1}"), err2))
1354 >>> print(error_squared(clifford("1{1}-3{2}+4{3}"), clifford("{1}"), err2))
1359cpdef inline approx_equal(lhs, rhs, threshold=
None, tol=
None):
1361 Test for approximate equality of multivectors.
1363 >>> err2=scalar_epsilon*scalar_epsilon
1365 >>> print(approx_equal(clifford("{1}"), clifford("1{1}")))
1367 >>> print(approx_equal(clifford("1{1}-3{2}+4{3}"), clifford("{1}")))
1369 >>> print(approx_equal(clifford("1{1}-3{2}+4{3}+0.001"), clifford("1{1}-3{2}+4{3}"), err2, err2))
1371 >>> print(approx_equal(clifford("1{1}-3{2}+4{3}+1.0e-30"), clifford("1{1}-3{2}+4{3}"), err2, err2))
1374 threshold = error_squared_tol(rhs)
if threshold
is None else threshold
1375 tol = error_squared_tol(rhs)
if tol
is None else tol
1376 return glucat.approx_equal(toClifford(lhs), toClifford(rhs), <scalar_t>threshold, <scalar_t>tol)
1378cpdef inline inv(obj):
1380 Geometric multiplicative inverse.
1382 >>> print(inv(clifford("{1}")))
1384 >>> print(inv(clifford("{-1}")))
1386 >>> print(inv(clifford("{-2,-1}")))
1388 >>> print(inv(clifford("{-1}+{1}")))
1393cpdef inline scalar(obj):
1397 >>> scalar(clifford("1+{1}+{1,2}"))
1399 >>> scalar(clifford("{1,2}"))
1404cpdef inline real(obj):
1406 Real part: synonym for scalar part.
1408 >>> real(clifford("1+{1}+{1,2}"))
1410 >>> real(clifford("{1,2}"))
1415cpdef inline imag(obj):
1417 Imaginary part: deprecated (always 0).
1419 >>> imag(clifford("1+{1}+{1,2}"))
1421 >>> imag(clifford("{1,2}"))
1426cpdef inline pure(obj):
1430 >>> print(pure(clifford("1+{1}+{1,2}")))
1432 >>> print(pure(clifford("{1,2}")))
1437cpdef inline even(obj):
1439 Even part of multivector, sum of even grade terms.
1441 >>> print(even(clifford("1+{1}+{1,2}")))
1446cpdef inline odd(obj):
1448 Odd part of multivector, sum of odd grade terms.
1450 >>> print(odd(clifford("1+{1}+{1,2}")))
1455cpdef inline involute(obj):
1457 Main involution, each {i} is replaced by -{i} in each term, eg. {1}*{2} -> (-{2})*(-{1})
1459 >>> print(involute(clifford("{1}")))
1461 >>> print(involute(clifford("{2}") * clifford("{1}")))
1463 >>> print(involute(clifford("{1}") * clifford("{2}")))
1465 >>> print(involute(clifford("1+{1}+{1,2}")))
1470cpdef inline reverse(obj):
1472 Reversion, eg. {1}*{2} -> {2}*{1}
1474 >>> print(reverse(clifford("{1}")))
1476 >>> print(reverse(clifford("{2}") * clifford("{1}")))
1478 >>> print(reverse(clifford("{1}") * clifford("{2}")))
1480 >>> print(reverse(clifford("1+{1}+{1,2}")))
1485cpdef inline conj(obj):
1487 Conjugation, reverse o involute == involute o reverse.
1489 >>> print(conj(clifford("{1}")))
1491 >>> print(conj(clifford("{2}") * clifford("{1}")))
1493 >>> print(conj(clifford("{1}") * clifford("{2}")))
1495 >>> print(conj(clifford("1+{1}+{1,2}")))
1500cpdef inline quad(obj):
1502 Quadratic form == (rev(x)*x)(0).
1504 >>> print(quad(clifford("1+{1}+{1,2}")))
1506 >>> print(quad(clifford("1+{-1}+{1,2}+{1,2,3}")))
1511cpdef inline norm(obj):
1513 norm == sum of squares of coordinates.
1515 >>> norm(clifford("1+{1}+{1,2}"))
1517 >>> norm(clifford("1+{-1}+{1,2}+{1,2,3}"))
1522cpdef inline abs(obj):
1524 Absolute value of multivector: multivector 2-norm.
1526 >>> abs(clifford("1+{-1}+{1,2}+{1,2,3}"))
1531cpdef inline max_abs(obj):
1533 Maximum absolute value of coordinates multivector: multivector infinity-norm.
1535 >>> max_abs(clifford("1+{-1}+{1,2}+{1,2,3}"))
1537 >>> max_abs(clifford("3+2{1}+{1,2}"))
1543cpdef inline pow(obj, m):
1545 Integer power of multivector: obj to the m.
1547 >>> x=clifford("{1}"); print(pow(x,2))
1549 >>> x=clifford("2"); print(pow(x,2))
1551 >>> x=clifford("2+{1}"); print(pow(x,0))
1553 >>> x=clifford("2+{1}"); print(pow(x,1))
1555 >>> x=clifford("2+{1}"); print(pow(x,2))
1557 >>> print(pow(clifford("1+{1}+{1,2}"),3))
1559 >>> i=clifford("{1,2}"); print(exp(pi/2) * pow(i, i))
1567cpdef inline outer_pow(obj, m):
1569 Outer product power of multivector.
1571 >>> print(outer_pow(clifford("1+{1}+{1,2}"),3))
1576cpdef inline complexifier(obj):
1578 Square root of -1 which commutes with all members of the frame of the given multivector.
1580 >>> print(complexifier(clifford(index_set({1}))))
1582 >>> print(complexifier(clifford(index_set({-1}))))
1584 >>> print(complexifier(index_set({1})))
1586 >>> print(complexifier(index_set({-1})))
1591cpdef inline sqrt(obj, i =
None):
1593 Square root of multivector with optional complexifier.
1597 >>> print(sqrt(clifford("2{-1}")))
1599 >>> j=sqrt(-1,complexifier(index_set({1}))); print(j); print(j*j)
1602 >>> j=sqrt(-1,"{1,2,3}"); print(j); print(j*j)
1610 return math.sqrt(obj)
1614cpdef inline exp(obj):
1616 Exponential of multivector.
1618 >>> x=clifford("{1,2}") * pi/4; print(exp(x))
1620 >>> x=clifford("{1,2}") * pi/2; print(exp(x))
1624 return math.exp(obj)
1628cpdef inline log(obj,i =
None):
1630 Natural logarithm of multivector with optional complexifier.
1632 >>> x=clifford("{-1}"); print((log(x,"{-1}") * 2/pi))
1634 >>> x=clifford("{1,2}"); print((log(x,"{1,2,3}") * 2/pi))
1636 >>> x=clifford("{1,2}"); print((log(x) * 2/pi))
1638 >>> x=clifford("{1,2}"); print((log(x,"{1,2}") * 2/pi))
1639 Traceback (most recent call last):
1641 RuntimeError: check_complex(val, i): i is not a valid complexifier for val
1647 return math.log(obj)
1651cpdef inline cos(obj,i =
None):
1653 Cosine of multivector with optional complexifier.
1655 >>> x=clifford("{1,2}"); print(cos(acos(x),"{1,2,3}"))
1657 >>> x=clifford("{1,2}"); print(cos(acos(x)))
1664 return math.cos(obj)
1668cpdef inline acos(obj,i =
None):
1670 Inverse cosine of multivector with optional complexifier.
1672 >>> x=clifford("{1,2}"); print(cos(acos(x),"{1,2,3}"))
1674 >>> x=clifford("{1,2}"); print(cos(acos(x),"{-1,1,2,3,4}"))
1676 >>> print(acos(0) / pi)
1678 >>> x=clifford("{1,2}"); print(cos(acos(x)))
1685 return math.acos(obj)
1689cpdef inline cosh(obj):
1691 Hyperbolic cosine of multivector.
1693 >>> x=clifford("{1,2}") * pi; print(cosh(x))
1695 >>> x=clifford("{1,2,3}"); print(cosh(acosh(x)))
1697 >>> x=clifford("{1,2}"); print(cosh(acosh(x)))
1701 return math.cosh(obj)
1705cpdef inline acosh(obj,i =
None):
1707 Inverse hyperbolic cosine of multivector with optional complexifier.
1709 >>> print(acosh(0,"{-2,-1,1}"))
1711 >>> x=clifford("{1,2,3}"); print(cosh(acosh(x,"{-1,1,2,3,4}")))
1715 >>> x=clifford("{1,2,3}"); print(cosh(acosh(x)))
1717 >>> x=clifford("{1,2}"); print(cosh(acosh(x)))
1724 return math.acosh(obj)
1728cpdef inline sin(obj,i =
None):
1730 Sine of multivector with optional complexifier.
1732 >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),s))
1734 >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),"{-2,-1,1}"))
1736 >>> x=clifford("{1,2,3}"); print(asin(sin(x)))
1743 return math.sin(obj)
1747cpdef inline asin(obj,i =
None):
1749 Inverse sine of multivector with optional complexifier.
1751 >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),s))
1753 >>> s="{-1}"; x=clifford(s); print(asin(sin(x,s),"{-2,-1,1}"))
1755 >>> print(asin(1) / pi)
1757 >>> x=clifford("{1,2,3}"); print(asin(sin(x)))
1764 return math.asin(obj)
1768cpdef inline sinh(obj):
1770 Hyperbolic sine of multivector.
1772 >>> x=clifford("{1,2}") * pi/2; print(sinh(x))
1774 >>> x=clifford("{1,2}") * pi/6; print(sinh(x))
1778 return math.sinh(obj)
1782cpdef inline asinh(obj,i =
None):
1784 Inverse hyperbolic sine of multivector with optional complexifier.
1786 >>> x=clifford("{1,2}"); print(asinh(x,"{1,2,3}") * 2/pi)
1788 >>> x=clifford("{1,2}"); print(asinh(x) * 2/pi)
1790 >>> x=clifford("{1,2}") / 2; print(asinh(x) * 6/pi)
1797 return math.asinh(obj)
1801cpdef inline tan(obj,i =
None):
1803 Tangent of multivector with optional complexifier.
1805 >>> x=clifford("{1,2}"); print(tan(x,"{1,2,3}"))
1807 >>> x=clifford("{1,2}"); print(tan(x))
1814 return math.tan(obj)
1818cpdef inline atan(obj,i =
None):
1820 Inverse tangent of multivector with optional complexifier.
1822 >>> s=index_set({1,2,3}); x=clifford("{1}"); print(tan(atan(x,s),s))
1824 >>> x=clifford("{1}"); print(tan(atan(x)))
1831 return math.atan(obj)
1835cpdef inline tanh(obj):
1837 Hyperbolic tangent of multivector.
1839 >>> x=clifford("{1,2}") * pi/4; print(tanh(x))
1843 return math.tanh(obj)
1847cpdef inline atanh(obj,i =
None):
1849 Inverse hyperbolic tangent of multivector with optional complexifier.
1851 >>> s=index_set({1,2,3}); x=clifford("{1,2}"); print(tanh(atanh(x,s)))
1853 >>> x=clifford("{1,2}"); print(tanh(atanh(x)))
1860 return math.atanh(obj)
1864cpdef inline random_clifford(index_set ixt, fill = 1.0):
1866 Random multivector within a frame.
1868 >>> print(random_clifford(index_set({-3,-1,2})).frame())
1871 return clifford().wrap(
clifford().instance.random(ixt.unwrap(), <scalar_t>fill) )
1873cpdef inline
cga3(obj):
1875 Convert Euclidean 3D multivector to Conformal Geometric Algebra using Doran and Lasenby definition.
1877 >>> x=clifford("2{1}+9{2}+{3}"); print(cga3(x))
1878 87{-1}+4{1}+18{2}+2{3}+85{4}
1880 return clifford().wrap( glucat.cga3(toClifford(obj)) )
1882cpdef inline cga3std(obj):
1884 Convert CGA3 null vector to standard conformal null vector using Doran and Lasenby definition.
1886 >>> x=clifford("2{1}+9{2}+{3}"); print(cga3std(cga3(x)))
1887 87{-1}+4{1}+18{2}+2{3}+85{4}
1888 >>> x=clifford("2{1}+9{2}+{3}"); print(cga3std(cga3(x))-cga3(x))
1891 return clifford().wrap( glucat.cga3std(toClifford(obj)) )
1893cpdef inline agc3(obj):
1895 Convert CGA3 null vector to Euclidean 3D vector using Doran and Lasenby definition.
1897 >>> x=clifford("2{1}+9{2}+{3}"); print(agc3(cga3(x)))
1899 >>> x=clifford("2{1}+9{2}+{3}"); print(agc3(cga3(x))-x)
1902 return clifford().wrap( glucat.agc3(toClifford(obj)) )
1905scalar_epsilon = epsilon
1912Abbreviation for clifford.
1918>>> print(cl(5.0e-1))
1922>>> print(cl("2{1,2,3}"))
1924>>> print(cl(cl("2{1,2,3}")))
1930Abbreviation for index_set.
1932>>> print(ist("{1,2,3}"))
1938 Abbreviation for clifford(index_set(obj)).
1951 Abbreviation for index_set({-q,...p}).
1953 >>> print(istpq(2,3))
1963 import PyClical, doctest
1964 return doctest.testmod(PyClical)
1966if __name__ ==
"__main__":
String clifford_to_str(const Multivector_T &mv)
The "informal" string representation of Multivector_T mv.
String clifford_to_repr(const Multivector_T &mv)
The “official” string representation of Multivector_T mv.
String index_set_to_str(const Index_Set_T &ist)
The "informal" string representation of Index_Set_T ist.
String index_set_to_repr(const Index_Set_T &ist)
The “official” string representation of Index_Set_T ist.
__cinit__(self, other=0, ixt=None)
vector_part(self, frm=None)
__richcmp__(lhs, rhs, int, op)
__setitem__(self, idx, val)
__richcmp__(lhs, rhs, int, op)
clifford_hidden_doctests()
index_set_hidden_doctests()
Definitions for 3D Conformal Geometric Algebra [DL].
auto exp(const framed_multi< Scalar_T, LO, HI, Tune_P > &val) -> const framed_multi< Scalar_T, LO, HI, Tune_P >
Exponential of multivector.
auto compare(const index_set< LO, HI > &a, const index_set< LO, HI > &b) -> int
"lexicographic compare" eg. {3,4,5} is less than {3,7,8}
auto cosh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic cosine of multivector.
auto tanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic tangent of multivector.
auto approx_equal(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs, const Scalar_T threshold, const Scalar_T tolerance) -> bool
Test for approximate equality of multivectors.
auto min_neg(const index_set< LO, HI > &ist) -> index_t
Minimum negative index, or 0 if none.
auto tan(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Tangent of multivector with specified complexifier.
auto error_squared(const Multivector< Scalar_T, LO, HI, Tune_P > &lhs, const RHS< Scalar_T, LO, HI, Tune_P > &rhs, const Scalar_T threshold) -> Scalar_T
Relative or absolute error using the quadratic norm.
auto sinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Hyperbolic sine of multivector.
auto sin(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Sine of multivector with specified complexifier.
auto abs(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Absolute value == sqrt(norm)
auto asinh(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic sine of multivector with specified complexifier.
auto atanh(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic tangent of multivector with specified complexifier.
auto atan(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse tangent of multivector with specified complexifier.
auto cos(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Cosine of multivector with specified complexifier.
auto log(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Natural logarithm of multivector with specified complexifier.
auto asin(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse sine of multivector with specified complexifier.
auto acosh(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse hyperbolic cosine of multivector with specified complexifier.
auto error_squared_tol(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Quadratic norm error tolerance relative to a specific multivector.
auto max_abs(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> Scalar_T
Maximum of absolute values of components of multivector: multivector infinity norm.
auto sqrt(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Square root of multivector with specified complexifier.
auto complexifier(const Multivector< Scalar_T, LO, HI, Tune_P > &val) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Square root of -1 which commutes with all members of the frame of the given multivector.
auto acos(const Multivector< Scalar_T, LO, HI, Tune_P > &val, const Multivector< Scalar_T, LO, HI, Tune_P > &i, const bool prechecked=false) -> const Multivector< Scalar_T, LO, HI, Tune_P >
Inverse cosine of multivector with specified complexifier.
auto max_pos(const index_set< LO, HI > &ist) -> index_t
Maximum positive index, or 0 if none.