-
Notifications
You must be signed in to change notification settings - Fork 1
Math with Class (Java)
Sometimes the default primitive data types like
double, float, int, short, byte, long... are not enough!
One classic example for an important numeric format which is not embedded
into most languages is the complex number.
If you want to go beyond primitive data types and
get any class to act as a numeric type within a tensor and tensor operations
then take a look at the
following example.
First we have to define a class acting as numeric data type, meaning it implements
methods like "plus", "minus", "divide" and so on...
Let's create a simple "ComplexNumber" class:
public class ComplexNumber
{
private double real = 0.0
private double imaginary = 0.0
public ComplexNumber(double real, double imaginary){
this.real = real; this.imaginary = imaginary;
}
public ComplexNumber plus(ComplexNumber z2) {
return new ComplexNumber(this.real + z2.real, this.imaginary + z2.imaginary);
}
public ComplexNumber minus(ComplexNumber z2) {
return new ComplexNumber(this.real - z2.real, this.imaginary - z2.imaginary);
}
public ComplexNumber multiply(ComplexNumber z2) {
double _real = this.real*z2.real - this.imaginary*z2.imaginary;
double _imaginary = this.real*z2.imaginary + this.imaginary*z2.real;
return new ComplexNumber(_real,_imaginary);
}
public ComplexNumber divide(ComplexNumber z2) {
ComplexNumber output = multiply(z2.conjugate());
double div = Math.pow(z2.mod(),2);
return new ComplexNumber(output.real/div,output.imaginary/div);
}
public double mod() {
return Math.sqrt(Math.pow(this.real,2) + Math.pow(this.imaginary,2));
}
@Override
public String toString() {
String re = this.real + "";
String im;
if (this.imaginary < 0) im = this.imaginary+"i";
else im = "+"+this.imaginary+"i";
return re + im;
}
}
Next we have to create two tensors holding some complex numbers.
Let's just initialize them for 2D tensors and let them be points
which are also the indices of the tensors.
Tsr<ComplexNumber> a = Tsr.of(ComplexNumber.class)
withShape(3, 2)
andWhere( ( int i, int[] idx ) -> new ComplexNumber( idx[0], idx[1] ) );
Tsr<ComplexNumber> b = Tsr.of(ComplexNumber.class)
.withShape(3, 2)
.andWhere( ( int i, int[] idx ) -> new ComplexNumber( idx[1], idx[0] ) );
And as expected, when doing calculations on these two tensors then this will translate to elementwise operation calls and new tensors containing the results!
assert a.toString().equals("(3x2):[0.0+0.0i, 0.0+1.0i, 1.0+0.0i, 1.0+1.0i, 2.0+0.0i, 2.0+1.0i]");
assert b.toString().equals("(3x2):[0.0+0.0i, 1.0+0.0i, 0.0+1.0i, 1.0+1.0i, 0.0+2.0i, 1.0+2.0i]");
assert a.plus(b).toString().equals("(3x2):[0.0+0.0i, 1.0+1.0i, 1.0+1.0i, 2.0+2.0i, 2.0+2.0i, 3.0+3.0i]");
assert a.minus(b).toString().equals( "(3x2):[0.0+0.0i, -1.0+1.0i, 1.0-1.0i, 0.0+0.0i, 2.0-2.0i, 1.0-1.0i]");
assert a.multiply(b).toString().equals("(3x2):[0.0+0.0i, 0.0+1.0i, 0.0+1.0i, 0.0+2.0i, 0.0+4.0i, 0.0+5.0i]");
This feature currently only work for elementwise operations.
In future versions linear operations will be supported as well.
One important note that has to be kept in mind when using this feature
is that is substantially slower than operations in conventional (primitive)
data types.