Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions galgebra/ga.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from itertools import combinations
import functools
from functools import reduce
from typing import Tuple, TypeVar, Callable, Dict
from typing import Tuple, TypeVar, Callable, Dict, Sequence
from ._backports.typing import OrderedDict

from sympy import (
Expand Down Expand Up @@ -1976,14 +1976,27 @@ def connection(self, rbase, key_base, mode, left):
self.connect[mode_key].append((key, C))
return C

def ReciprocalFrame(self, basis, mode='norm'):
"""
If ``basis`` is a list/tuple of vectors, ``ReciprocalFrame()`` returns a tuple of reciprocal vectors.
def ReciprocalFrame(self, basis: Sequence[_mv.Mv], mode: str = 'norm') -> Tuple[_mv.Mv]:
r"""
Compute the reciprocal frame :math:`v^i` of a set of vectors :math:`v_i`.

If ``mode=norm`` the vectors are normalized.
If ``mode`` is anything other than ``norm`` the vectors are unnormalized
and the normalization coefficient is added to the end of the tuple.
One must divide by this coefficient to normalize the vectors.
Parameters
----------
basis :
The sequence of vectors :math:`v_i` defining the input frame.
mode :
* ``"norm"`` -- indicates that the reciprocal vectors should be
normalized such that their product with the input vectors is 1,
:math:`v^i \cdot v_j = \delta_{ij}`.
* ``"append"`` -- indicates that instead of normalizing, the
normalization coefficient :math:`E^2` should be appended to the returned tuple.
One can divide by this coefficient to normalize the vectors.
The returned vectors are such that
:math:`v^i \cdot v_j = E^2\delta_{ij}`.

.. deprecated:: 0.5.0
Arbitrary strings are interpreted as ``"append"``, but in
future will be an error
"""
dim = len(basis)

Expand Down Expand Up @@ -2017,11 +2030,17 @@ def ReciprocalFrame(self, basis, mode='norm'):
rbasis.append(recpv)
sgn = -sgn

if mode != 'norm':
rbasis.append(E_sq)
else:
if mode == 'norm':
for i in range(dim):
rbasis[i] = rbasis[i] / E_sq
else:
if mode != 'append':
# galgebra 0.5.0
warnings.warn(
"Mode {!r} not understood, falling back to {!r} but this "
"is deprecated".format(mode, 'append'),
DeprecationWarning, stacklevel=2)
rbasis.append(E_sq)

return tuple(rbasis)

Expand Down
27 changes: 27 additions & 0 deletions test/test_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,33 @@ def test_extracting_vectors_from_conformal_2_blade(self):
aB = a|B
assert str(aB) == '-(P2.a)*P1 + (P1.a)*P2'

def test_ReciprocalFrame(self):
ga, *basis = Ga.build('e*u|v|w')

r_basis = ga.ReciprocalFrame(basis)

for i, base in enumerate(basis):
for r_i, r_base in enumerate(r_basis):
if i == r_i:
assert (base | r_base).simplify() == 1
else:
assert (base | r_base).simplify() == 0

def test_ReciprocalFrame_append(self):
ga, *basis = Ga.build('e*u|v|w')
*r_basis, E_sq = ga.ReciprocalFrame(basis, mode='append')

for i, base in enumerate(basis):
for r_i, r_base in enumerate(r_basis):
if i == r_i:
assert (base | r_base).simplify() == E_sq
else:
assert (base | r_base).simplify() == 0

# anything that isn't 'norm' means 'append', but this is deprecated
with pytest.warns(DeprecationWarning):
assert ga.ReciprocalFrame(basis, mode='nonsense') == (*r_basis, E_sq)

def test_reciprocal_frame_test(self):

g = '1 # #,'+ \
Expand Down