Skip to content

Commit 1e0bc39

Browse files
committed
Simplify the implementation of ReciprocalFrame
This is fewer lines and more comments
1 parent be5d8a8 commit 1e0bc39

File tree

1 file changed

+34
-37
lines changed

1 file changed

+34
-37
lines changed

galgebra/ga.py

+34-37
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
import operator
66
import copy
77
from collections import OrderedDict
8-
from itertools import combinations
8+
import itertools
99
import functools
1010
from functools import reduce
11-
from typing import Tuple, TypeVar, Callable, Mapping
11+
from typing import Tuple, TypeVar, Callable, Mapping, Sequence
1212

1313
from sympy import (
1414
diff, Rational, Symbol, S, Mul, Add,
@@ -27,6 +27,10 @@
2727
zero = S(0)
2828

2929

30+
# needed to avoid clashes below
31+
_mv = mv
32+
33+
3034
def 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

Comments
 (0)