// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License

// 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
*
* @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

/** true if multivector is zero */
protected boolean zero;

/** MULTIVECTOR, VERSOR, or BLADE */
protected int type;
/** top grade occupied by the multivector */
/** 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));
{
final int[] cnt = new int[]{0, 0}; // nb even, odd grade parts in use
int cntIdx = 0;
while (gu != 0) {
if ((gu & 1) != 0)
cnt[cntIdx]++;
cntIdx ^= 1;
gu >>>= 1;
}

if ((cnt == 0) && (cnt == 0)) {
// multivector = zero blade, case closed
zero = true;
parity = 0;
return;
}
else {
zero = false;
if ((cnt != 0) && (cnt != 0)) {
// multivector = multivector, case closed
type = MULTIVECTOR;
parity = -1;
return;
}
else // more work to do, but parity is known:
parity = (cnt != 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;
}

// 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;
}

}

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 */
return ((getType() & _BLADE) != 0);
}

/** @return grade of the multivector */
}

/** @return grade usage of the multivector */
}

/** @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")) +