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

io.jenetics.lattices.matrix.DoubleMatrix2d Maven / Gradle / Ivy

/*
 * Java Lattice Library (lattices-3.0.0.ALPHA1).
 * Copyright (c) 2022-2022 Franz Wilhelmstötter
 *
 * 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.
 *
 * Author:
 *    Franz Wilhelmstötter ([email protected])
 */
package io.jenetics.lattices.matrix;

import static java.util.Objects.requireNonNull;
import static io.jenetics.lattices.NumericalContext.ZERO_EPSILON;

import java.util.function.DoubleUnaryOperator;

import io.jenetics.lattices.NumericalContext;
import io.jenetics.lattices.array.DenseDoubleArray;
import io.jenetics.lattices.array.DoubleArray;
import io.jenetics.lattices.grid.DoubleGrid2d;
import io.jenetics.lattices.grid.Extent1d;
import io.jenetics.lattices.grid.Extent2d;
import io.jenetics.lattices.grid.Factory2d;
import io.jenetics.lattices.grid.Loop2d;
import io.jenetics.lattices.grid.Range2d;
import io.jenetics.lattices.grid.StrideOrder2d;
import io.jenetics.lattices.grid.Structure1d;
import io.jenetics.lattices.grid.Structure2d;

/**
 * Generic class for 2-d matrices holding {@code double} elements. Instances
 * of this class are usually created via a factory.
 * 
{@code
 * final DoubleMatrix2d matrix5x10 = DoubleMatrix2d.DENSE.create(5, 10);
 * }
* * @see #DENSE * * @author Franz Wilhelmstötter * @since 3.0 * @version 3.0 */ public class DoubleMatrix2d extends DoubleGrid2d implements Matrix2d { /** * Factory for creating dense 2-d double matrices. */ public static final Factory2d DENSE = struct -> new DoubleMatrix2d( struct, DenseDoubleArray.ofSize(struct.extent().size()) ); /** * Create a new 2-d matrix with the given {@code structure} and element * {@code array}. * * @param structure the matrix structure * @param array the element array */ public DoubleMatrix2d(final Structure2d structure, final DoubleArray array) { super(structure, array); } /** * Create a new matrix view from the given {@code grid}. * * @param grid the data grid */ public DoubleMatrix2d(final DoubleGrid2d grid) { this(grid.structure(), grid.array()); } @Override public Factory2d factory() { return struct -> new DoubleMatrix2d( struct, array.like(struct.extent().size()) ); } @Override public DoubleMatrix2d view(final Structure2d structure) { return new DoubleMatrix2d(structure, array); } @Override public DoubleMatrix2d copy(final Range2d range) { // Fast copy, if applicable. if (range.row() == 0 && range.col() == 0 && range.height() == rows() && range.width() == cols() && structure.order().equals(new StrideOrder2d(new Extent2d(range)))) { return new DoubleMatrix2d(structure, array.copy()); } else { final var struct = structure.copy(range); final var elems = array.like(range.size()); final var loop = new Loop2d.RowMajor(struct.extent()); loop.forEach((r, c) -> elems.set( struct.order().index(r, c), get(r + range.row(), c + range.col()) ) ); return new DoubleMatrix2d(struct, elems); } } @Override public DoubleMatrix2d transpose() { return new DoubleMatrix2d(structure.transpose(), array); } /* ************************************************************************* * Matrix view methods. * ************************************************************************/ /** * Constructs and returns a view representing the rows of the given * column. The returned view is backed by this matrix, so changes in the * returned view are reflected in this matrix, and vice-versa. * * @param index the column index. * @return a new column view. * @throws IndexOutOfBoundsException if {@code index < 0 || index >= cols()} * @throws UnsupportedOperationException if the {@link #order()} function * is not an instance of {@link StrideOrder2d} */ public DoubleMatrix1d colAt(final int index) { return new DoubleMatrix1d(structure.colAt(index), array); } /** * Constructs and returns a view representing the columns of the * given row. The returned view is backed by this matrix, so changes in the * returned view are reflected in this matrix, and vice-versa. * * @param index the row index. * @return a new row view. * @throws IndexOutOfBoundsException if {@code index < 0 || index >= rows()} * @throws UnsupportedOperationException if the {@link #order()} function * is not an instance of {@link StrideOrder2d} */ public DoubleMatrix1d rowAt(final int index) { return new DoubleMatrix1d(structure.rowAt(index), array); } /* ************************************************************************* * Matrix algebra methods. * ************************************************************************/ /** * Linear algebraic matrix-vector multiplication *
     *     z = alpha * A * y + beta*z
     *     z[i] = alpha*Sum(A[i, j] * y[j]) + beta*z[i],
     *           i = 0..A.rows() - 1, j = 0..y.size() - 1
     *     where
     *     A == this
     * 
* * @implNote * Matrix shape conformance is checked after potential * transpositions. * * @param y the source vector. * @param z the vector where results are to be stored. Set this parameter to * {@code null} to indicate that a new result vector should be * constructed. * @return z, or a newly created result matrix * @throws IllegalArgumentException if {@code A.cols() != y.size() || * A.rows() > z.size())}. */ public DoubleMatrix1d mult( final DoubleMatrix1d y, final DoubleMatrix1d z, final double alpha, final double beta, final boolean transposeA ) { if (transposeA) { return view(structure().transpose()) .mult(y, z, alpha, beta, false); } if (z == null) { final var struct = new Structure1d(new Extent1d(rows())); final var elems = array.like(struct.extent().size()); return mult(y, new DoubleMatrix1d(struct, elems), alpha, beta, false); } if (cols() != y.size() || rows() > z.size()) { throw new IllegalArgumentException( "Incompatible args: " + extent() + ", " + y.extent() + ", " + z.extent() ); } for (int i = rows(); --i >= 0; ) { double s = 0; for (int j = cols(); --j >= 0;) { s = Math.fma(get(i, j), y.get(j), s); } z.set(i, Math.fma(alpha, s, beta*z.get(i))); } return z; } /** * Linear algebraic matrix-vector multiplication; {@code z = A * y}; * Equivalent to {@code return A.mult(y, z, 1, 0);} * * @see #mult(DoubleMatrix1d, DoubleMatrix1d, double, double, boolean) * * @param y the source vector. * @param z the vector where results are to be stored. Set this parameter to * {@code null} to indicate that a new result vector should be * constructed. * @return z, or a newly created result matrix */ public DoubleMatrix1d mult(final DoubleMatrix1d y, final DoubleMatrix1d z) { return mult(y, z, 1, (z == null ? 1 : 0), false); } /** * Linear algebraic matrix-matrix multiplication: *
     *     C = alpha * A x B + beta*C
     *     C[i, j] = alpha*Sum(A[i, k] * B[k, j]) + beta*C[i, j], k = 0..n-1
     * 
* Matrix shapes: *
     *     A(m x n), B(n x p), C(m x p)
     * 
* * @implNote * Matrix shape conformance is checked after potential * transpositions. * * @param B the second source matrix. * @param C the matrix where results are to be stored. Set this parameter to * {@code null} to indicate that a new result matrix should be * constructed. * @return C, or a newly created result matrix * @throws IllegalArgumentException if {@code B.rows() != A.cols()} or * {@code C.rows() != A.rows() || C.cols() != B.cols()} or * {@code A == C || B == C} */ public DoubleMatrix2d mult( final DoubleMatrix2d B, final DoubleMatrix2d C, final double alpha, final double beta, final boolean transposeA, final boolean transposeB ) { requireNonNull(B); if (transposeA) { return view(structure().transpose()) .mult(B, C, alpha, beta, false, transposeB); } if (transposeB) { return mult( B.view(B.structure().transpose()), C, alpha, beta, false, false ); } if (C == null) { return mult(B, like(rows(), B.cols()), alpha, beta, false, false); } final int m = rows(); final int n = cols(); final int p = B.cols(); if (B.rows() != n) { throw new IllegalArgumentException( "2-d matrix inner dimensions must be equal:" + extent() + ", " + B.extent() ); } if (C.rows() != m || C.cols() != p) { throw new IllegalArgumentException( "Incompatible result matrix: " + extent() + ", " + B.extent() + ", " + C.extent() ); } if (this == C || B == C) { throw new IllegalArgumentException( "Matrices A, B or C must not be identical." ); } for (int j = p; --j >= 0;) { for (int i = m; --i >= 0;) { double s = 0; for (int k = n; --k >= 0;) { s = Math.fma(get(i, k), B.get(k, j), s); } C.set(i, j, Math.fma(alpha, s, beta*C.get(i, j))); } } return C; } /** * Linear algebraic matrix-matrix multiplication {@code C = A x B}, which is * equivalent to {@code A.mult(B, C, 1, 0, false, false)}. * * @see #mult(DoubleMatrix2d, DoubleMatrix2d, double, double, boolean, boolean) * * @param B the second source matrix. * @param C the matrix where results are to be stored. Set this parameter to * {@code null} to indicate that a new result matrix should be * constructed. * @return C, or a newly created result matrix. * @throws IllegalArgumentException if {@code B.rows() != A.cols()} or * {@code C.rows() != A.rows() || C.cols() != B.cols()} or * {@code A == C || B == C} */ public DoubleMatrix2d mult(final DoubleMatrix2d B, final DoubleMatrix2d C) { return mult(B, C, 1, (C == null ? 1 : 0), false, false); } /** * Return the sum of all cells: {@code Sum(x[i, j])}. * * @return the sum of all cells */ public double sum() { if (size() == 0) { return 0; } else { return reduce(Double::sum, DoubleUnaryOperator.identity()); } } @Override public boolean equals(final Object object) { return object == this || object instanceof DoubleMatrix2d matrix && NumericalContext.with(ZERO_EPSILON, () -> equals(matrix)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy