pygae / galgebra

Symbolic Geometric Algebra/Calculus package for SymPy :crystal_ball:
https://galgebra.rtfd.io/
BSD 3-Clause "New" or "Revised" License
233 stars 62 forks source link

Mv.dual() method return wrong result #514

Open mammalwong opened 7 months ago

mammalwong commented 7 months ago

To reproduce the bug, run this in a Jupyter/Colab cell:

ga = Ga('e', g=[1,1,1], coords=S.symbols('x y z', real=True), wedge=False)
ex,ey,ez = ga.mv()
I = ga.i
(ex*I) * (ex*I).dual(), (ex*I).dual() * (ex*I), ga.dual_mode_value

Which outputs: (-e_xyz, -e_xyz, 'I+')

Expected correct result: (e_xyz, e_xyz, 'I+')

mammalwong commented 7 months ago

The current implementation of Mv.dual() only multiply the input multivector by the pseudoscalar I in different ways according to the dual mode, but according to this: https://youtu.be/2AKt6adG_OI?t=1611&si=Z8VbJiqwMEVUlCW1, the implementation will not give correct result in some situations, the dual multivector v of v should always produce this result: v (v) = I, where I is the pseudoscalar.

mammalwong commented 6 months ago

Hi @utensil, I found galgebra have no "dual inverse" (hodge star inverse $\ast^{-1}$ in https://youtu.be/2AKt6adG_OI?t=1611&si=Z8VbJiqwMEVUlCW1) while there are "dual" of multivectors? I found there are two funny definition of dual/dual-inverse and may be you will interest in it:

1) from https://www.rigidgeometricalgebra.org/wiki/index.php?title=Complements they call dual/dual-inverse as right/left complement respectively, it works with degenerate GA, with I as the pseudo scalar, the dual/right-complement of X is defined as X dual(X) = I and the dual-inverse/left-complement of X is defined as dual-inverse(X) X = I, and dual(dual-inverse(X)) = dual-inverse(dual(X)) = X. I think it is more standard than the second definition below since X * dual(X) is always equal to I so when a dual multivector is interacting with an ordinary multivector the result is more "predictable".

2) from https://github.com/enkimute/ganja.js their dual and dual-inverse is the same function, they sorted their basis (of all grades, including basis like 1 and pseudo scalar) such that when a = basis and b = list(reversed(basis)), a[i] b[i] is always equal either I or -I, and the dual and dual-inverse is just to reverse the ordering of the components of a multivector (e.g. dual([1,2,3,4]) is simply [4,3,2,1] and dual-inverse([4,3,2,1]) is also simply [1,2,3,4]). The pros is the dual and dual-inverse are the same function but the cons is for some basis Y, Y dual(Y) may equal to -I instead of I.

I am not sure how exactly they work when the pseudoscalar can not be normalized because of degenerate basis set, but definition 1 is specifically defined for projective GA which is always degenerate. However, https://www.rigidgeometricalgebra.org/wiki/index.php?title=Geometric_norm state for any degenerate basis like the pseudo scalar in projective GA, although it can not be normalized because the basis square to 0, the dual of a degenerate basis is always non-degenerate (like the dual of a degenerate pseudo scalar I is always a scalar which is non-degenerate), so we can "normalize" a degenerate basis like I by doing dual-inverse(normalize(dual(I))). It is absolutely beyond my math understanding so I am just mentioning this as a record.

Complements - Rigid Geometric Algebra
GitHub
GitHub - enkimute/ganja.js: :triangular_ruler: Javascript Geometric Algebra Generator for Javascript, c++, c#, rust, python. (with operator overloading and algebraic literals) -
:triangular_ruler: Javascript Geometric Algebra Generator for Javascript, c++, c#, rust, python. (with operator overloading and algebraic literals) - - GitHub - enkimute/ganja.js: :triangular_rule...
utensil commented 6 months ago

With the latest branch , per http://www.faculty.luther.edu/~macdonal/GAlgebraPrimer.pdf , the behavior you desire can be restored by adding a Ga.dual_mode('Iinv+') call after imports.

This means the dual will be calculated by $M^* = M I^{-1}$.

undual is also defined in the branch, $M^{-*} = M I^{-1}$ by default, and Ga.dual_mode('Iinv+') takes it to $M\^{-*} = M I$.

GAlgebra embraces as many conventions as possible, via modes.

mammalwong commented 6 months ago

@utensil thanks for the explanation 👍

utensil commented 6 months ago

@mammalwong Issues reported by you are mostly fixed in the latest branch, except the ones marked with enhancement.

The branch will be included in the 0.6.0 release. It's recommend to try the branch out, I have just made it green again and should be (known) bug-free now. I will also include these fixes in a 0.5.3 release if you find more issues.

mammalwong commented 6 months ago

@utensil thanks for the notification, I have tried the primer-update branch and confirmed my reported non-enhancement issues except #511 are fixed already. I will report issues if I find more.

utensil commented 6 months ago

Ah, sorry, I missed that one. Thanks!