`.is_versor()` method in class `Mv` of module mv.py uses an incorrect algorithm
The multivector method .is_versor() purports to follow the test on p. 533 of Leo Dorst's Geometric Algebra for Computer Science. But:
- Dorst's test itself, as it appears in GACS, is incorrect, as shown by a simple counterexample.
- The algorithm used in
.is_versor()does not faithfully implement Dorst's test. - The algorithm used in
.is_versor()has a simple counterexample.
I have devised four conditions satisfied by versors which, if satisfied, also imply that a multivector is a versor. I am currently checking with Dorst as to his opinion, but I'm pretty confident in my reasoning.
Let V be a multivector, and let V.rev() and V.g_invol() be its reverse and grade involute. Let x be a generic 1-vector. Then V will be a versor if and only if it meets each of the following conditions:
-
V * V.rev()andV.rev() * Vare both scalars. -
V * V.rev()is not zero. -
V.g_invol() * V.rev()is a scalar. -
V.g_invol() * x * V.rev()is a vector.
The counterexamples, if anyone's interested, are these:
- To Dorst's test as it appears in GACS: Let V = 1 + I where I = e0 e1 e2 e3 is the unit pseudoscalar of the spacetime algebra G(1,3). Then V meets the conditions described by GACS, but the geometric product V (reverse of V) is not a scalar, showing that V cannot be a versor.
- To the algorithm currently used in
.is_versor(): Let V = e1 + e2 e3 in the algebra G(3,0) of Euclidean 3-space. Then V passes the test in.is_versor(), but V cannot be a versor as it is a mixture of odd and even grades.
I will post further after hearing back from Dorst. In the meanwhile, I have a proposed rewrite of the .is_versor() method that I am testing. Once my testing is satisfied, I'll post my rewrite here.
Greg Grunberg [email protected] 2025 March 04
Greg, many thanks for sharing this with the community, also, thanks for your previous work that merged into GAlgebra main branch in #510 .
Given that V * V.rev() is a nonzero scalar, the requirement that V.rev() * V be a scalar becomes superfluous, for then V.rev() * V will equal V * V.rev(). Instead of the four conditions listed in my original issue statement, the sufficient conditions for V to be a versor may be taken to be
-
V * V.rev()is a nonzero scalar. -
V.g_invol() * V.rev()is a scalar. -
V.g_invol() * x * V.rev()is a vector wheneverxis a vector.
I have written a detailed mathematical proof that those three conditions are equivalent to V being a versor. Email me a request and I'll gladly provide a PDF of the proof.
Greg Grunberg [email protected] 2025 March 09
I have eliminated as superfluous one of the three tests for versorhood mentioned in my post of 2025 March 09. It's necessary to show only that
-
V * V.rev()is a nonzero scalar. -
V.g_invol() * x * V.rev()is a vector wheneverxis a 1-vector.
Again, a PDF is available.
Greg Grunberg [email protected] 2025 March 12
My initial attempt at actual Python code for the test follows. Be cautioned that I have not yet tried out that code. I am aware that its computation of self * reverse twice is an inefficiency.
def is_versor(self) -> bool:
"""
Tests for versor status of `self`, where a versor is defined as
a geometric product of finitely-many nonnull vectors.
Sets self.versor_flg and returns its value.
"""
if self.versor_flg is not None:
return self.versor_flg
self.characterise_Mv()
reverse = self.rev()
involute = self.g_invol() # self's grade involute
self.versor_flg = (self * reverse).is_scalar() \
and not (self * reverse).is_zero() \
and (involute * self.Ga._XOX * reverse).is_vector()
# self.Ga._XOX is a generic vector in self's geometric algebra
return self.versor_flg
Hi @Greg1950 , sorry for the delay, I've created a PR #536 for this, along with some test cases from the top of my head. Can you review the code and tests? Thanks!