All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jscl.math.Matrix Maven / Gradle / Ivy

There is a newer version: 1.0.11
Show newest version
package jscl.math;

import jscl.math.function.Conjugate;
import jscl.math.function.Constant;
import jscl.math.function.Fraction;
import jscl.math.function.trigonometric.Cos;
import jscl.math.function.trigonometric.Sin;
import jscl.mathml.MathML;
import jscl.util.ArrayComparator;

import javax.annotation.Nonnull;
import java.util.HashSet;
import java.util.Set;

public class Matrix extends Generic {

	protected final Generic elements[][];
	protected final int rows, cols;

	public Matrix(Generic elements[][]) {
		this.elements = elements;
		rows = elements.length;
		cols = elements.length > 0 ? elements[0].length : 0;
	}

	public Generic[][] elements() {
		return elements;
	}

	public Matrix add(Matrix matrix) {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].add(matrix.elements[i][j]);
			}
		}
		return m;
	}

	@Nonnull
	public Generic add(@Nonnull Generic that) {
		if (that instanceof Matrix) {
			return add((Matrix) that);
		} else {
			return add(valueOf(that));
		}
	}

	public Matrix subtract(Matrix matrix) {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].subtract(matrix.elements[i][j]);
			}
		}
		return m;
	}

	@Nonnull
	public Generic subtract(@Nonnull Generic that) {
		if (that instanceof Matrix) {
			return subtract((Matrix) that);
		} else {
			return subtract(valueOf(that));
		}
	}

	public static boolean isMatrixProduct(@Nonnull Generic a, @Nonnull Generic b) {
		return (a instanceof Matrix && b instanceof Matrix) ||
				(a instanceof Matrix && b instanceof JsclVector) ||
				(a instanceof JsclVector && b instanceof Matrix);
	}

	public Matrix multiply(Matrix matrix) {
		if (cols != matrix.rows) {
			throw new ArithmeticException("Unable to multiply matrix by matrix: number of columns of left matrix doesn't match number of rows of right matrix!");
		}
		Matrix m = (Matrix) newInstance(new Generic[rows][matrix.cols]);
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < matrix.cols; j++) {
				m.elements[i][j] = JsclInteger.valueOf(0);
				for (int k = 0; k < cols; k++) {
					m.elements[i][j] = m.elements[i][j].add(elements[i][k].multiply(matrix.elements[k][j]));
				}
			}
		}
		return m;
	}

	@Nonnull
	public Generic multiply(@Nonnull Generic that) {
		if (that instanceof Matrix) {
			return multiply((Matrix) that);
		} else if (that instanceof JsclVector) {
			JsclVector v = (JsclVector) ((JsclVector) that).newInstance(new Generic[rows]);
			JsclVector v2 = (JsclVector) that;
			if (cols != v2.rows) {
				throw new ArithmeticException("Unable to multiply matrix by vector: number of matrix columns doesn't match number of vector rows!");
			}
			for (int i = 0; i < rows; i++) {
				v.elements[i] = JsclInteger.valueOf(0);
				for (int k = 0; k < cols; k++) {
					v.elements[i] = v.elements[i].add(elements[i][k].multiply(v2.elements[k]));
				}
			}
			return v;
		} else {
			Matrix m = (Matrix) newInstance();
			for (int i = 0; i < rows; i++) {
				for (int j = 0; j < cols; j++) {
					m.elements[i][j] = elements[i][j].multiply(that);
				}
			}
			return m;
		}
	}

	@Nonnull
	public Generic divide(@Nonnull Generic that) throws NotDivisibleException {
		if (that instanceof Matrix) {
			return multiply(that.inverse());
		} else if (that instanceof JsclVector) {
			throw new ArithmeticException("Unable to divide matrix by vector: matrix could not be divided by vector!");
		} else {
			Matrix m = (Matrix) newInstance();
			for (int i = 0; i < rows; i++) {
				for (int j = 0; j < cols; j++) {
					try {
						m.elements[i][j] = elements[i][j].divide(that);
					} catch (NotDivisibleException e) {
						m.elements[i][j] = new Fraction(elements[i][j], that).selfExpand();
					}
				}
			}
			return m;
		}
	}

	public Generic gcd(@Nonnull Generic generic) {
		return null;
	}

	@Nonnull
	public Generic gcd() {
		return null;
	}

	public Generic negate() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].negate();
			}
		}
		return m;
	}

	public int signum() {
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				int c = elements[i][j].signum();
				if (c < 0) return -1;
				else if (c > 0) return 1;
			}
		}
		return 0;
	}

	public int degree() {
		return 0;
	}

	public Generic antiDerivative(@Nonnull Variable variable) throws NotIntegrableException {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].antiDerivative(variable);
			}
		}
		return m;
	}

	public Generic derivative(@Nonnull Variable variable) {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].derivative(variable);
			}
		}
		return m;
	}

	public Generic substitute(@Nonnull Variable variable, Generic generic) {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].substitute(variable, generic);
			}
		}
		return m;
	}

	public Generic expand() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].expand();
			}
		}
		return m;
	}

	public Generic factorize() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].factorize();
			}
		}
		return m;
	}

	public Generic elementary() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].elementary();
			}
		}
		return m;
	}

	public Generic simplify() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = elements[i][j].simplify();
			}
		}
		return m;
	}

	public Generic numeric() {
		return new NumericWrapper(this);
	}

	public Generic valueOf(Generic generic) {
		if (generic instanceof Matrix || generic instanceof JsclVector) {
			throw new ArithmeticException("Unable to create matrix: matrix of vectors and matrix of matrices are forbidden");
		} else {
			Matrix m = (Matrix) identity(rows, cols).multiply(generic);
			return newInstance(m.elements);
		}
	}

	public Generic[] sumValue() {
		return new Generic[]{this};
	}

	public Generic[] productValue() throws NotProductException {
		return new Generic[]{this};
	}

	public Power powerValue() throws NotPowerException {
		return new Power(this, 1);
	}

	public Expression expressionValue() throws NotExpressionException {
		throw new NotExpressionException();
	}

	public JsclInteger integerValue() throws NotIntegerException {
		throw new NotIntegerException();
	}

	@Override
	public boolean isInteger() {
		return false;
	}

	public Variable variableValue() throws NotVariableException {
		throw new NotVariableException();
	}

	public Variable[] variables() {
		return null;
	}

	public boolean isPolynomial(@Nonnull Variable variable) {
		return false;
	}

	public boolean isConstant(@Nonnull Variable variable) {
		return false;
	}

	public Generic[] vectors() {
		JsclVector v[] = new JsclVector[rows];
		for (int i = 0; i < rows; i++) {
			v[i] = new JsclVector(new Generic[cols]);
			for (int j = 0; j < cols; j++) {
				v[i].elements[j] = elements[i][j];
			}
		}
		return v;
	}

	public Generic tensorProduct(Matrix matrix) {
		Matrix m = (Matrix) newInstance(new Generic[rows * matrix.rows][cols * matrix.cols]);
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				for (int k = 0; k < matrix.rows; k++) {
					for (int l = 0; l < matrix.cols; l++) {
						m.elements[i * matrix.rows + k][j * matrix.cols + l] = elements[i][j].multiply(matrix.elements[k][l]);
					}
				}
			}
		}
		return m;
	}

	public Matrix transpose() {
		Matrix m = (Matrix) newInstance(new Generic[cols][rows]);
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[j][i] = elements[i][j];
			}
		}
		return m;
	}

	public Generic trace() {
		Generic s = JsclInteger.valueOf(0);
		for (int i = 0; i < rows; i++) {
			s = s.add(elements[i][i]);
		}
		return s;
	}

	public Generic inverse() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < rows; j++) {
				m.elements[i][j] = inverseElement(i, j);
			}
		}
		return m.transpose().divide(determinant());
	}

	Generic inverseElement(int k, int l) {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < rows; j++) {
				m.elements[i][j] = i == k ? JsclInteger.valueOf(j == l ? 1 : 0) : elements[i][j];
			}
		}
		return m.determinant();
	}

	public Generic determinant() {
		if (rows > 1) {
			Generic a = JsclInteger.valueOf(0);
			for (int i = 0; i < rows; i++) {
				if (elements[i][0].signum() == 0) ;
				else {
					Matrix m = (Matrix) newInstance(new Generic[rows - 1][rows - 1]);
					for (int j = 0; j < rows - 1; j++) {
						for (int k = 0; k < rows - 1; k++) m.elements[j][k] = elements[j < i ? j : j + 1][k + 1];
					}
					if (i % 2 == 0) a = a.add(elements[i][0].multiply(m.determinant()));
					else a = a.subtract(elements[i][0].multiply(m.determinant()));
				}
			}
			return a;
		} else if (rows > 0) return elements[0][0];
		else return JsclInteger.valueOf(0);
	}

	public Generic conjugate() {
		Matrix m = (Matrix) newInstance();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				m.elements[i][j] = new Conjugate(elements[i][j]).selfExpand();
			}
		}
		return m;
	}

	public int compareTo(Matrix matrix) {
		return ArrayComparator.comparator.compare(vectors(), matrix.vectors());
	}

	public int compareTo(Generic generic) {
		if (generic instanceof Matrix) {
			return compareTo((Matrix) generic);
		} else {
			return compareTo(valueOf(generic));
		}
	}

	public static Matrix identity(int dimension) {
		return identity(dimension, dimension);
	}

	public static Matrix identity(int n, int p) {
		Matrix m = new Matrix(new Generic[n][p]);
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < p; j++) {
				if (i == j) {
					m.elements[i][j] = JsclInteger.valueOf(1);
				} else {
					m.elements[i][j] = JsclInteger.valueOf(0);
				}
			}
		}
		return m;
	}

	public static Matrix frame(JsclVector vector[]) {
		Matrix m = new Matrix(new Generic[vector.length > 0 ? vector[0].rows : 0][vector.length]);
		for (int i = 0; i < m.rows; i++) {
			for (int j = 0; j < m.cols; j++) {
				m.elements[i][j] = vector[j].elements[i];
			}
		}
		return m;
	}

	public static Matrix rotation(int dimension, int plane, Generic angle) {
		return rotation(dimension, plane, 2, angle);
	}

	public static Matrix rotation(int dimension, int axis1, int axis2, Generic angle) {
		Matrix m = new Matrix(new Generic[dimension][dimension]);
		for (int i = 0; i < m.rows; i++) {
			for (int j = 0; j < m.cols; j++) {
				if (i == axis1 && j == axis1) {
					m.elements[i][j] = new Cos(angle).selfExpand();
				} else if (i == axis1 && j == axis2) {
					m.elements[i][j] = new Sin(angle).selfExpand().negate();
				} else if (i == axis2 && j == axis1) {
					m.elements[i][j] = new Sin(angle).selfExpand();
				} else if (i == axis2 && j == axis2) {
					m.elements[i][j] = new Cos(angle).selfExpand();
				} else if (i == j) {
					m.elements[i][j] = JsclInteger.valueOf(1);
				} else {
					m.elements[i][j] = JsclInteger.valueOf(0);
				}
			}
		}
		return m;
	}

	public String toString() {
		final StringBuilder result = new StringBuilder();

		result.append("[");
		for (int i = 0; i < rows; i++) {
			result.append("[");

			for (int j = 0; j < cols; j++) {
				result.append(elements[i][j]).append(j < cols - 1 ? ", " : "");
			}

			result.append("]").append(i < rows - 1 ? ",\n" : "");
		}

		result.append("]");

		return result.toString();
	}

	public String toJava() {
		final StringBuilder result = new StringBuilder();

		result.append("new Matrix(new Numeric[][] {");

		for (int i = 0; i < rows; i++) {
			result.append("{");
			for (int j = 0; j < cols; j++) {
				result.append(elements[i][j].toJava()).append(j < cols - 1 ? ", " : "");
			}
			result.append("}").append(i < rows - 1 ? ", " : "");
		}

		result.append("})");

		return result.toString();
	}

	public void toMathML(MathML element, Object data) {
		int exponent = data instanceof Integer ? (Integer) data : 1;
		if (exponent == 1) bodyToMathML(element);
		else {
			MathML e1 = element.element("msup");
			bodyToMathML(e1);
			MathML e2 = element.element("mn");
			e2.appendChild(element.text(String.valueOf(exponent)));
			e1.appendChild(e2);
			element.appendChild(e1);
		}
	}

	@Nonnull
	@Override
	public Set getConstants() {
		final Set result = new HashSet();

		for (Generic[] element : elements) {
			for (Generic generic : element) {
				result.addAll(generic.getConstants());
			}
		}

		return result;
	}

	protected void bodyToMathML(MathML e0) {
		MathML e1 = e0.element("mfenced");
		MathML e2 = e0.element("mtable");
		for (int i = 0; i < rows; i++) {
			MathML e3 = e0.element("mtr");
			for (int j = 0; j < cols; j++) {
				MathML e4 = e0.element("mtd");
				elements[i][j].toMathML(e4, null);
				e3.appendChild(e4);
			}
			e2.appendChild(e3);
		}
		e1.appendChild(e2);
		e0.appendChild(e1);
	}

	@Nonnull
	protected Generic newInstance() {
		return newInstance(new Generic[rows][cols]);
	}

	@Nonnull
	protected static Generic newInstance(Generic element[][]) {
		return new Matrix(element);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy