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
@@ -1978,7 +1982,8 @@ def connection(self, rbase, key_base, mode, left):
19781982 self .connect [mode_key ].append ((key , C ))
19791983 return C
19801984
1981- def ReciprocalFrame (self , basis , mode = 'norm' ):
1985+ # need _mv as mv would refer to the method!
1986+ def ReciprocalFrame (self , basis : Sequence [_mv .Mv ], mode : str = 'norm' ) -> Tuple [_mv .Mv ]:
19821987 """
19831988 Compute the reciprocal frame of a set of vectors
19841989
@@ -1990,51 +1995,43 @@ def ReciprocalFrame(self, basis, mode='norm'):
19901995 normalization coefficient should be appended to the returned tuple.
19911996 One can divide by this coefficient to normalize the vectors.
19921997 """
1993- dim = len (basis )
1994-
1995- indexes = tuple (range (dim ))
1996- index = [()]
1997-
1998- for i in indexes [- 2 :]:
1999- index .append (tuple (combinations (indexes , i + 1 )))
2000-
2001- MFbasis = []
2002-
2003- for igrade in index [- 2 :]:
2004- grade = []
2005- for iblade in igrade :
2006- blade = self .mv (S (1 ), 'scalar' )
2007- for ibasis in iblade :
2008- blade ^= basis [ibasis ]
2009- blade = blade .trigsimp ()
2010- grade .append (blade )
2011- MFbasis .append (grade )
2012- E = MFbasis [- 1 ][0 ]
2013- E_sq = trigsimp ((E * E ).scalar ())
20141998
2015- duals = copy .copy (MFbasis [- 2 ])
1999+ def wedge_reduce (mvs ):
2000+ """ wedge together a list of multivectors """
2001+ if not mvs :
2002+ return self .mv (S (1 ), 'scalar' )
2003+ return functools .reduce (operator .xor , mvs ).trigsimp ()
2004+
2005+ E = wedge_reduce (basis )
2006+
2007+ # elements are such that `basis[i] ^ co_basis[i] == E`
2008+ co_basis = [
2009+ sign * wedge_reduce (basis_subset )
2010+ for sign , basis_subset in zip (
2011+ # alternating signs
2012+ itertools .cycle ([S (1 ), S (- 1 )]),
2013+ # tuples with one basis missing
2014+ itertools .combinations (basis , len (basis ) - 1 ),
2015+ )
2016+ ]
20162017
2017- duals .reverse ()
2018- sgn = S (1 )
2019- rbasis = []
2020- for dual in duals :
2021- recpv = (sgn * dual * E ).trigsimp ()
2022- rbasis .append (recpv )
2023- sgn = - sgn
2018+ # take the dual without normalization
2019+ r_basis = [(co_base * E ).trigsimp () for co_base in co_basis ]
20242020
2021+ # normalize
2022+ E_sq = trigsimp ((E * E ).scalar ())
20252023 if mode == 'norm' :
2026- for i in range (dim ):
2027- rbasis [i ] = rbasis [i ] / E_sq
2024+ r_basis = [r_base / E_sq for r_base in r_basis ]
20282025 else :
20292026 if mode != 'append' :
20302027 # galgebra 0.5.0
20312028 warnings .warn (
20322029 "Mode {!r} not understood, falling back to {!r} but this "
20332030 "is deprecated" .format (mode , 'append' ),
20342031 DeprecationWarning , stacklevel = 2 )
2035- rbasis .append (E_sq )
2032+ r_basis .append (E_sq )
20362033
2037- return tuple (rbasis )
2034+ return tuple (r_basis )
20382035
20392036 def Mlt (self , * args , ** kwargs ):
20402037 return lt .Mlt (args [0 ], self , * args [1 :], ** kwargs )
0 commit comments