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

io.jenetics.lattices.grid.DoubleGrid2d 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.grid;

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

import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleUnaryOperator;

import io.jenetics.lattices.NumericalContext;
import io.jenetics.lattices.array.DoubleArray;

/**
 * Generic class for 2-d grids holding {@code double} elements. The
 * {@code DoubleGrid2d} is just a 2-d view onto a 1-d Java
 * {@code double[]} array. The following example shows how to create such a grid
 * view from a given {@code double[]} array.
 *
 * 
{@code
 * final var values = new double[50*100];
 * final var grid = new DoubleGrid2d(
 *     new Structure2d(new Extent2d(50, 100)),
 *     new DenseDoubleArray(values)
 * );
 * }
* * @author Franz Wilhelmstötter * @since 3.0 * @version 3.0 */ public class DoubleGrid2d implements Grid2d { /** * The structure, which defines the extent of the grid and the * order which determines the index mapping {@code N^2 -> N}. */ protected final Structure2d structure; /** * The underlying {@code double[]} array. */ protected final DoubleArray array; /** * 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 * @throws IllegalArgumentException if the size of the given {@code array} * is not able to hold the required number of elements. It is still * possible that an {@link IndexOutOfBoundsException} is thrown when * the defined order of the grid tries to access an array index, * which is not within the bounds of the {@code array}. * @throws NullPointerException if one of the arguments is {@code null} */ public DoubleGrid2d(final Structure2d structure, final DoubleArray array) { if (structure.extent().size() > array.length()) { throw new IllegalArgumentException( "The number of available elements is smaller than the number of " + "required grid cells: %s > %s." .formatted(structure.extent(), array.length()) ); } this.structure = structure; this.array = array; } @Override public Structure2d structure() { return structure; } /** * Return the underlying element array. * * @return the underlying element array */ public DoubleArray array() { return array; } /** * Returns the matrix cell value at coordinate {@code [row, col]}. * * @param row the index of the row-coordinate * @param col the index of the column-coordinate * @return the value of the specified cell * @throws IndexOutOfBoundsException if the given coordinates are out of * bounds */ public double get(final int row, final int col) { return array.get(order().index(row, col)); } /** * Sets the matrix cell at coordinate {@code [row, col]} to the specified * {@code value}. * * @param row the index of the row-coordinate * @param col the index of the column-coordinate * @param value the value to be filled into the specified cell * @throws IndexOutOfBoundsException if the given coordinates are out of * bounds */ public void set(final int row, final int col, final double value) { array.set(order().index(row, col), value); } /** * Replaces all cell values of the receiver with the values of another * matrix. Both matrices must have the same number of rows and columns. * * @param other the source matrix to copy from (maybe identical to the * receiver). * @throws IllegalArgumentException if {@code !extent().equals(other.extent())} */ public void assign(final DoubleGrid2d other) { if (other == this) { return; } checkSameExtent(this, other); for (int r = rows(); --r >= 0;) { for (int c = cols(); --c >= 0;) { set(r, c, other.get(r, c)); } } } /** * Sets all cells to the state specified by given {@code values}. The * {@code values} are required to have the form {@code values[row][column]} * and have exactly the same number of rows and columns as the receiver. * * @implNote * The {@code values} are copied and subsequent chances to the {@code values} * are not reflected in the matrix, and vice-versa * * @param values the values to be filled into the cells. * @throws IllegalArgumentException if {@code !extent().equals(other.extent())} */ public void assign(final double[][] values) { if (values.length != rows()) { throw new IllegalArgumentException( "Values must have the same number of rows: " + values.length + " != " + rows() ); } for (int r = rows(); --r >= 0;) { final double[] row = values[r]; if (row.length != cols()) { throw new IllegalArgumentException( "Values must have the same number of columns: " + row.length + " != " + cols() ); } for (int c = cols(); --c >= 0;) { set(r, c, row[c]); } } } /** * Sets all cells to the state specified by {@code values}. * * @param value the value to be filled into the cells */ public void assign(final double value) { for (int r = rows(); --r >= 0;) { for (int c = cols(); --c >= 0;) { set(r, c, value); } } } /** * Assigns the result of a function to each cell {@code x[row, col] = * f(x[row, col], y[row, col])}. * * @param y the secondary matrix to operate on. * @param f a function object taking as first argument the current cell's * value of {@code this}, and as second argument the current cell's * value of {@code y} * @throws IllegalArgumentException if {@code !extent().equals(y.extent())} */ public void assign( final DoubleGrid2d y, final DoubleBinaryOperator f ) { requireNonNull(f); checkSameExtent(this, y); for (int r = rows(); --r >= 0;) { for (int c = cols(); --c >= 0;) { set(r, c, f.applyAsDouble(get(r, c), y.get(r, c))); } } } /** * Assigns the result of a function to each cell * {@code x[row, col] = f(x[row, col])}. * * @param f a function object taking as argument the current cell's value. */ public void assign(final DoubleUnaryOperator f) { requireNonNull(f); for (int r = rows(); --r >= 0;) { for (int c = cols(); --c >= 0;) { set(r, c, f.applyAsDouble(get(r, c))); } } } /** * Swaps each element {@code this[i, j]} with {@code other[i, j]}. * * @throws IllegalArgumentException if {@code extent() != other.extent()}. */ public void swap(final DoubleGrid2d other) { checkSameExtent(this, other); for (int r = rows(); --r >= 0;) { for (int c = cols(); --c >= 0;) { final var tmp = get(r, c); set(r, c, other.get(r, c)); other.set(r, c, tmp); } }; } /** * Applies a function to each cell and aggregates the results. Returns a * value v such that v==a(size()) where * a(i) == reduce(a(i - 1), f(get(row, col))) and terminators are * a(1) == f(get(0,0)), a(0) == Double.NaN. *

Example:

*
     * 2 x 2 matrix
     * 0 1
     * 2 3
     *
     * // Sum(x[row, col]*x[row, col])
     * matrix.aggregate(Double::sum, a -> a*a) --> 14
     * 
* * @param reducer an aggregation function taking as first argument the * current aggregation and as second argument the transformed current * cell value * @param f a function transforming the current cell value * @return the aggregated value */ public double reduce( final DoubleBinaryOperator reducer, final DoubleUnaryOperator f ) { requireNonNull(reducer); requireNonNull(f); if (size() == 0) { return Double.NaN; } double a = f.applyAsDouble(get(rows() - 1, cols() - 1)); int d = 1; for (int r = rows(); --r >= 0;) { for (int c = cols() - d; --c >= 0;) { a = reducer.applyAsDouble(a, f.applyAsDouble(get(r, c))); } d = 0; } return a; } /** * Checks whether the given matrices have the same dimension and contains * the same values. * * @param other the second matrix to compare * @return {@code true} if the two given matrices are equal, {@code false} * otherwise */ public boolean equals(final DoubleGrid2d other) { final var context = NumericalContext.get(); return extent().equals(other.extent()) && allMatch((r, c) -> context.equals(get(r, c), other.get(r, c))); } @Override public int hashCode() { final int[] hash = new int[] { 37 }; forEach((i, j) -> hash[0] += Double.hashCode(get(i, j))*17); return hash[0]; } @Override public boolean equals(final Object object) { return object == this || object instanceof DoubleGrid2d grid && NumericalContext.with(ZERO_EPSILON, () -> equals(grid)); } @Override public String toString() { final var out = new StringBuilder(); out.append("["); for (int i = 0; i < rows(); ++i) { if (i != 0) { out.append(" "); } out.append("["); for (int j = 0; j < cols(); ++j) { out.append(get(i, j)); if (j < cols() - 1) { out.append(", "); } } out.append("]"); if (i < rows() - 1) { out.append("\n"); } } out.append("]"); return out.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy