|
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