5
5
import operator
6
6
import copy
7
7
from collections import OrderedDict
8
- from itertools import combinations
8
+ import itertools
9
9
import functools
10
10
from functools import reduce
11
- from typing import Tuple , TypeVar , Callable , Mapping
11
+ from typing import Tuple , TypeVar , Callable , Mapping , Sequence
12
12
13
13
from sympy import (
14
14
diff , Rational , Symbol , S , Mul , Add ,
27
27
zero = S (0 )
28
28
29
29
30
+ # needed to avoid clashes below
31
+ _mv = mv
32
+
33
+
30
34
def all_same (items ):
31
35
return all (x == items [0 ] for x in items )
32
36
@@ -832,7 +836,7 @@ def _build_bases(self):
832
836
# index list for multivector bases and blades by grade
833
837
basis_indexes = tuple (self .n_range )
834
838
self .indexes = GradedTuple (
835
- tuple (combinations (basis_indexes , i ))
839
+ tuple (itertools . combinations (basis_indexes , i ))
836
840
for i in range (len (basis_indexes ) + 1 )
837
841
)
838
842
@@ -1950,7 +1954,8 @@ def connection(self, rbase, key_base, mode, left):
1950
1954
self .connect [mode_key ].append ((key , C ))
1951
1955
return C
1952
1956
1953
- def ReciprocalFrame (self , basis , mode = 'norm' ):
1957
+ # need _mv as mv would refer to the method!
1958
+ def ReciprocalFrame (self , basis : Sequence [_mv .Mv ], mode : str = 'norm' ) -> Tuple [_mv .Mv ]:
1954
1959
"""
1955
1960
Compute the reciprocal frame of a set of vectors
1956
1961
@@ -1962,51 +1967,43 @@ def ReciprocalFrame(self, basis, mode='norm'):
1962
1967
normalization coefficient should be appended to the returned tuple.
1963
1968
One can divide by this coefficient to normalize the vectors.
1964
1969
"""
1965
- dim = len (basis )
1966
-
1967
- indexes = tuple (range (dim ))
1968
- index = [()]
1969
-
1970
- for i in indexes [- 2 :]:
1971
- index .append (tuple (combinations (indexes , i + 1 )))
1972
-
1973
- MFbasis = []
1974
-
1975
- for igrade in index [- 2 :]:
1976
- grade = []
1977
- for iblade in igrade :
1978
- blade = self .mv (S (1 ), 'scalar' )
1979
- for ibasis in iblade :
1980
- blade ^= basis [ibasis ]
1981
- blade = blade .trigsimp ()
1982
- grade .append (blade )
1983
- MFbasis .append (grade )
1984
- E = MFbasis [- 1 ][0 ]
1985
- E_sq = trigsimp ((E * E ).scalar ())
1986
1970
1987
- duals = copy .copy (MFbasis [- 2 ])
1971
+ def wedge_reduce (mvs ):
1972
+ """ wedge together a list of multivectors """
1973
+ if not mvs :
1974
+ return self .mv (S (1 ), 'scalar' )
1975
+ return functools .reduce (operator .xor , mvs ).trigsimp ()
1976
+
1977
+ E = wedge_reduce (basis )
1978
+
1979
+ # elements are such that `basis[i] ^ co_basis[i] == E`
1980
+ co_basis = [
1981
+ sign * wedge_reduce (basis_subset )
1982
+ for sign , basis_subset in zip (
1983
+ # alternating signs
1984
+ itertools .cycle ([S (1 ), S (- 1 )]),
1985
+ # tuples with one basis missing
1986
+ itertools .combinations (basis , len (basis ) - 1 ),
1987
+ )
1988
+ ]
1988
1989
1989
- duals .reverse ()
1990
- sgn = S (1 )
1991
- rbasis = []
1992
- for dual in duals :
1993
- recpv = (sgn * dual * E ).trigsimp ()
1994
- rbasis .append (recpv )
1995
- sgn = - sgn
1990
+ # take the dual without normalization
1991
+ r_basis = [(co_base * E ).trigsimp () for co_base in co_basis ]
1996
1992
1993
+ # normalize
1994
+ E_sq = trigsimp ((E * E ).scalar ())
1997
1995
if mode == 'norm' :
1998
- for i in range (dim ):
1999
- rbasis [i ] = rbasis [i ] / E_sq
1996
+ r_basis = [r_base / E_sq for r_base in r_basis ]
2000
1997
else :
2001
1998
if mode != 'append' :
2002
1999
# galgebra 0.5.0
2003
2000
warnings .warn (
2004
2001
"Mode {!r} not understood, falling back to {!r} but this "
2005
2002
"is deprecated" .format (mode , 'append' ),
2006
2003
DeprecationWarning , stacklevel = 2 )
2007
- rbasis .append (E_sq )
2004
+ r_basis .append (E_sq )
2008
2005
2009
- return tuple (rbasis )
2006
+ return tuple (r_basis )
2010
2007
2011
2008
def Mlt (self , * args , ** kwargs ):
2012
2009
return lt .Mlt (args [0 ], self , * args [1 :], ** kwargs )
0 commit comments