/* * Copyright 2011-2013, by Vladimir Kostyukov and Contributors. * * This file is part of la4j project (http://la4j.org) * * Licensed 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. * * Contributor(s): - * */ package org.la4j.matrix.dense; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; import org.la4j.Matrices; import org.la4j.Matrix; import org.la4j.matrix.DenseMatrix; import org.la4j.matrix.MatrixFactory; import org.la4j.Vector; import org.la4j.vector.dense.BasicVector; public class Basic2DMatrix extends DenseMatrix { private static final byte MATRIX_TAG = (byte) 0x10; private double[][] self; public Basic2DMatrix() { this(0, 0); } public Basic2DMatrix(int rows, int columns) { this(new double[rows][columns]); } public Basic2DMatrix(double[][] array) { super(array.length, array.length == 0 ? 0: array[0].length); this.self = array; } /** * Creates a zero {@link Basic2DMatrix} of the given shape: * {@code rows} x {@code columns}. */ public static Basic2DMatrix zero(int rows, int columns) { return new Basic2DMatrix(rows, columns); } /** * Creates a constant {@link Basic2DMatrix} of the given shape and {@code value}. */ public static Basic2DMatrix constant(int rows, int columns, double constant) { double[][] array = new double[rows][columns]; for (int i = 0; i < rows; i++) { Arrays.fill(array[i], constant); } return new Basic2DMatrix(array); } /** * Creates a diagonal {@link Basic2DMatrix} of the given {@code size} whose * diagonal elements are equal to {@code diagonal}. */ public static Basic2DMatrix diagonal(int size, double diagonal) { double[][] array = new double[size][size]; for (int i = 0; i < size; i++) { array[i][i] = diagonal; } return new Basic2DMatrix(array); } /** * Creates an unit {@link Basic2DMatrix} of the given shape: * {@code rows} x {@code columns}. */ public static Basic2DMatrix unit(int rows, int columns) { return Basic2DMatrix.constant(rows, columns, 1.0); } /** * Creates an identity {@link Basic2DMatrix} of the given {@code size}. */ public static Basic2DMatrix identity(int size) { return Basic2DMatrix.diagonal(size, 1.0); } /** * Creates a random {@link Basic2DMatrix} of the given shape: * {@code rows} x {@code columns}. */ public static Basic2DMatrix random(int rows, int columns, Random random) { double[][] array = new double[rows][columns]; for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { array[i][j] = random.nextDouble(); } } return new Basic2DMatrix(array); } /** * Creates a random symmetric {@link Basic2DMatrix} of the given {@code size}. */ public static Basic2DMatrix randomSymmetric(int size, Random random) { double[][] array = new double[size][size]; for (int i = 0; i < size; i++) { for (int j = i; j < size; j++) { double value = random.nextDouble(); array[i][j] = value; array[j][i] = value; } } return new Basic2DMatrix(array); } /** * Creates a {@link Basic2DMatrix} of the given 1D {@code array} with * copying the underlying array. */ public static Basic2DMatrix from1DArray(int rows, int columns, double[] array) { double[][] array2D = new double[rows][columns]; for (int i = 0; i < rows; i++) { System.arraycopy(array, i * columns, array2D[i], 0, columns); } return new Basic2DMatrix(array2D); } /** * Creates a {@link Basic2DMatrix} of the given 2D {@code array} w/o * copying the underlying array. */ public static Basic2DMatrix from2DArray(double[][] array) { return new Basic2DMatrix(array); } /** * Creates a block {@link Basic2DMatrix} of the given blocks {@code a}, * {@code b}, {@code c} and {@code d}. */ public static Basic2DMatrix block(Matrix a, Matrix b, Matrix c, Matrix d) { if ((a.rows() != b.rows()) || (a.columns() != c.columns()) || (c.rows() != d.rows()) || (b.columns() != d.columns())) { throw new IllegalArgumentException("Sides of blocks are incompatible!"); } int rows = a.rows() + c.rows(); int columns = a.columns() + b.columns(); double[][] array = new double[rows][columns]; for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if ((i < a.rows()) && (j < a.columns())) { array[i][j] = a.get(i, j); } if ((i < a.rows()) && (j > a.columns())) { array[i][j] = b.get(i, j); } if ((i > a.rows()) && (j < a.columns())) { array[i][j] = c.get(i, j); } if ((i > a.rows()) && (j > a.columns())) { array[i][j] = d.get(i, j); } } } return new Basic2DMatrix(array); } /** * Decodes {@link Basic2DMatrix} from the given byte {@code array}. * * @param array the byte array representing a matrix * * @return a decoded matrix */ public static Basic2DMatrix fromBinary(byte[] array) { ByteBuffer buffer = ByteBuffer.wrap(array); if (buffer.get() != MATRIX_TAG) { throw new IllegalArgumentException("Can not decode Basic2DMatrix from the given byte array."); } int rows = buffer.getInt(); int columns = buffer.getInt(); double[][] values = new double[rows][columns]; for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { values[i][j] = buffer.getDouble(); } } return new Basic2DMatrix(values); } /** * Parses {@link Basic2DMatrix} from the given CSV string. * * @param csv the CSV string representing a matrix * * @return a parsed matrix */ public static Basic2DMatrix fromCSV(String csv) { return Matrix.fromCSV(csv).to(Matrices.BASIC_2D); } /** * Parses {@link Basic2DMatrix} from the given Matrix Market string. * * @param mm the string in Matrix Market format * * @return a parsed matrix */ public static Basic2DMatrix fromMatrixMarket(String mm) { return Matrix.fromMatrixMarket(mm).to(Matrices.BASIC_2D); } @Override public double get(int i, int j) { return self[i][j]; } @Override public void set(int i, int j, double value) { self[i][j] = value; } @Override public void setAll(double value) { for (int i = 0; i < rows; i++) { Arrays.fill(self[i], value); } } @Override public void swapRows(int i, int j) { if (i != j) { double[] tmp = self[i]; self[i] = self[j]; self[j] = tmp; } } @Override public void swapColumns(int i, int j) { if (i != j) { for (int ii = 0; ii < rows; ii++) { double tmp = self[ii][i]; self[ii][i] = self[ii][j]; self[ii][j] = tmp; } } } @Override public Vector getRow(int i) { double[] result = new double[columns]; System.arraycopy(self[i], 0, result, 0, columns); return new BasicVector(result); } @Override public Matrix copyOfShape(int rows, int columns) { ensureDimensionsAreCorrect(rows, columns); double[][] $self = new double[rows][columns]; for (int i = 0; i < Math.min(this.rows, rows); i++) { System.arraycopy(self[i], 0, $self[i], 0, Math.min(this.columns, columns)); } return new Basic2DMatrix($self); } @Override public double[][] toArray() { double[][] result = new double[rows][columns]; for (int i = 0; i < rows; i++) { System.arraycopy(self[i], 0, result[i], 0, columns); } return result; } @Override public <T extends Matrix> T to(MatrixFactory<T> factory) { if (factory.outputClass == Basic2DMatrix.class) { return factory.outputClass.cast(this); } return super.to(factory); } @Override public Matrix blankOfShape(int rows, int columns) { return Basic2DMatrix.zero(rows, columns); } @Override public byte[] toBinary() { int size = 1 + // 1 byte: class tag 4 + // 4 bytes: rows 4 + // 4 bytes: columns (8 * rows * columns); // 8 * rows * columns bytes: values ByteBuffer buffer = ByteBuffer.allocate(size); buffer.put(MATRIX_TAG); buffer.putInt(rows); buffer.putInt(columns); for (int i = 0; i < rows; i++) { for (double value : self[i]) { buffer.putDouble(value); } } return buffer.array(); } }