// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/*
* MultivectorInfo.java
*
* Created on October 19, 2005, 12:14 PM
*
* Copyright 2005-2007 Daniel Fontijne, University of Amsterdam
* fontijne@science.uva.nl
*
*/
package subspace.basis;
/**
* A class that computes whether a multivector is a blade or a versor,
* and if so, what is the grade and parity of the blade/versor.
*
* <p>If you just want to know if something is a blade, don't provide
* any metric, since non-invertible blades are blades too.
*
* @author fontijne
*/
public class MultivectorType {
protected final static int _VERSOR = 2;
protected final static int _BLADE = 4;
public final static int MULTIVECTOR = 1;
public final static int VERSOR = MULTIVECTOR | _VERSOR; // a versor is a multivector too
public final static int BLADE = VERSOR | _BLADE; // a blade is a versor too
/** true if multivector is zero */
protected boolean zero;
/** MULTIVECTOR, VERSOR, or BLADE */
protected int type;
/** top grade occupied by the multivector */
protected int grade;
/** grade usage (bitmap containing what grade parts are present) */
protected int gradeUsage;
/** parity (1 = odd, 0 = even , -1 is none)*/
protected int parity;
/** Creates a new instance of MultivectorInfo */
public MultivectorType(Multivector A) {
init(A, null, 0.0);
}
/** Creates a new instance of MultivectorInfo */
public MultivectorType(Multivector A, double epsilon) {
init(A, null, epsilon);
}
/** Creates a new instance of MultivectorInfo */
public MultivectorType(Multivector A, Object metric) {
init(A, metric, 0.0);
}
/** Creates a new instance of MultivectorInfo */
public MultivectorType(Multivector A, Object metric, double epsilon) {
init(A, metric, epsilon);
}
/**
* Called by constructor to initialize the instance
* Performs the actual test if 'A' is a versor or blade under 'metric'
*/
protected void init(Multivector A, Object metric, double epsilon) {
// first of all determine grade usage & parity
Multivector cA = ((epsilon == 0.0) ? A : A.compress(epsilon));
grade = cA.topGradeIndex();
gradeUsage = cA.gradeUsage();
{
final int[] cnt = new int[]{0, 0}; // nb even, odd grade parts in use
int cntIdx = 0;
int gu = gradeUsage;
while (gu != 0) {
if ((gu & 1) != 0)
cnt[cntIdx]++;
cntIdx ^= 1;
gu >>>= 1;
}
if ((cnt[0] == 0) && (cnt[1] == 0)) {
// multivector = zero blade, case closed
zero = true;
type = BLADE;
parity = 0;
grade = -1;
return;
}
else {
zero = false;
if ((cnt[0] != 0) && (cnt[1] != 0)) {
// multivector = multivector, case closed
type = MULTIVECTOR;
parity = -1;
return;
}
else // more work to do, but parity is known:
parity = (cnt[1] != 0) ? 1 : 0;
}
}
// determine if versor or blade:
// get versor inverse, grade inversion:
Multivector Avi;
try {
Avi = A._versorInverse(metric);
} catch (java.lang.ArithmeticException ex) {
type = MULTIVECTOR;
return;
}
Multivector Agi = A.gradeInversion();
// check if Agi Avi is a scalar:
if (Agi._gp(Avi, metric).compress(epsilon).gradeUsage() != 1) {
// multivector = multivector, case closed
type = MULTIVECTOR;
return;
}
// check if Agi Avi == Avi Agi
if (!Agi._gp(Avi, metric).subtract(Avi._gp(Agi, metric)).compress(epsilon).isNull()) {
// multivector = multivector, case closed
type = MULTIVECTOR;
return;
}
// check if grade preserving for all basis vectors:
int dim = A.spaceDim();
for (int i = 0; i < dim; i++) {
Multivector ei = new Multivector(new BasisBlade(1 << i));
if (Avi._gp(ei, metric)._gp(Agi, metric).compress().gradeUsage() != 2) {
// multivector = multivector, case closed
type = MULTIVECTOR;
return;
}
}
// if homogeneous: blade
if (subspace.util.Bits.bitCount(gradeUsage) == 1)
type = BLADE;
else type = VERSOR;
}
/** @return MULTIVECTOR, VERSOR, or BLADE */
public int getType() {
return type;
}
/** @return true if multivector is zero */
public boolean isZero() {
return zero;
}
/** @return true if multivector is a versor */
public boolean isVersor() {
return ((getType() & _VERSOR) != 0);
}
/** @return true if multivector is a blade */
public boolean isBlade() {
return ((getType() & _BLADE) != 0);
}
/** @return grade of the multivector */
public int getTopGradeIndex() {
return grade;
}
/** @return grade usage of the multivector */
public int getGradeUsage() {
return gradeUsage;
}
/** @return true if multivector is even versor */
public boolean isEven() {
return parity == 0;
}
public boolean isOdd() {
return parity == 1;
}
/** parity (1 = odd, 0 = even , -1 is none)*/
public int getParity() {
return parity;
}
public String toString() {
return "Multivector type[" +
"type = " + (isBlade() ? "blade" : (isVersor() ? "versor" : "multivector")) +
", parity = " + (isEven() ? "even" : (isOdd() ? "odd" : "none")) +
", top grade index = " + getTopGradeIndex() +
", grade usage = " + getGradeUsage() + "]";
}
}