package de.gaalop.productComputer;
/**
* Calculates the inner product of two blades
* @author christian
*/
public class InnerProductCalculator implements ProductCalculator {
/**
* Calculates the inner product of two one grade blades
* @param b1 The first blade
* @param b2 The second blade
* @param result The result of the inner product
* @param bitCount The maximum number of bits
* @param squareMask The signature
* @return true, if the result is not empty; false, otherwise
*/
private boolean calcInner1Product1(SignedBlade b1, SignedBlade b2, SignedBlade result, int bitCount, byte[] squareMask) {
result.clear();
result.coefficient = b1.coefficient * b2.coefficient;
Blade aAndB = new Blade(bitCount, b1);
aAndB.and(b2);
if (aAndB.isEmpty()) {
return false;
}
for (int index=0;index<bitCount;index++)
if (aAndB.get(index)) {
result.coefficient *= squareMask[index];
return (squareMask[index] != 0);
}
throw new IllegalStateException("InnerProductCalculator.calcInner1Product1: state not allowed");
}
/**
* Calculates the inner product of one one-grade blade and one two-or-more-grade blade
* @param b1 The first blade (grade one)
* @param b2 The second blade (grade two-or-more)
* @param result The result of the inner product
* @param bitCount The maximum number of bits
* @param squareMask The signature
* @return true, if the result is not empty; false, otherwise
*/
private boolean calcInner1Productn(SignedBlade b1, SignedBlade b2, SignedBlade result, int bitCount, byte[] squareMask) {
Blade aAndBMasked2 = new Blade(bitCount, b1);
aAndBMasked2.and(b2);
if (!aAndBMasked2.isEmpty()) {
result.coefficient = b1.coefficient * b2.coefficient;
result.clear();
result.or(b1);
result.xor(b2);
boolean negate = false;
int i = 0;
while (!b1.get(i)) {
if (b2.get(i)) {
negate = !negate;
}
i++;
}
if (negate) {
result.coefficient *= -1;
}
for (int index = 0;index<bitCount;index++)
if (aAndBMasked2.get(index)) {
result.coefficient *= squareMask[index];
if (squareMask[index] == 0)
return false;
}
return true;
}
return false;
}
/**
* Calculates the inner product of one two-or-more-grade blade and one one-grade blade
* @param b1 The first blade (grade two-or-more)
* @param b2 The second blade (grade one)
* @param result The result of the inner product
* @param bitCount The maximum number of bits
* @param squareMask The signature
* @return true, if the result is not empty; false, otherwise
*/
private boolean calcInnernProduct1(SignedBlade b1, SignedBlade b2, SignedBlade result, int bitCount, byte[] squareMask) {
Blade aAndBMasked3 = new Blade(bitCount, b1);
aAndBMasked3.and(b2);
if (!aAndBMasked3.isEmpty()) {
result.coefficient = b1.coefficient * b2.coefficient;
result.clear();
result.or(b1);
result.xor(b2);
boolean negate = false;
int i = bitCount - 1;
while (!b2.get(i)) {
if (b1.get(i)) {
negate = !negate;
}
i--;
}
if (negate) {
result.coefficient *= -1;
}
for (int index = 0;index<bitCount;index++)
if (aAndBMasked3.get(index)) {
result.coefficient *= squareMask[index];
if (squareMask[index] == 0)
return false;
}
return true;
}
return false;
}
/**
* Calculates the inner product of two two-or-more-grade blades
* @param b1 The first blade
* @param b2 The second blade
* @param result The result of the inner product
* @param bitCount The maximum number of bits
* @param squareMask The signature
* @return true, if the result is not empty; false, otherwise
*/
private boolean calcInnernProductn(SignedBlade b1, SignedBlade b2, SignedBlade result, int bitCount, byte[] squareMask) {
if (b1.cardinality() > b2.cardinality()) {
// Bl*ak, k<l
SignedBlade b1Cp = new SignedBlade(bitCount, b1, b1.coefficient);
boolean add = false;
for (int i = 0; i < bitCount; ++i) {
if (b2.get(i)) {
SignedBlade maskedBlade = new SignedBlade(bitCount);
maskedBlade.set(i);
SignedBlade toB1Cp = new SignedBlade(bitCount);
if (!calcInnernProduct1(b1Cp, maskedBlade, toB1Cp, bitCount, squareMask)) {
return false;
}
b1Cp = toB1Cp;
add = true;
}
}
result.clear();
result.or(b1Cp);
result.coefficient *= b1Cp.coefficient*b2.coefficient;
return add;
} else {
// ak*bl, k<l
SignedBlade b2Cp = new SignedBlade(bitCount, b2, b2.coefficient);
boolean add = false;
for (int i = bitCount - 1; i >= 0; --i) {
if (b1.get(i)) {
SignedBlade maskedBlade = new SignedBlade(bitCount);
maskedBlade.set(i);
SignedBlade toB2Cp = new SignedBlade(bitCount);
if (!calcInner1Productn(maskedBlade, b2Cp, toB2Cp, bitCount, squareMask)) {
return false;
}
b2Cp = toB2Cp;
add = true;
}
}
result.clear();
result.or(b2Cp);
result.coefficient *= b2Cp.coefficient*b1.coefficient;
return add;
}
}
@Override
public void calcProduct(SignedBlade b1, SignedBlade b2, SumOfBlades innerProduct, int bitCount, byte[] squareMask) {
if (!b1.isEmpty() && !b2.isEmpty()) {
SignedBlade result = new SignedBlade(bitCount);
if (b1.cardinality() == 1) {
if (b2.cardinality() == 1) {
//length(b1) = 1 && length(b2) = 1
if (calcInner1Product1(b1, b2, result, bitCount, squareMask))
innerProduct.add(result);
} else {
//length(b1) = 1 && length(b2) > 1
if (calcInner1Productn(b1, b2, result, bitCount, squareMask))
innerProduct.add(result);
}
} else {
if (b2.cardinality() == 1) {
//length(b1) > 1 && length(b2) = 1
if (calcInnernProduct1(b1, b2, result, bitCount, squareMask))
innerProduct.add(result);
} else {
//length(b1) > 1 && length(b2) > 1
if (calcInnernProductn(b1, b2, result, bitCount, squareMask))
innerProduct.add(result);
}
}
}
}
}