FieldDenseMatrix.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.math4.legacy.field.linalg;
- import java.util.Arrays;
- import java.util.List;
- import java.util.ArrayList;
- import org.apache.commons.numbers.field.Field;
- import org.apache.commons.math4.legacy.linear.AnyMatrix;
- /**
- * Square matrix whose elements define a {@link Field}.
- *
- * @param <T> Type of the field elements.
- *
- * @since 4.0
- */
- public final class FieldDenseMatrix<T>
- implements AnyMatrix {
- /** Field. */
- private final Field<T> field;
- /** Number of rows. */
- private final int rows;
- /** Number of columns. */
- private final int columns;
- /**
- * Data storage (in row-major order).
- *
- * <p>Note: This is an Object[] that has been cast to T[] for convenience. It should not be
- * exposed to avoid heap pollution. It is expected all entries stored in the array are
- * instances of T.
- */
- private final T[] data;
- /**
- * @param f Field.
- * @param r Number of rows.
- * @param c Number of columns.
- * @throws IllegalArgumentException if {@code r <= 0} or {@code c <= 0}.
- */
- @SuppressWarnings("unchecked")
- private FieldDenseMatrix(Field<T> f,
- int r,
- int c) {
- if (r <= 0 ||
- c <= 0) {
- throw new IllegalArgumentException("Negative size");
- }
- field = f;
- rows = r;
- columns = c;
- data = (T[]) new Object[r * c];
- }
- /**
- * Factory method.
- *
- * @param <T> Type of the field elements.
- * @param f Field.
- * @param r Number of rows.
- * @param c Number of columns.
- * @return a new instance.
- * @throws IllegalArgumentException if {@code r <= 0} or {@code c <= 0}.
- */
- public static <T> FieldDenseMatrix<T> create(Field<T> f,
- int r,
- int c) {
- return new FieldDenseMatrix<>(f, r, c);
- }
- /**
- * Factory method.
- *
- * @param <T> Type of the field elements.
- * @param f Field.
- * @param r Number of rows.
- * @param c Number of columns.
- * @return a matrix with elements zet to {@link Field#zero() zero}.
- * @throws IllegalArgumentException if {@code r <= 0} or {@code c <= 0}.
- */
- public static <T> FieldDenseMatrix<T> zero(Field<T> f,
- int r,
- int c) {
- return create(f, r, c).fill(f.zero());
- }
- /**
- * Factory method.
- *
- * @param <T> Type of the field elements.
- * @param f Field.
- * @param n Dimension of the matrix.
- * @throws IllegalArgumentException if {@code n <= 0}.
- * @return the identity matrix.
- */
- public static <T> FieldDenseMatrix<T> identity(Field<T> f,
- int n) {
- final FieldDenseMatrix<T> r = zero(f, n, n);
- for (int i = 0; i < n; i++) {
- r.set(i, i, f.one());
- }
- return r;
- }
- /** {@inheritDoc} */
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- } else {
- if (other instanceof FieldDenseMatrix) {
- final FieldDenseMatrix<?> m = (FieldDenseMatrix<?>) other;
- return field.equals(m.field) &&
- rows == m.rows &&
- columns == m.columns &&
- Arrays.equals(data, m.data);
- } else {
- return false;
- }
- }
- }
- /**
- * Copies this matrix.
- *
- * @return a new instance.
- */
- public FieldDenseMatrix<T> copy() {
- final FieldDenseMatrix<T> r = create(field, rows, columns);
- System.arraycopy(data, 0, r.data, 0, data.length);
- return r;
- }
- /**
- * Transposes this matrix.
- *
- * @return a new instance.
- */
- public FieldDenseMatrix<T> transpose() {
- final FieldDenseMatrix<T> r = create(field, columns, rows);
- for (int i = 0; i < rows; i++) {
- for (int j = 0; j < columns; j++) {
- r.set(j, i, get(i, j));
- }
- }
- return r;
- }
- /** {@inheritDoc} */
- @Override
- public int getRowDimension() {
- return rows;
- }
- /** {@inheritDoc} */
- @Override
- public int getColumnDimension() {
- return columns;
- }
- /**
- * @return the field associated with the matrix entries.
- */
- public Field<T> getField() {
- return field;
- }
- /**
- * Sets all elements to the given value.
- *
- * @param value Value of the elements of the matrix.
- * @return {@code this}.
- */
- public FieldDenseMatrix<T> fill(T value) {
- Arrays.fill(data, value);
- return this;
- }
- /**
- * Gets an element.
- *
- * @param i Row.
- * @param j Column.
- * @return the element at (i, j).
- */
- public T get(int i,
- int j) {
- return data[i * columns + j];
- }
- /**
- * Sets an element.
- *
- * @param i Row.
- * @param j Column.
- * @param value Value.
- */
- public void set(int i,
- int j,
- T value) {
- data[i * columns + j] = value;
- }
- /**
- * Addition.
- *
- * @param other Matrix to add.
- * @return a new instance with the result of the addition.
- * @throws IllegalArgumentException if the dimensions do not match.
- */
- public FieldDenseMatrix<T> add(FieldDenseMatrix<T> other) {
- checkAdd(other);
- final FieldDenseMatrix<T> r = create(field, rows, columns);
- for (int i = 0; i < data.length; i++) {
- r.data[i] = field.add(data[i], other.data[i]);
- }
- return r;
- }
- /**
- * Subtraction.
- *
- * @param other Matrix to subtract.
- * @return a new instance with the result of the subtraction.
- * @throws IllegalArgumentException if the dimensions do not match.
- */
- public FieldDenseMatrix<T> subtract(FieldDenseMatrix<T> other) {
- checkAdd(other);
- final FieldDenseMatrix<T> r = create(field, rows, columns);
- for (int i = 0; i < data.length; i++) {
- r.data[i] = field.subtract(data[i], other.data[i]);
- }
- return r;
- }
- /**
- * Negate.
- *
- * @return a new instance with the opposite matrix.
- */
- public FieldDenseMatrix<T> negate() {
- final FieldDenseMatrix<T> r = create(field, rows, columns);
- for (int i = 0; i < data.length; i++) {
- r.data[i] = field.negate(data[i]);
- }
- return r;
- }
- /**
- * Multiplication.
- *
- * @param other Matrix to multiply with.
- * @return a new instance with the result of the multiplication.
- * @throws IllegalArgumentException if the dimensions do not match.
- */
- public FieldDenseMatrix<T> multiply(FieldDenseMatrix<T> other) {
- checkMultiply(other);
- final FieldDenseMatrix<T> r = zero(field, rows, other.columns);
- for (int i = 0; i < rows; i++) {
- final int o1 = i * columns;
- final int o2 = i * r.columns;
- for (int j = 0; j < other.columns; j++) {
- final int o3 = o2 + j;
- for (int k = 0; k < columns; k++) {
- r.data[o3] = field.add(r.data[o3],
- field.multiply(data[o1 + k],
- other.data[k * other.columns + j]));
- }
- }
- }
- return r;
- }
- /**
- * Multiplies the matrix with itself {@code p} times.
- *
- * @param p Exponent.
- * @return a new instance.
- * @throws IllegalArgumentException if {@code p < 0}.
- */
- public FieldDenseMatrix<T> pow(int p) {
- checkMultiply(this);
- if (p < 0) {
- throw new IllegalArgumentException("Negative exponent: " + p);
- }
- if (p == 0) {
- return identity(field, rows);
- }
- if (p == 1) {
- return copy();
- }
- final int power = p - 1;
- // Only log_2(p) operations are necessary by doing as follows:
- // 5^214 = 5^128 * 5^64 * 5^16 * 5^4 * 5^2
- // The same approach is used for A^p.
- final char[] binary = Integer.toBinaryString(power).toCharArray();
- final ArrayList<Integer> nonZeroPositions = new ArrayList<>();
- for (int i = 0; i < binary.length; i++) {
- if (binary[i] == '1') {
- final int pos = binary.length - i - 1;
- nonZeroPositions.add(pos);
- }
- }
- final List<FieldDenseMatrix<T>> results = new ArrayList<>(binary.length);
- results.add(this);
- for (int i = 1; i < binary.length; i++) {
- final FieldDenseMatrix<T> s = results.get(i - 1);
- final FieldDenseMatrix<T> r = s.multiply(s);
- results.add(r);
- }
- FieldDenseMatrix<T> r = this;
- for (Integer i : nonZeroPositions) {
- r = r.multiply(results.get(i));
- }
- return r;
- }
- /** {@inheritDoc} */
- @Override
- public int hashCode() {
- assert false : "hashCode not designed";
- return 42; // Any arbitrary constant will do.
- }
- }