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

net.algart.matrices.DependenceApertureBuilder Maven / Gradle / Ivy

Go to download

Open-source Java libraries, supporting generalized smart arrays and matrices with elements of any types, including a wide set of 2D-, 3D- and multidimensional image processing and other algorithms, working with arrays and matrices.

There is a newer version: 1.4.23
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2007-2024 Daniel Alievsky, AlgART Laboratory (http://algart.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.algart.matrices;

import net.algart.arrays.Arrays;
import net.algart.arrays.Matrix;
import net.algart.arrays.PArray;
import net.algart.math.IPoint;
import net.algart.math.IRange;
import net.algart.math.IRectangularArea;
import net.algart.math.patterns.Pattern;

import java.util.Objects;

/**
 * 

Helper class for calculation of the rectangular dependence aperture of some matrix processing algorithms.

* *

Many algorithms, processing {@link Matrix n-dimensional matrices}, calculate a resulting matrix, * where the value of every element depends only on the elements of some source matrix (or matrices), * lying inside some rectangular aperture around the coordinates of the resulting element. * The typical examples are aperture-dependent processors, represented by {@link ApertureProcessor} interface, * and a group of algorithms, described by {@link StreamingApertureProcessor} class. * We call such an aperture the dependence aperture of a given processing algorithm.

* *

More precisely, the dependence aperture is such rectangular area in n-dimensional space, * represented by {@link IRectangularArea} object A, * that every element of the resulting n-dimensional matrix with coordinates * x = (x0, x1, ..., xn−1) * can depend only on elements of the source matrix (or matrices) with coordinates

* *
* x+a = * x0+a0, * x1+a1, ..., * xn−1+an−1, *
* *

where * a = (a0, a1, ..., an−1) * is one of points belonging to the rectangular area A. * Please draw attention that we use plus sing + in this definition, instead of more traditional minus sign − * (used, for example, in specifications of {@link StreamingApertureProcessor} * or {@link net.algart.matrices.morphology.RankMorphology}).

* *

The goal of this class is to build such rectangular aperture A on the base of one or several * apertures (patterns), represented by {@link Pattern} interface and specifying, for example, * possible dependence aperture for different stages of the full processing algorithm. * Draw attention: for the apertures, specified as patterns, we suppose more traditional definitions with * minus sign −, as in specifications of {@link StreamingApertureProcessor} * or {@link net.algart.matrices.morphology.RankMorphology} * (a set of points * xp = (x0p0, * x1p1, ..., * xn−1pn−1) * for all pP, P is a pattern).

* *

The main method, solving this task, is

* *
* {@link #getAperture(int dimCount, Pattern[] patterns, boolean[] inverted, short additionalSpace)} *
* *

The resulting rectangular aperture is built on the base of the rounded coordinate ranges of every * pattern ({@link Pattern#roundedCoordRange(int)}) according to combination rules, * depending on a concrete instance of this enumeration. * Please see comments to the constants of this enumeration class:

* *
    *
  • {@link #SUM},
  • *
  • {@link #MAX},
  • *
  • {@link #SUM_MAX_0}.
  • *
* *

This class is immutable and thread-safe: * there are no ways to modify settings of the created instance.

* * @author Daniel Alievsky */ public enum DependenceApertureBuilder { /** * Aperture builder, calculating sum of coordinate ranges of all passed patterns. * *

More precisely, in this builder the basic * {@link #getAperture(int dimCount, Pattern[] patterns, boolean[] inverted, short additionalSpace)} method * works according the following algorithm: * *

     * long[] allMin = new long[dimCount]; // zero-filled by Java
     * long[] allMax = new long[dimCount]; // zero-filled by Java
     * for (int k = 0; k < dimCount; k++) {
     *     for (int i = 0; i < patterns.length; i++) {
     *         {@link IRange} range = patterns[i].{@link Pattern#roundedCoordRange(int)
     *         roundedCoordRange}(k);
     *         long min = inverted[i] ? range.min() : -range.max();
     *         long max = inverted[i] ? range.max() : -range.min();
     *         allMin[k] += min;
     *         allMax[k] += max;
     *     }
     *     allMin[k] -= additionalSpace;
     *     allMax[k] += additionalSpace;
     * }
     * return {@link IRectangularArea#valueOf(IPoint, IPoint)
     * IRectangularArea.valueOf}({@link IPoint#valueOf(long...)
     * IPoint.valueOf}(allMin), {@link IPoint#valueOf(long...)
     * IPoint.valueOf}(allMax));
     * 
* *

The only difference from this code is that this class checks possible overflow before every usage of * Java + and - operators with long values and, in a case of overflow, * throws IndexOutOfBoundsException. * *

This mode is suitable for algorithms, which perform several sequential operations over the matrix, * when each elements of the result of each operation #k with coordinates * x = (x0, x1, ..., xn−1) * depends on the elements of the previous matrix with coordinates * xpi = (x0pi0, * x1pi1, ..., * xn−1pi,n−1). * Here pi are all points of the corresponding pattern * patterns[k] or, if inverted[k] is true, * of the symmetric pattern patterns[k].{@link Pattern#symmetric() symmetric()}. * *

An example of algorithm, where this aperture builder can be useful, is * {@link net.algart.matrices.morphology.Morphology#dilationErosion(Matrix, Pattern, Pattern, * net.algart.matrices.morphology.Morphology.SubtractionMode)} (if the last argument is * {@link net.algart.matrices.morphology.Morphology.SubtractionMode#NONE}). */ SUM, /** * Aperture builder, calculating set-theoretical union of coordinate ranges of all passed patterns, * with an additional guarantee that the result will contain the origin of coordinates. * *

More precisely, in this builder the basic * {@link #getAperture(int dimCount, Pattern[] patterns, boolean[] inverted, short additionalSpace)} method * works according the following algorithm: * *

     * long[] allMin = new long[dimCount]; // zero-filled by Java
     * long[] allMax = new long[dimCount]; // zero-filled by Java
     * for (int k = 0; k < dimCount; k++) {
     *     for (int i = 0; i < patterns.length; i++) {
     *         {@link IRange} range = patterns[i].{@link Pattern#roundedCoordRange(int)
     *         roundedCoordRange}(k);
     *         long min = inverted[i] ? range.min() : -range.max();
     *         long max = inverted[i] ? range.max() : -range.min();
     *         allMin[k] = Math.min(allMin[k], min);
     *         allMax[k] = Math.max(allMax[k], max);
     *     }
     *     allMin[k] -= additionalSpace;
     *     allMax[k] += additionalSpace;
     * }
     * return {@link IRectangularArea#valueOf(IPoint, IPoint)
     * IRectangularArea.valueOf}({@link IPoint#valueOf(long...)
     * IPoint.valueOf}(allMin), {@link IPoint#valueOf(long...)
     * IPoint.valueOf}(allMax));
     * 
* *

The only difference from this code is that this class checks possible overflow before every usage of * Java + and - operators with long values and, in a case of overflow, * throws IndexOutOfBoundsException. * *

This mode is suitable for algorithms, which perform several independent operations over the same * original matrix, * when each elements of the result of each operation #k with coordinates * x = (x0, x1, ..., xn−1) * depends on the elements of the previous matrix with coordinates * xpi = (x0pi0, * x1pi1, ..., * xn−1pi,n−1). * Here pi are all points of the corresponding pattern * patterns[k] or, if inverted[k] is true, * of the symmetric pattern patterns[k].{@link Pattern#symmetric() symmetric()}. * *

An example of algorithm, where this aperture builder can be useful, is * {@link net.algart.matrices.morphology.Morphology#beucherGradient(Matrix, Pattern)}. */ MAX, /** * Aperture builder, calculating sum of coordinate ranges of all passed patterns, * with an additional guarantee that the result will contain the origin of coordinates. * *

More precisely, in this builder the basic * {@link #getAperture(int dimCount, Pattern[] patterns, boolean[] inverted, short additionalSpace)} method * works according the following algorithm: * *

     * long[] allMin = new long[dimCount]; // zero-filled by Java
     * long[] allMax = new long[dimCount]; // zero-filled by Java
     * for (int k = 0; k < dimCount; k++) {
     *     for (int i = 0; i < patterns.length; i++) {
     *         {@link IRange} range = patterns[i].{@link Pattern#roundedCoordRange(int)
     *         roundedCoordRange}(k);
     *         long min = inverted[i] ? range.min() : -range.max();
     *         long max = inverted[i] ? range.max() : -range.min();
     *         allMin[k] += min;
     *         allMax[k] += max;
     *     }
     *     allMin[k] = Math.min(allMin[k], 0);
     *     allMax[k] = Math.max(allMax[k], 0);
     *     allMin[k] -= additionalSpace;
     *     allMax[k] += additionalSpace;
     * }
     * return {@link IRectangularArea#valueOf(IPoint, IPoint)
     * IRectangularArea.valueOf}({@link IPoint#valueOf(long...)
     * IPoint.valueOf}(allMin), {@link IPoint#valueOf(long...)
     * IPoint.valueOf}(allMax));
     * 
* *

The only difference from this code is that this class checks possible overflow before every usage of * Java + and - operators with long values and, in a case of overflow, * throws IndexOutOfBoundsException. * *

This mode is suitable for algorithms, which perform several sequential operations over the matrix, * when each elements of the result of each operation #k with coordinates * x = (x0, x1, ..., xn−1) * depends on the elements of the previous matrix with coordinates * xpi = (x0pi0, * x1pi1, ..., * xn−1pi,n−1). * Here pi are all points of the corresponding pattern * patterns[k] or, if inverted[k] is true, * of the symmetric pattern patterns[k].{@link Pattern#symmetric() symmetric()}. * *

An example of algorithm, where this aperture builder can be useful, is * {@link net.algart.matrices.morphology.Morphology#maskedDilationErosion(Matrix, Pattern, Pattern)}. */ SUM_MAX_0; /** * Default additional space, used by {@link #getAperture(int, Pattern[], boolean[])} method: {@value} elements. * This gap is enough for most cases, when a processing algorithm uses not only the elements * from the corresponding apertures (specified by {@link Pattern} objects), but probably also their neighbours * and neighbours of neighbours. */ public static final short DEFAULT_ADDITIONAL_SPACE = 2; /** * Equivalent to {@link #getAperture(int, net.algart.math.patterns.Pattern[], boolean[], short) * getAperture}(dimCount, new Pattern[]{pattern}, * new boolean[]{inverted}, {@link #DEFAULT_ADDITIONAL_SPACE}). * * @param dimCount the number of dimensions. * @param pattern the pattern, describing the dependence apertures the algorithm. * @param inverted if true, then patterns is supposed to be inverted. * @return rectangular dependence aperture, describing dependence of the elements of the full * processing algorithm. * @throws NullPointerException if pattern argument is {@code null}. * @throws IllegalArgumentException if dimCount<=0, * or the passed pattern has * {@link Pattern#dimCount() number of dimensions}, less than * dimCount argument. * @throws IndexOutOfBoundsException in a case of integer (63-bit) overflow while calculation of the resulting * aperture: see {@link #SUM}, {@link #MAX} and {@link #SUM_MAX_0} constants. */ public IRectangularArea getAperture(int dimCount, Pattern pattern, boolean inverted) { return getAperture(dimCount, new Pattern[]{pattern}, new boolean[]{inverted}); } /** * Equivalent to {@link #getAperture(int, net.algart.math.patterns.Pattern[], boolean[], short) * getAperture}(dimCount, new Pattern[]{pattern1, pattern2}, * new boolean[]{inverted1, inverted2}, {@link #DEFAULT_ADDITIONAL_SPACE}). * * @param dimCount the number of dimensions. * @param pattern1 the pattern, describing the dependence apertures of the 1st part * (stage) of the full algorithm. * @param pattern2 the pattern, describing the dependence apertures of the 2nd part * (stage) of the full algorithm. * @param inverted1 if true, then pattern1 is supposed to be inverted. * @param inverted2 if true, then pattern2 is supposed to be inverted. * @return rectangular dependence aperture, describing dependence of the elements of the full * processing algorithm, consisting of 2 parts (stages). * @throws NullPointerException if patterns1 or pattern2 argument is {@code null}. * @throws IllegalArgumentException if dimCount<=0, * or if some of the passed patterns have * {@link Pattern#dimCount() number of dimensions}, less than * dimCount argument. * @throws IndexOutOfBoundsException in a case of integer (63-bit) overflow while calculation of the resulting * aperture: see {@link #SUM}, {@link #MAX} and {@link #SUM_MAX_0} constants. */ public IRectangularArea getAperture(int dimCount, Pattern pattern1, boolean inverted1, Pattern pattern2, boolean inverted2) { return getAperture(dimCount, new Pattern[]{pattern1, pattern2}, new boolean[]{inverted1, inverted2}); } /** * Equivalent to {@link #getAperture(int, net.algart.math.patterns.Pattern[], boolean[], short) * getAperture}(dimCount, patterns, inverted, {@link #DEFAULT_ADDITIONAL_SPACE}). * * @param dimCount the number of dimensions. * @param patterns the set of patterns, describing the dependence apertures of different parts * (stages) of the full algorithms, for example, in terms * of {@link StreamingApertureProcessor} class. * @param inverted if some element inverted[k] is true, * then the corresponding element * patterns[k] is supposed to be inverted. * @return rectangular dependence aperture, describing dependence of the elements of the full * processing algorithm, consisting of patterns.length parts (stages). * @throws NullPointerException if patterns or inverted argument is {@code null}, * or if some elements of patterns array is {@code null}. * @throws IllegalArgumentException if dimCount<=0, * or if patterns and inverted * arrays have different lengths, * or if their length is zero (patterns.length==0), * or if some of the passed patterns have * {@link Pattern#dimCount() number of dimensions}, less than * dimCount argument. * @throws IndexOutOfBoundsException in a case of integer (63-bit) overflow while calculation of the resulting * aperture: see {@link #SUM}, {@link #MAX} and {@link #SUM_MAX_0} constants. */ public IRectangularArea getAperture(int dimCount, Pattern[] patterns, boolean[] inverted) { return getAperture(dimCount, patterns, inverted, DEFAULT_ADDITIONAL_SPACE); } /** * Builds the rectangular aperture on the base of specified array of apertures-patterns. * If inverted[k] is true, then the corresponding pattern is supposed to be inverted * (i.e. replaced with its {@link Pattern#symmetric() symmetric} version). * Please see comments to {@link #SUM}, {@link #MAX} and {@link #SUM_MAX_0} constants * for detailed specification of the behaviour of this method. * * @param dimCount the number of dimensions. * @param patterns the set of patterns, describing the dependence apertures of different parts * (stages) of the full algorithms, for example, in terms * of {@link StreamingApertureProcessor} class. * @param inverted if some element inverted[k] is true, * then the corresponding element * patterns[k] is supposed to be inverted. * @param additionalSpace additional gap, added to all coordinate ranges of the resulting aperture. * @return rectangular dependence aperture, describing dependence of the elements of the full * processing algorithm, consisting of patterns.length parts (stages). * @throws NullPointerException if patterns or inverted argument is {@code null}, * or if some elements of patterns array is {@code null}. * @throws IllegalArgumentException if dimCount<=0, * or if patterns and inverted * arrays have different lengths, * or if their length is zero (patterns.length==0), * or if additionalSpace<0, * or if some of the passed patterns have * {@link Pattern#dimCount() number of dimensions}, less than * dimCount argument. * @throws IndexOutOfBoundsException in a case of integer (63-bit) overflow while calculation of the resulting * aperture: see {@link #SUM}, {@link #MAX} and {@link #SUM_MAX_0} constants. */ public IRectangularArea getAperture(int dimCount, Pattern[] patterns, boolean[] inverted, short additionalSpace) { Objects.requireNonNull(patterns, "Null patterns argument"); Objects.requireNonNull(inverted, "Null inverted argument"); if (dimCount <= 0) { throw new IllegalArgumentException("Zero or negative dimCount argument"); } if (patterns.length == 0) { throw new IllegalArgumentException("Empty patterns argument"); } if (inverted.length == 0) { throw new IllegalArgumentException("Empty inverted argument"); } if (patterns.length != inverted.length) { throw new IllegalArgumentException("Different lengths of patterns and inverted arguments"); } if (additionalSpace < 0) { throw new IllegalArgumentException("Negative additionalSpace argument"); } patterns = patterns.clone(); // after this moment, "patterns" cannot be changed by parallel threads inverted = inverted.clone(); // after this moment, "inverted" cannot be changed by parallel threads for (int i = 0; i < patterns.length; i++) { Objects.requireNonNull(patterns[i], "Null pattern #" + i); if (patterns[i].dimCount() < dimCount) { throw new IllegalArgumentException("Pattern #" + i + " has insufficient dimensions (<" + dimCount + ")"); } } long[] allMin = new long[dimCount]; // zero-filled by Java long[] allMax = new long[dimCount]; // zero-filled by Java for (int k = 0; k < dimCount; k++) { for (int i = 0; i < patterns.length; i++) { IRange range = patterns[i].roundedCoordRange(k); long min = inverted[i] ? range.min() : -range.max(); long max = inverted[i] ? range.max() : -range.min(); switch (this) { case SUM: case SUM_MAX_0: allMin[k] = safelyAdd(allMin[k], min); allMax[k] = safelyAdd(allMax[k], max); break; case MAX: allMin[k] = Math.min(allMin[k], min); allMax[k] = Math.max(allMax[k], max); break; } } if (this == DependenceApertureBuilder.SUM_MAX_0) { allMin[k] = Math.min(allMin[k], 0); allMax[k] = Math.max(allMax[k], 0); } allMin[k] = safelyAdd(allMin[k], -additionalSpace); allMax[k] = safelyAdd(allMax[k], additionalSpace); } return IRectangularArea.valueOf(IPoint.valueOf(allMin), IPoint.valueOf(allMax)); } /** * Returns a newly created array result with the same length as the first argument, where * result[k] = matrixDimensions[k])+aperture.{@link IRectangularArea#width(int) width}(k). * This method also checks that all dimensions in the matrixDimensions array, * as well as the resulting dimensions result array, are allowed dimensions for some * AlgART matrix, i.e. are non-negative and their product is not greater than * Long.MAX_VALUE. If it is not so, IndexOutOfBoundsException is thrown. * *

In the special case, when some of the elements of the matrixDimensions array is zero, * this method returns a precise clone of this array without changes. * *

Note: the matrix, returned by * {@link #extend(Matrix, IRectangularArea, Matrix.ContinuationMode)} method, always has dimensions, * equal to the result of this method, called for {@link Matrix#dimensions() dimensions} of the source matrix * with the same aperture. * * @param matrixDimensions {@link Matrix#dimensions() dimensions} of some n-dimensional matrix. * @param aperture the dependence aperture. * @return new dimensions, extended by the given aperture. * @throws NullPointerException if one of the arguments is {@code null}. * @throws IllegalArgumentException if matrixDimensions.length!=aperture.{@link * IRectangularArea#coordCount() * coordCount()}, * or if matrixDimensions[k]<0 for some k. * @throws IndexOutOfBoundsException if product of all elements of matrixDimensions array * is greater than Long.MAX_VALUE, * or in a case of integer overflow while calculating result[k], * or if product of all elements of the resulting array * is greater than Long.MAX_VALUE. */ public static long[] extendDimensions(long[] matrixDimensions, IRectangularArea aperture) { Objects.requireNonNull(matrixDimensions, "Null matrixDimensions"); Objects.requireNonNull(aperture, "Null aperture"); if (matrixDimensions.length != aperture.coordCount()) { throw new IllegalArgumentException("Dimensions count mismatch: " + matrixDimensions.length + " dimensions in array and " + aperture.coordCount() + "-dimensional aperture"); } for (int k = 0; k < matrixDimensions.length; k++) { if (matrixDimensions[k] < 0) { throw new IllegalArgumentException("Negative matrixDimensions[" + k + "]"); } } long[] result = matrixDimensions.clone(); // after this moment, "result" cannot be changed by parallel thread long len = Arrays.longMul(result); if (len == Long.MIN_VALUE) { throw new IndexOutOfBoundsException("Too large matrixDimensions: their product > Long.MAX_VALUE"); } if (len == 0) { return result; } for (int k = 0; k < result.length; k++) { result[k] += aperture.width(k); if (result[k] < 0) { throw new IndexOutOfBoundsException("Too large matrix continuation: " + "the dimension #" + k + " of the matrix, extended to the corresponding aperture " + aperture + ", is greater than Long.MAX_VALUE"); } } if (Arrays.longMul(result) == Long.MIN_VALUE) { throw new IndexOutOfBoundsException("Too large matrix continuation: product of dimensions " + "of the matrix, extended to the corresponding aperture " + aperture + ", is greater than Long.MAX_VALUE"); } return result; } /** * Returns matrix.{@link Matrix#subMatrix(long[], long[], Matrix.ContinuationMode) * subMatrix}(from, to, continuationMode), * where from[k] = aperture.{@link IRectangularArea#min(int) min}(k) * and to[k] = matrix.{@link Matrix#dim(int) dim}(k)+aperture.{@link IRectangularArea#max(int) * max}(k). * This method allows to extends the source matrix in such a way, that every element of the resulting matrix * of some processing algorithm, having the given dependence aperture, will depend only on the existing * elements of the extended matrix (lying inside its bounds). * *

In the special case matrix.{@link Matrix#size() size()}==0, * this method returns the matrix argument without changes. * *

This method performs additional checks, whether adding aperture.max().{@link IPoint#coord(int) * coord}(k) to the matrix dimension leads to integer overflow, and throws * IndexOutOfBoundsException in a case of overflow. * * @param matrix some n-dimensional matrix. * @param aperture the dependence aperture. * @param continuationMode the continuation mode for extending the matrix. * @return new matrix, extended by the given aperture. * @throws NullPointerException if one of the arguments is {@code null}. * @throws IllegalArgumentException if matrix.{@link Matrix#dimCount() * dimCount()}!=aperture.{@link IRectangularArea#coordCount() * coordCount()}. * @throws IndexOutOfBoundsException in a case of integer overflow while calculating to[k], * or in the same situations as the corresponding * {@link Matrix#subMatrix(long[], long[], Matrix.ContinuationMode) * subMatrix} call. * @throws ClassCastException in the same situations as the corresponding * {@link Matrix#subMatrix(long[], long[], Matrix.ContinuationMode) * subMatrix} call.. * @see #extendDimensions(long[], net.algart.math.IRectangularArea) */ public static Matrix extend(Matrix matrix, IRectangularArea aperture, Matrix.ContinuationMode continuationMode) { Objects.requireNonNull(matrix, "Null matrix"); Objects.requireNonNull(aperture, "Null aperture"); Objects.requireNonNull(continuationMode, "Null continuation mode"); if (matrix.dimCount() != aperture.coordCount()) { throw new IllegalArgumentException("Dimensions count mismatch: " + matrix.dimCount() + "-dimensional matrix and " + aperture.coordCount() + "-dimensional aperture"); } if (matrix.isEmpty()) { return matrix; } long[] from = new long[matrix.dimCount()]; long[] to = new long[from.length]; for (int k = 0; k < from.length; k++) { from[k] = aperture.min(k); to[k] = matrix.dim(k) + aperture.max(k); if (to[k] < 0 && aperture.max(k) >= 0) { throw new IndexOutOfBoundsException("Too large matrix continuation: " + "the dimension #" + k + " of the matrix, extended to the corresponding aperture " + aperture + ", is greater than Long.MAX_VALUE"); } } return matrix.subMatrix(from, to, continuationMode); } /** * Returns matrix.{@link Matrix#subMatrix(long[], long[], Matrix.ContinuationMode) * subMatrix}(from, to, {@link net.algart.arrays.Matrix.ContinuationMode#PSEUDO_CYCLIC}), * where from[k] = -aperture.{@link IRectangularArea#min(int) min}(k) * and to[k] = matrix.{@link Matrix#dim(int) dim}(k)-aperture.{@link IRectangularArea#max(int) * max}(k). * It is the reverse method for {@link #extend(Matrix, IRectangularArea, Matrix.ContinuationMode)}. * *

In the special case matrix.{@link Matrix#size() size()}==0, * this method returns the matrix argument without changes. * * @param matrix some n-dimensional matrix, extended by * {@link #extend(Matrix, IRectangularArea, Matrix.ContinuationMode)} method. * @param aperture the dependence aperture. * @return new matrix, reduced to the original sizes. * @throws NullPointerException if one of the arguments is {@code null}. * @throws IllegalArgumentException if matrix.{@link Matrix#dimCount() * dimCount()}!=aperture.{@link IRectangularArea#coordCount() * coordCount()}. * @throws IndexOutOfBoundsException in the same situations as the corresponding * {@link Matrix#subMatrix(long[], long[], Matrix.ContinuationMode) * subMatrix} call. */ public static Matrix reduce(Matrix matrix, IRectangularArea aperture) { Objects.requireNonNull(matrix, "Null matrix"); Objects.requireNonNull(aperture, "Null aperture"); if (matrix.dimCount() != aperture.coordCount()) { throw new IllegalArgumentException("Dimensions count mismatch: " + matrix.dimCount() + "-dimensional matrix and " + aperture.coordCount() + "-dimensional aperture"); } if (matrix.isEmpty()) { return matrix; } long[] from = new long[matrix.dimCount()]; long[] to = new long[from.length]; for (int k = 0; k < from.length; k++) { from[k] = -aperture.min(k); to[k] = matrix.dim(k) - aperture.max(k); } return matrix.subMatrix(from, to, Matrix.ContinuationMode.PSEUDO_CYCLIC); } /** * Returns sum of the arguments a+b, if this sum can be precisely represented by long * type, i.e. if it lies in Long.MIN_VALUE..Long.MAX_VALUE range, * or throws IndexOutOfBoundsException in other case. * (Unlike this method, the simple Java operator a+b always returns low 64 bits * of the mathematical sum a+b without any checks and exceptions.) * *

This method is useful for accurate calculating matrix dimensions and integer rectangular areas, * for example, for calculating dimensions of a matrix, extended with some rectangular aperture. * * @param a first summand. * @param b second summand. * @return sum a+b. * @throws IndexOutOfBoundsException in a case of integer overflow, i.e. if the mathematical sum a+b * of this integers is less than Long.MIN_VALUE * or greater than Long.MAX_VALUE. */ public static long safelyAdd(long a, long b) throws IndexOutOfBoundsException { long result = a + b; if ((a < 0) != (b < 0)) { // overflow impossible when signs are different return result; } if ((a < 0) != (result < 0)) // overflow: the sum has another sign than both summands { throw new IndexOutOfBoundsException("Integer overflow while summing two long values " + a + " and " + b + " (maybe, dimensions of some matrices or areas)"); } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy