55import operator
66import copy
77from collections import OrderedDict
8- from itertools import combinations
8+ import itertools
99import functools
1010from functools import reduce
11- from typing import Tuple , TypeVar , Callable , Mapping
11+ from typing import Tuple , TypeVar , Callable , Mapping , Sequence
1212
1313from sympy import (
1414 diff , Rational , Symbol , S , Mul , Add ,
2727zero = S (0 )
2828
2929
30+ # needed to avoid clashes below
31+ _mv = mv
32+
33+
3034def all_same (items ):
3135 return all (x == items [0 ] for x in items )
3236
@@ -832,7 +836,7 @@ def _build_bases(self):
832836 # index list for multivector bases and blades by grade
833837 basis_indexes = tuple (self .n_range )
834838 self .indexes = GradedTuple (
835- tuple (combinations (basis_indexes , i ))
839+ tuple (itertools . combinations (basis_indexes , i ))
836840 for i in range (len (basis_indexes ) + 1 )
837841 )
838842
@@ -1950,7 +1954,8 @@ def connection(self, rbase, key_base, mode, left):
19501954 self .connect [mode_key ].append ((key , C ))
19511955 return C
19521956
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 ]:
19541959 """
19551960 Compute the reciprocal frame of a set of vectors
19561961
@@ -1962,51 +1967,43 @@ def ReciprocalFrame(self, basis, mode='norm'):
19621967 normalization coefficient should be appended to the returned tuple.
19631968 One can divide by this coefficient to normalize the vectors.
19641969 """
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 ())
19861970
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+ ]
19881989
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 ]
19961992
1993+ # normalize
1994+ E_sq = trigsimp ((E * E ).scalar ())
19971995 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 ]
20001997 else :
20011998 if mode != 'append' :
20021999 # galgebra 0.5.0
20032000 warnings .warn (
20042001 "Mode {!r} not understood, falling back to {!r} but this "
20052002 "is deprecated" .format (mode , 'append' ),
20062003 DeprecationWarning , stacklevel = 2 )
2007- rbasis .append (E_sq )
2004+ r_basis .append (E_sq )
20082005
2009- return tuple (rbasis )
2006+ return tuple (r_basis )
20102007
20112008 def Mlt (self , * args , ** kwargs ):
20122009 return lt .Mlt (args [0 ], self , * args [1 :], ** kwargs )
0 commit comments