|
4 | 4 | import warnings
|
5 | 5 | import operator
|
6 | 6 | import copy
|
7 |
| -from itertools import combinations |
| 7 | +import itertools |
8 | 8 | import functools
|
9 | 9 | from functools import reduce
|
10 | 10 | from typing import Tuple, TypeVar, Callable, Dict, Sequence
|
@@ -790,7 +790,7 @@ def indexes(self) -> GradedTuple[Tuple[int, ...]]:
|
790 | 790 | """ Index tuples of basis blades """
|
791 | 791 | basis_indexes = tuple(self.n_range)
|
792 | 792 | return GradedTuple(
|
793 |
| - tuple(combinations(basis_indexes, i)) |
| 793 | + tuple(itertools.combinations(basis_indexes, i)) |
794 | 794 | for i in range(len(basis_indexes) + 1)
|
795 | 795 | )
|
796 | 796 |
|
@@ -1998,51 +1998,43 @@ def ReciprocalFrame(self, basis: Sequence[_mv.Mv], mode: str = 'norm') -> Tuple[
|
1998 | 1998 | Arbitrary strings are interpreted as ``"append"``, but in
|
1999 | 1999 | future will be an error
|
2000 | 2000 | """
|
2001 |
| - dim = len(basis) |
2002 |
| - |
2003 |
| - indexes = tuple(range(dim)) |
2004 |
| - index = [()] |
2005 |
| - |
2006 |
| - for i in indexes[-2:]: |
2007 |
| - index.append(tuple(combinations(indexes, i + 1))) |
2008 |
| - |
2009 |
| - MFbasis = [] |
2010 |
| - |
2011 |
| - for igrade in index[-2:]: |
2012 |
| - grade = [] |
2013 |
| - for iblade in igrade: |
2014 |
| - blade = self.mv(S(1), 'scalar') |
2015 |
| - for ibasis in iblade: |
2016 |
| - blade ^= basis[ibasis] |
2017 |
| - blade = blade.trigsimp() |
2018 |
| - grade.append(blade) |
2019 |
| - MFbasis.append(grade) |
2020 |
| - E = MFbasis[-1][0] |
2021 |
| - E_sq = trigsimp((E * E).scalar()) |
2022 | 2001 |
|
2023 |
| - duals = copy.copy(MFbasis[-2]) |
| 2002 | + def wedge_reduce(mvs): |
| 2003 | + """ wedge together a list of multivectors """ |
| 2004 | + if not mvs: |
| 2005 | + return self.mv(S(1), 'scalar') |
| 2006 | + return functools.reduce(operator.xor, mvs).trigsimp() |
| 2007 | + |
| 2008 | + E = wedge_reduce(basis) |
| 2009 | + |
| 2010 | + # elements are such that `basis[i] ^ co_basis[i] == E` |
| 2011 | + co_basis = [ |
| 2012 | + sign * wedge_reduce(basis_subset) |
| 2013 | + for sign, basis_subset in zip( |
| 2014 | + # alternating signs |
| 2015 | + itertools.cycle([S(1), S(-1)]), |
| 2016 | + # tuples with one basis missing |
| 2017 | + itertools.combinations(basis, len(basis) - 1), |
| 2018 | + ) |
| 2019 | + ] |
2024 | 2020 |
|
2025 |
| - duals.reverse() |
2026 |
| - sgn = S(1) |
2027 |
| - rbasis = [] |
2028 |
| - for dual in duals: |
2029 |
| - recpv = (sgn * dual * E).trigsimp() |
2030 |
| - rbasis.append(recpv) |
2031 |
| - sgn = -sgn |
| 2021 | + # take the dual without normalization |
| 2022 | + r_basis = [(co_base * E).trigsimp() for co_base in co_basis] |
2032 | 2023 |
|
| 2024 | + # normalize |
| 2025 | + E_sq = trigsimp((E * E).scalar()) |
2033 | 2026 | if mode == 'norm':
|
2034 |
| - for i in range(dim): |
2035 |
| - rbasis[i] = rbasis[i] / E_sq |
| 2027 | + r_basis = [r_base / E_sq for r_base in r_basis] |
2036 | 2028 | else:
|
2037 | 2029 | if mode != 'append':
|
2038 | 2030 | # galgebra 0.5.0
|
2039 | 2031 | warnings.warn(
|
2040 | 2032 | "Mode {!r} not understood, falling back to {!r} but this "
|
2041 | 2033 | "is deprecated".format(mode, 'append'),
|
2042 | 2034 | DeprecationWarning, stacklevel=2)
|
2043 |
| - rbasis.append(E_sq) |
| 2035 | + r_basis.append(E_sq) |
2044 | 2036 |
|
2045 |
| - return tuple(rbasis) |
| 2037 | + return tuple(r_basis) |
2046 | 2038 |
|
2047 | 2039 | def Mlt(self, *args, **kwargs):
|
2048 | 2040 | return lt.Mlt(args[0], self, *args[1:], **kwargs)
|
|
0 commit comments