Java
Source code for the example .class and .jar libraries.
Example .class
file
The following file is compiled to Trig.class
byte code.
Trig.java
/*
* Compile with JDK 6 for maximal compatibility with Py4J
*
* javac Trig.java
*
*/
public class Trig {
/** Returns the trigonometric cosine of an angle. */
static public double cos(double x) {
return Math.cos(x);
}
/** Returns the hyperbolic cosine of a value. */
static public double cosh(double x) {
return Math.cosh(x);
}
/** Returns the arc cosine of a value, [0.0, pi]. */
static public double acos(double x) {
return Math.acos(x);
}
/** Returns the trigonometric sine of an angle. */
static public double sin(double x) {
return Math.sin(x);
}
/** Returns the hyperbolic sine of a value. */
static public double sinh(double x) {
return Math.sinh(x);
}
/** Returns the arc sine of a value, [-pi/2, pi/2]. */
static public double asin(double x) {
return Math.asin(x);
}
/** Returns the trigonometric tangent of an angle. */
static public double tan(double x) {
return Math.tan(x);
}
/** Returns the hyperbolic tangent of a value. */
static public double tanh(double x) {
return Math.tanh(x);
}
/** Returns the arc tangent of a value; [-pi/2, pi/2]. */
static public double atan(double x) {
return Math.atan(x);
}
/**
* Returns the angle theta from the conversion of rectangular coordinates
* (x, y) to polar coordinates (r, theta).
*/
static public double atan2(double y, double x) {
return Math.atan2(y, x);
}
}
Example .jar
file
The following classes are included in the nz.msl.examples
package in java_lib.jar
.
MathUtils.java
package nz.msl.examples;
public class MathUtils {
/** Generate a random number between [0, 1) */
static public double random() {
return Math.random();
}
/** Calculate the square root of {@code x} */
static public double sqrt(double x) {
return Math.sqrt(x);
}
}
Matrix.java
package nz.msl.examples;
import java.util.Random;
public class Matrix {
/** The matrix, M */
private double[][] m;
/** Lower-triangular matrix representation, M=LU, in LU Decomposition */
private Matrix L;
/** Upper-triangular matrix representation, M=LU, in LU Decomposition */
private Matrix U;
/** A NxM orthogonal matrix representation, M=QR, in QR Decomposition */
private Matrix Q;
/** Upper-triangular matrix representation, M=QR, in QR Decomposition */
private Matrix R;
/** When calculating the inverse we calculate the LU matrices once */
static private boolean calculatingInverse = false;
/*
*
* Define the constructors.
*
*
*/
/** Create a Matrix that is a copy of another Matrix. */
public Matrix(Matrix m) {
this.m = new double[m.getNumberOfRows()][m.getNumberOfColumns()];
for (int i=0; i<m.getNumberOfRows(); i++)
for (int j=0; j<m.getNumberOfColumns(); j++)
this.m[i][j] = m.getValue(i,j);
}
/** Create a {@code n} x {@code n} identity Matrix */
public Matrix(int n) {
m = new double[n][n];
for (int i=0; i<n; i++)
m[i][i] = 1.0;
}
/** Create a {@code rows} x {@code cols} Matrix filled with zeros. */
public Matrix(int rows, int cols) {
m = new double[rows][cols];
}
/** Create a {@code rows} x {@code cols} Matrix filled with a value. */
public Matrix(int rows, int cols, double value) {
m = new double[rows][cols];
for (int i=0; i<rows; i++)
for (int j=0; j<cols; j++)
m[i][j] = value;
}
/**
* Create a {@code rows} x {@code cols} Matrix that is filled with
* uniformly-distributed random values that are within the range
* {@code min} to {@code max}.
*/
public Matrix(int rows, int cols, double min, double max) {
Random rand = new Random();
m = new double[rows][cols];
for (int i=0; i<rows; i++)
for (int j=0; j<cols; j++)
m[i][j] = (max-min)*rand.nextDouble()+min;
}
/** Create a Matrix from {@code m}. */
public Matrix(Double[][] m) {
this.m = new double[m.length][m[0].length];
for (int i=0; i<m.length; i++)
for (int j=0; j<m[0].length; j++)
this.m[i][j] = m[i][j];
}
/** Create a Matrix from a vector. */
public Matrix(Double[] vector) {
m = new double[1][vector.length];
for (int i=0; i<vector.length; i++)
m[0][i] = vector[i];
}
/*
*
* The public static methods.
*
*
*/
/** Returns the product of two Matrices as a new Matrix, C=AB. */
public static Matrix multiply(Matrix a, Matrix b) {
if (a.getNumberOfColumns() != b.getNumberOfRows()) {
throw new IllegalArgumentException(
String.format("ERROR! Cannot multiply a %dx%d matrix "
+ "with a %dx%d matrix",
a.getNumberOfRows(), a.getNumberOfColumns(),
b.getNumberOfRows(), b.getNumberOfColumns()));
} else {
Matrix c = new Matrix(a.getNumberOfRows(), b.getNumberOfColumns());
double sum = 0.0;
for (int i = 0; i < a.getNumberOfRows() ; i++) {
for (int j = 0; j < b.getNumberOfColumns(); j++) {
for (int k = 0 ; k < b.getNumberOfRows() ; k++) {
sum += a.getValue(i,k)*b.getValue(k,j);
}
c.setValue(i, j, sum);
sum = 0.0;
}
}
return c;
}
}
/**
* Solves {@code b = Ax} for {@code x}.
*
* @param A - the coefficient matrix
* @param b - the expected values
* @return x - the solution to the system of equations
*/
public static Matrix solve(Matrix A, Matrix b) {
// ensure that 'b' is a column vector
if (b.getNumberOfColumns() > 1) b = b.transpose();
// ensure that 'A' and 'b' have the correct dimensions
if (b.getNumberOfRows() != A.getNumberOfRows()) {
throw new IllegalArgumentException(
String.format("ERROR! Dimension mismatch when solving the "
+ "system of equations using b=Ax, b has dimension "
+ " %dx%d and A is %dx%d.", b.getNumberOfRows(),
b.getNumberOfColumns(), A.getNumberOfRows(),
A.getNumberOfColumns()));
}
// if A is an under-determined system of equations then use the
// matrix-multiplication expression to solve for x
if (A.getNumberOfRows() < A.getNumberOfColumns()) {
Matrix At = A.transpose();
return Matrix.multiply(Matrix.multiply(At,
Matrix.multiply(A, At).getInverse() ), b);
}
// If A is a square matrix then use LU Decomposition, if it is an
// over-determined system of equations then use QR Decomposition
Double[] x = new Double[A.getNumberOfColumns()];
if (A.isSquare()) {
// when using 'solve' to calculate the inverse of a matrix we
// only need to generate the LU Decomposition matrices once
if (!calculatingInverse) A.makeLU();
// solve Ly=b for y using forward substitution
double[] y = new double[b.getNumberOfRows()];
y[0] = b.getValue(0,0);
for (int i=1; i<y.length; i++) {
y[i] = b.getValue(i,0);
for (int j=0; j<i; j++)
y[i] -= A.getL().getValue(i,j)*y[j];
}
// solve Ux=y for x using backward substitution
for (int i=x.length-1; i>-1; i--) {
x[i] = y[i];
for (int j=i+1; j<x.length; j++)
x[i] -= A.getU().getValue(i,j)*x[j];
x[i] /= A.getU().getValue(i,i);
}
} else {
A.makeQR();
Matrix d = Matrix.multiply(A.getQ().transpose(), b);
// solve Rx=d for x using backward substitution
for (int i=x.length-1; i>-1; i--) {
x[i] = d.getValue(i, 0);
for (int j=i+1; j<x.length; j++)
x[i] -= A.getR().getValue(i,j)*x[j];
x[i] /= A.getR().getValue(i,i);
}
}
return new Matrix(x).transpose();
}
/*
*
* The public methods.
*
*
*/
/** Returns the primitive data of the Matrix. */
public double[][] primitive() {
return m;
}
/** Convert the Matrix to a string. */
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i=0; i<m.length; i++) {
for (int j=0; j<m[0].length; j++) {
sb.append(String.format("%+.6e\t", m[i][j]));
}
sb.append("\n");
}
return sb.toString();
}
/** Returns the number of rows in the Matrix. */
public int getNumberOfRows() {
return m.length;
}
/** Returns the number of columns in the Matrix. */
public int getNumberOfColumns() {
try {
return m[0].length;
} catch (ArrayIndexOutOfBoundsException e) {
return 0;
}
}
/** Returns the value at {@code row} and {@code col}. */
public double getValue(int row, int col) {
return m[row][col];
}
/** Sets the value at {@code row} and {@code col} to be {@code value}. */
public void setValue(int row, int col, double value) {
m[row][col] = value;
}
/** Returns the transpose of the Matrix. */
public Matrix transpose() {
Matrix mt = new Matrix(m[0].length, m.length);
for (int i=0; i<m.length; i++)
for (int j=0; j<m[0].length; j++)
mt.setValue(j, i, m[i][j]);
return mt;
}
/** Returns whether the Matrix is a square Matrix. */
public boolean isSquare() {
return m.length == m[0].length;
}
/** Returns the determinant of the Matrix. */
public double getDeterminant() {
if (isSquare()) {
makeLU();
double det = 1.0;
for (int i=0; i<m.length; i++)
det *= U.getValue(i,i);
// 's' is the number of row and column exchanges in LU Decomposition
// but we are currently not using pivoting
int s = 0;
return Math.pow(-1.0, s)*det;
} else {
return Double.NaN;
}
}
/** Returns the lower-triangular Matrix, L, from a LU Decomposition */
public Matrix getL() {
if (L==null) makeLU();
return L;
}
/** Returns the upper-triangular Matrix, U, from a LU Decomposition */
public Matrix getU() {
if (U==null) makeLU();
return U;
}
/** Returns the orthogonal Matrix, Q, from a QR Decomposition */
public Matrix getQ() {
if (Q==null) makeQR();
return Q;
}
/** Returns the upper-triangular Matrix, R, from a QR Decomposition */
public Matrix getR() {
if (R==null) makeQR();
return R;
}
/** Returns the inverse of the Matrix, if it exists. */
public Matrix getInverse() {
if (isSquare()) {
Matrix inv = new Matrix(m.length);
Matrix bb = new Matrix(m.length);
for (int i=0; i<m.length; i++) {
inv.setColumn(i, Matrix.solve(this, bb.getColumn(i)));
calculatingInverse = true;
}
calculatingInverse = false;
return inv;
} else {
throw new IllegalArgumentException(
String.format("ERROR! Cannot calculate the inverse of a "
+ "%dx%d matrix, it must be a square Matrix",
m.length, m[0].length));
}
}
/*
*
* Private methods.
*
*
*/
/**
* Create the Lower, L, and Upper, U, triangular matrices, such that M=LU.
* Does not use pivoting.
*/
private void makeLU() {
L = new Matrix(m.length); // create an identity matrix
U = new Matrix(this); // copy the values of this matrix
double val;
for (int k=0; k<m[0].length; k++) {
for (int i=k+1; i<m.length; i++) {
val = U.getValue(i,k)/U.getValue(k,k);
L.setValue(i, k, val);
for (int j=k; j<m[0].length; j++)
U.setValue(i, j, U.getValue(i,j)-val*U.getValue(k,j));
}
}
}
/**
* Computes the QR Factorization matrices using a modified
* Gram–Schmidt process.<p>
*
* @see https://people.inf.ethz.ch/gander/papers/qrneu.pdf
*/
private void makeQR() {
Q = new Matrix(m.length, m[0].length);
R = new Matrix(m[0].length, m[0].length);
Matrix A = new Matrix(this);
double s;
for (int k=0; k<m[0].length; k++) {
s = 0.0;
for (int j=0; j<m.length; j++)
s += Math.pow(A.getValue(j, k), 2);
s = Math.sqrt(s);
R.setValue(k, k, s);
for (int j=0; j<m.length; j++)
Q.setValue(j, k, A.getValue(j, k)/s);
for (int i=k+1; i<m[0].length; i++) {
s = 0.0;
for (int j=0; j<m.length; j++)
s += A.getValue(j, i)*Q.getValue(j, k);
R.setValue(k, i, s);
for (int j=0; j<m.length; j++)
A.setValue(j, i, A.getValue(j,i)-R.getValue(k,i)*Q.getValue(j,k));
}
}
}
/** Returns a copy of the specified column. */
private Matrix getColumn(int column) {
if (column < m[0].length) {
Matrix c = new Matrix(m.length, 1);
for (int i=0; i<m.length; i++)
c.setValue(i, 0, m[i][column]);
return c;
} else {
throw new IllegalArgumentException(
String.format("ERROR! Cannot get column %d in the Matrix "
+ "since it is > the number of columns in the "
+ "Matrix, %d.", column, m[0].length));
}
}
/**
* Replace the values in the specified column of the matrix to the values in
* {@code vector}.
*
* The {@code vector} must be a 1D vector, can have dimension 1xN or Nx1.
*/
private void setColumn(int column, Matrix vector) {
// make sure that 'vector' is either a 1xN or Nx1 vector and not a NxM Matrix
if ( (vector.getNumberOfColumns() != 1) && (vector.getNumberOfRows() != 1) ) {
throw new IllegalArgumentException(
String.format("ERROR! Require a 1D vector to replace the values "
+ "in a column of a matrix. Got a %dx%d vector.",
vector.getNumberOfRows(), vector.getNumberOfColumns()));
}
// make sure we have a column vector
if (vector.getNumberOfColumns() != 1) {
vector = vector.transpose();
}
// make sure the 'vector' has the correct length
if (vector.getNumberOfRows() != m.length) {
throw new IllegalArgumentException(
String.format("ERROR! Cannot replace a Matrix column of length "
+ "%d, with a column vector of length %d.",
m.length, vector.getNumberOfRows()));
}
// make sure the column is valid
if (column >= m[0].length) {
throw new IllegalArgumentException(
String.format("ERROR! Cannot replace column %d in the Matrix "
+ "since it is > the number of columns in the matrix.", column));
}
for (int i=0; i<m.length; i++)
m[i][column] = vector.getValue(i,0);
}
}