``````
// 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.

/*
*
* Created on February 1, 2005, 11:41 AM
*
* Copyright 2005-2007 Daniel Fontijne, University of Amsterdam
* fontijne@science.uva.nl
*
*/

package subspace.basis;

import java.util.ArrayList;

/**
* A simple class to represent a basis blade.
*
* <p>mutable :( Should have made it immutable . . .
*
* <p>Could use subspace.util.Bits.lowestOneBit() and such to make
* loops slightly more efficient, but didn't to keep text simple for the book.
*
* @author  fontijne
*/
final public class BasisBlade implements Cloneable, InnerProductTypes {

/** temp for testing */
public static void main(String args[]) {

double[][] m = new double[][]{
{1.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 1.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0 ,0.0, -1.0},
{0.0, 0.0, 0.0 , -1.0, 0.0}
};

try {
Metric M = new Metric(m); {
for (int i = 0; i < 32; i++)
for (int j = 0; j < 32; j++) {
ArrayList R = Util.round(gp(a, b, M), 1.0, 0.0001);
}
}
/*
ArrayList L = new ArrayList();
long t = System.currentTimeMillis();
for (int i = 0; i < 32; i++)
for (int j = 0; j < 32; j++) {
ArrayList R = gp(a, b, M);
System.out.println(a + " " + b + " = " + R);
}

System.out.println("time: " + (System.currentTimeMillis() - t));*/
} catch (subspace.metric.MetricException E) {
System.out.println("Exception: " + E);
}

}

/** constructs an instance of BasisBlade */
public BasisBlade(int b, double s) {
bitmap = b;
scale = s;
}

/** constructs an instance of a unit BasisBlade */
bitmap = b;
scale = 1.0;
}

/** constructs an instance of a scalar BasisBlade */
bitmap = 0;
scale = s;
}

/** constructs an instance of a zero BasisBlade */
bitmap = 0;
scale = 0.0;
}

/**
* by <code>a<code> and <code>b</code> into canonical order.
*/
public static double canonicalReorderingSign(int a, int b) {
// Count the number of basis vector flips required to
// get a and b into canonical order.
a >>= 1;
int sum = 0;
while (a != 0) {
sum += subspace.util.Bits.bitCount(a & b);
a >>= 1;
}

// even number of flips -> return 1
// odd number of flips -> return 1
return ((sum & 1) == 0) ? 1.0 : -1.0;
}

/** shortcut to outerProduct() */
return outerProduct(a, b);
}

/** @return the outer product of two basis blades */
return gp_op(a, b, true);
}

/** shortcut to geometricProduct() */
return geometricProduct(a, b);
}

/** return the geometric product of two basis blades */
return gp_op(a, b, false);
}

/**
* @return the geometric product or the outer product
* of 'a' and 'b'.
*/
// if outer product: check for independence
if (outer && ((a.bitmap & b.bitmap) != 0))

// compute the bitmap:
int bitmap = a.bitmap ^ b.bitmap;

// compute the sign change due to reordering:
double sign = canonicalReorderingSign(a.bitmap, b.bitmap);

// return result:
return new BasisBlade(bitmap, sign * a.scale * b.scale);
}

/** shortcut to geometricProduct() */
return geometricProduct(a, b, m);
}

/**
* @return reverse of this basis blade (always a newly constructed blade)
*/
// multiplier = (-1)^(x(x-1)/2)
}

/**
*/
// multiplier is (-1)^x
}

/**
* @return clifford conjugate of this basis blade (always a newly constructed blade)
*/
// multiplier is ((-1)^(x(x+1)/2)
}

/**
* Computes the geometric product of two basis blades in limited non-Euclidean metric.
* @param m is an array of doubles giving the metric for each basis vector.
*/
// compute the geometric product in Euclidean metric:

// compute the meet (bitmap of annihilated vectors):
int bitmap = a.bitmap & b.bitmap;

// change the scale according to the metric:
int i = 0;
while (bitmap != 0) {
if ((bitmap & 1) != 0) result.scale *= m[i];
i++;
bitmap = bitmap >> 1;
}

return result;
}

return geometricProduct(a, b, M);
}

/**
* Computes the geometric product of two basis blades in arbitary non-Euclidean metric.
* @param M is an instance of Metric giving the metric (and precomputed eigen vectors).
* @return an ArrayList, because the result does not have to be a single BasisBlade anymore . . .
*/
// convert argument to eigenbasis
ArrayList A = M.toEigenbasis(a);
ArrayList B = M.toEigenbasis(b);

ArrayList result = new ArrayList();
for (int i = 0; i < A.size(); i++) {
for (int j = 0; j < B.size(); j++) {
}
}

return M.toMetricBasis(simplify(result));
}

/**
* @return the geometric product of two basis blades
* @param type gives the type of inner product:
* LEFT_CONTRACTION,RIGHT_CONTRACTION, HESTENES_INNER_PRODUCT or MODIFIED_HESTENES_INNER_PRODUCT.
*/
}

/**
* Computes the inner product of two basis blades in limited non-Euclidean metric.
* @param m is an array of doubles giving the metric for each basis vector.
* @param type gives the type of inner product:
* LEFT_CONTRACTION,RIGHT_CONTRACTION, HESTENES_INNER_PRODUCT or MODIFIED_HESTENES_INNER_PRODUCT.
*/
}

/**
* Computes the inner product of two basis blades in arbitary non-Euclidean metric.
* @param M is an instance of Metric giving the metric (and precomputed eigen vectors).
* @param type gives the type of inner product:
* LEFT_CONTRACTION,RIGHT_CONTRACTION, HESTENES_INNER_PRODUCT or MODIFIED_HESTENES_INNER_PRODUCT.
* @return an ArrayList, because the result does not have to be a single BasisBlade anymore . . .
*
* <p>Todo: no need to return an ArrayList here? Result is always a single blade?
*/
public static ArrayList innerProduct(BasisBlade a, BasisBlade b, Metric M, int type) {
}

/** shortcut to innerProduct(...) */
return innerProduct(a, b, type);
}

/** shortcut to innerProduct(...) */
return innerProduct(a, b, m, type);
}

/** shortcut to innerProduct(...) */
public static ArrayList ip(BasisBlade a, BasisBlade b, Metric M, int type) {
return innerProduct(a, b, M, type);
}

return subspace.util.Bits.bitCount(bitmap);
}

/** @return pow(-1, i) */
public static int minusOnePow(int i) {
return ((i & 1) == 0) ? 1 : -1;
}

public boolean equals(Object O) {
return ((B.bitmap == bitmap) && (B.scale == scale));
}
else return false;
}

public int hashCode() {
return new Integer(bitmap).hashCode() ^ new Double(scale).hashCode();
}

public String toString() {
}

/**
* @param bvNames The names of the basis vector (e1, e2, e3) are used when
* not available
*/
public String toString(String[] bvNames) {
StringBuffer result = new StringBuffer();
int i = 1;
int b = bitmap;
while (b != 0) {
if ((b & 1) != 0) {
if (result.length() > 0) result.append("^");
if ((bvNames == null) || (i > bvNames.length) || (bvNames[i-1] == null))
result.append("e" + i);
else result.append(bvNames[i-1]);
}
b >>= 1;
i++;
}

return (result.length() == 0) ? new Double(scale).toString() : scale + "*" + result.toString();
}

}

public Object clone() {
}

private static ArrayList innerProductFilter(int ga, int gb, ArrayList R, int type) {
ArrayList result = new ArrayList();
for (int i = 0; i < R.size(); i++) {
if (B.scale != 0.0)
}
return result;
}

/**
* Applies the rules to turn a geometric product into an inner product
* @param ga Grade of argument 'a'
* @param gb Grade of argument 'b'
* @param r the basis blade to be filter
* @param type the type of inner product required:
* LEFT_CONTRACTION,RIGHT_CONTRACTION, HESTENES_INNER_PRODUCT or MODIFIED_HESTENES_INNER_PRODUCT
* @return Either a 0 basis blade, or 'r'
*/
private static BasisBlade innerProductFilter(int ga, int gb, BasisBlade r, int type) {
switch(type) {
case LEFT_CONTRACTION:
if ((ga > gb) || (r.grade() != (gb-ga)))
else return r;
case RIGHT_CONTRACTION:
if ((ga < gb) || (r.grade() != (ga-gb)))
else return r;
case HESTENES_INNER_PRODUCT:
if ((ga == 0) || (gb == 0)) return new BasisBlade();
// drop through to MODIFIED_HESTENES_INNER_PRODUCT
case MODIFIED_HESTENES_INNER_PRODUCT:
if (Math.abs(ga - gb) == r.grade()) return r;
default:
return null;
}
}

static private class simplifyComperator implements java.util.Comparator {
public int compare(Object o1, Object o2) {
return ((B1.bitmap < B2.bitmap) ? -1 :
((B1.bitmap > B2.bitmap) ? 1 : Double.compare(B1.scale, B2.scale)));
}
}

/** simplifies an arraylist (sum) of BasisBlades (destroys ordering of A!) */
static protected ArrayList simplify(ArrayList A) {
if (A.size() == 0) return A;

java.util.Collections.sort(A, new simplifyComperator());
ArrayList result = new ArrayList();
for (int i = 1; i < A.size(); i++) {
if (b.bitmap == current.bitmap) current.scale += b.scale;
else {
if (current.scale != 0.0)
current = b.copy();
}
}
if (current.scale != 0.0)

return result;
}

/**
* Rounds the scalar part of <code>this</code> to the nearest multiple X of <code>multipleOf</code>,
* if |X - what| <= epsilon. This is useful when eigenbasis is used to perform products in arbitrary
* metric, which leads to small roundof errors. You don't want to keep these roundof errors if your
* are computing a multiplication table.
*
* @returns a new basis blade if a change is required.
*/
public BasisBlade round(double multipleOf, double epsilon) {
double a = subspace.util.DoubleU.round(scale, multipleOf, epsilon);
if (a != scale)
else return this;
}

/**
* This bitmap specifies what basis vectors are
* present in this basis blade
*/
public int bitmap;

/**
* The scale of the basis blade is represented by this double
*/
public double scale;

} // end of class BasisBlade

// leave this comment such that when view in HTML, the final part of the class will display properly

``````