diff options
author | Karl Shaffer <karlshaffer@google.com> | 2023-08-10 22:35:48 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-08-10 22:35:48 +0000 |
commit | 5484895ffd3d0c8337d159667cafc127c459f677 (patch) | |
tree | ace24ba4307d4978ee3134f7da671a77ad172da0 /src/main/java/org/apache/commons/math3/util/MultidimensionalCounter.java | |
parent | bbf9548f049f99fd8e5a593baae983532dd983f4 (diff) | |
parent | b3715644fba79ef08acd9a2e157d078865281767 (diff) | |
download | apache-commons-math-5484895ffd3d0c8337d159667cafc127c459f677.tar.gz |
Check-in commons-math 3.6.1 am: 1354beaf45 am: 0018f64b87 am: b3715644fb
Original change: https://android-review.googlesource.com/c/platform/external/apache-commons-math/+/2702413
Change-Id: I5ad9b2a0822d668b5b6a62933c6d4c1f0b802001
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'src/main/java/org/apache/commons/math3/util/MultidimensionalCounter.java')
-rw-r--r-- | src/main/java/org/apache/commons/math3/util/MultidimensionalCounter.java | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/util/MultidimensionalCounter.java b/src/main/java/org/apache/commons/math3/util/MultidimensionalCounter.java new file mode 100644 index 0000000..5e239e9 --- /dev/null +++ b/src/main/java/org/apache/commons/math3/util/MultidimensionalCounter.java @@ -0,0 +1,283 @@ +/* + * 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.math3.util; + +import org.apache.commons.math3.exception.DimensionMismatchException; +import org.apache.commons.math3.exception.NotStrictlyPositiveException; +import org.apache.commons.math3.exception.OutOfRangeException; + +import java.util.NoSuchElementException; + +/** + * Converter between unidimensional storage structure and multidimensional conceptual structure. + * This utility will convert from indices in a multidimensional structure to the corresponding index + * in a one-dimensional array. For example, assuming that the ranges (in 3 dimensions) of indices + * are 2, 4 and 3, the following correspondences, between 3-tuples indices and unidimensional + * indices, will hold: + * + * <ul> + * <li>(0, 0, 0) corresponds to 0 + * <li>(0, 0, 1) corresponds to 1 + * <li>(0, 0, 2) corresponds to 2 + * <li>(0, 1, 0) corresponds to 3 + * <li>... + * <li>(1, 0, 0) corresponds to 12 + * <li>... + * <li>(1, 3, 2) corresponds to 23 + * </ul> + * + * @since 2.2 + */ +public class MultidimensionalCounter implements Iterable<Integer> { + /** Number of dimensions. */ + private final int dimension; + + /** Offset for each dimension. */ + private final int[] uniCounterOffset; + + /** Counter sizes. */ + private final int[] size; + + /** Total number of (one-dimensional) slots. */ + private final int totalSize; + + /** Index of last dimension. */ + private final int last; + + /** Perform iteration over the multidimensional counter. */ + public class Iterator implements java.util.Iterator<Integer> { + /** Multidimensional counter. */ + private final int[] counter = new int[dimension]; + + /** Unidimensional counter. */ + private int count = -1; + + /** Maximum value for {@link #count}. */ + private final int maxCount = totalSize - 1; + + /** + * Create an iterator + * + * @see #iterator() + */ + Iterator() { + counter[last] = -1; + } + + /** {@inheritDoc} */ + public boolean hasNext() { + return count < maxCount; + } + + /** + * @return the unidimensional count after the counter has been incremented by {@code 1}. + * @throws NoSuchElementException if {@link #hasNext()} would have returned {@code false}. + */ + public Integer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + for (int i = last; i >= 0; i--) { + if (counter[i] == size[i] - 1) { + counter[i] = 0; + } else { + ++counter[i]; + break; + } + } + + return ++count; + } + + /** + * Get the current unidimensional counter slot. + * + * @return the index within the unidimensionl counter. + */ + public int getCount() { + return count; + } + + /** + * Get the current multidimensional counter slots. + * + * @return the indices within the multidimensional counter. + */ + public int[] getCounts() { + return MathArrays.copyOf(counter); + } + + /** + * Get the current count in the selected dimension. + * + * @param dim Dimension index. + * @return the count at the corresponding index for the current state of the iterator. + * @throws IndexOutOfBoundsException if {@code index} is not in the correct interval (as + * defined by the length of the argument in the {@link + * MultidimensionalCounter#MultidimensionalCounter(int[]) constructor of the enclosing + * class}). + */ + public int getCount(int dim) { + return counter[dim]; + } + + /** + * @throws UnsupportedOperationException + */ + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** + * Create a counter. + * + * @param size Counter sizes (number of slots in each dimension). + * @throws NotStrictlyPositiveException if one of the sizes is negative or zero. + */ + public MultidimensionalCounter(int... size) throws NotStrictlyPositiveException { + dimension = size.length; + this.size = MathArrays.copyOf(size); + + uniCounterOffset = new int[dimension]; + + last = dimension - 1; + int tS = size[last]; + for (int i = 0; i < last; i++) { + int count = 1; + for (int j = i + 1; j < dimension; j++) { + count *= size[j]; + } + uniCounterOffset[i] = count; + tS *= size[i]; + } + uniCounterOffset[last] = 0; + + if (tS <= 0) { + throw new NotStrictlyPositiveException(tS); + } + + totalSize = tS; + } + + /** + * Create an iterator over this counter. + * + * @return the iterator. + */ + public Iterator iterator() { + return new Iterator(); + } + + /** + * Get the number of dimensions of the multidimensional counter. + * + * @return the number of dimensions. + */ + public int getDimension() { + return dimension; + } + + /** + * Convert to multidimensional counter. + * + * @param index Index in unidimensional counter. + * @return the multidimensional counts. + * @throws OutOfRangeException if {@code index} is not between {@code 0} and the value returned + * by {@link #getSize()} (excluded). + */ + public int[] getCounts(int index) throws OutOfRangeException { + if (index < 0 || index >= totalSize) { + throw new OutOfRangeException(index, 0, totalSize); + } + + final int[] indices = new int[dimension]; + + int count = 0; + for (int i = 0; i < last; i++) { + int idx = 0; + final int offset = uniCounterOffset[i]; + while (count <= index) { + count += offset; + ++idx; + } + --idx; + count -= offset; + indices[i] = idx; + } + + indices[last] = index - count; + + return indices; + } + + /** + * Convert to unidimensional counter. + * + * @param c Indices in multidimensional counter. + * @return the index within the unidimensionl counter. + * @throws DimensionMismatchException if the size of {@code c} does not match the size of the + * array given in the constructor. + * @throws OutOfRangeException if a value of {@code c} is not in the range of the corresponding + * dimension, as defined in the {@link + * MultidimensionalCounter#MultidimensionalCounter(int...) constructor}. + */ + public int getCount(int... c) throws OutOfRangeException, DimensionMismatchException { + if (c.length != dimension) { + throw new DimensionMismatchException(c.length, dimension); + } + int count = 0; + for (int i = 0; i < dimension; i++) { + final int index = c[i]; + if (index < 0 || index >= size[i]) { + throw new OutOfRangeException(index, 0, size[i] - 1); + } + count += uniCounterOffset[i] * c[i]; + } + return count + c[last]; + } + + /** + * Get the total number of elements. + * + * @return the total size of the unidimensional counter. + */ + public int getSize() { + return totalSize; + } + + /** + * Get the number of multidimensional counter slots in each dimension. + * + * @return the sizes of the multidimensional counter in each dimension. + */ + public int[] getSizes() { + return MathArrays.copyOf(size); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < dimension; i++) { + sb.append("[").append(getCount(i)).append("]"); + } + return sb.toString(); + } +} |