diff --git a/src/main/java/org/bytedeco/javacpp/indexer/HyperslabIndex.java b/src/main/java/org/bytedeco/javacpp/indexer/HyperslabIndex.java new file mode 100644 index 000000000..9c25498f8 --- /dev/null +++ b/src/main/java/org/bytedeco/javacpp/indexer/HyperslabIndex.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2016-2019 Samuel Audet + * + * Licensed either under the Apache License, Version 2.0, or (at your option) + * under the terms of the GNU General Public License as published by + * the Free Software Foundation (subject to the "Classpath" exception), + * either version 2, or any later version (collectively, 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 + * http://www.gnu.org/licenses/ + * http://www.gnu.org/software/classpath/license.html + * + * or as provided in the LICENSE.txt file that accompanied this code. + * 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.bytedeco.javacpp.indexer; + +/** + * A hyperslab is a rectangular pattern defined by four arrays. + *

+ * The {@code start} defines the origin of the hyperslab in the original coordinates. + * The {@code stride} is the number of elements to increment between selected elements. + * A stride of '1' is every element, a stride of '2' is every second element, etc. + * The default stride is 1. + * The {@code count} is the number of elements in the hyperslab selection. + * When the stride is 1, the selection is a hyper rectangle with a corner at {@code start} + * and size {@code count[0]} by {@code count[1]} by ... + * When stride is greater than one, the hyperslab bounded by start and the corners + * defined by {@code stride[n] * count[n]}. + * The {@code block} is a count on the number of repetitions of the hyperslab. + * The default block size is '1', which is one hyperslab. A block of 2 would be + * two hyperslabs in that dimension, with the second starting at {@code start[n]+ (count[n] * stride[n]) + 1}. + * + * @author Matteo Di Giovinazzo + * @see Reading From + * or Writing To a Subset of a Dataset + * @see H5S_SELECT_HYPERSLAB + * @see Dataspaces + */ +public class HyperslabIndex implements Index { + + protected long[] sizes; + private final long[] physicalStrides; + // + protected long[] starts; + protected long[] strides; + protected long[] counts; + protected long[] blocks; + + protected HyperslabIndex(long[] sizes, long[] starts, long[] strides, long[] counts, long[] blocks) { + this.sizes = sizes; + this.starts = starts; + this.strides = strides; + this.counts = counts; + this.blocks = blocks; + this.physicalStrides = DefaultIndex.strides(sizes); + } + + public static Index hyperslab(long[] sizes, long[] starts, long[] strides, long[] counts, long[] blocks) { + return new HyperslabIndex(sizes, starts, strides, counts, blocks); + } + + @Override + public long index(long i) { + return (starts[0] + strides[0] * (i / blocks[0]) + (i % blocks[0])) * physicalStrides[0]; + } + + @Override + public long index(long i, long j) { + return (starts[0] + strides[0] * (i / blocks[0]) + (i % blocks[0])) * physicalStrides[0] + + (starts[1] + strides[1] * (j / blocks[1]) + (j % blocks[1])) * physicalStrides[1]; + } + + @Override + public long index(long i, long j, long k) { + return (starts[0] + strides[0] * (i / blocks[0]) + (i % blocks[0])) * physicalStrides[0] + + (starts[1] + strides[1] * (j / blocks[1]) + (j % blocks[1])) * physicalStrides[1] + + (starts[2] + strides[2] * (k / blocks[2]) + (k % blocks[2])) * physicalStrides[2]; + } + + @Override + public long index(long... indices) { + long index = 0; + for (int i = 0; i < indices.length; i++) { + long coordinate = indices[i]; + long mappedCoordinate = starts[i] + strides[i] * (coordinate / blocks[i]) + (coordinate % blocks[i]); + index += mappedCoordinate * physicalStrides[i]; + } + return index; + } + + @Override + public long[] sizes() { + return sizes; + } + + @Override + public long[] strides() { + return physicalStrides; + } +} diff --git a/src/test/java/org/bytedeco/javacpp/indexer/HyperslabIndexTest.java b/src/test/java/org/bytedeco/javacpp/indexer/HyperslabIndexTest.java new file mode 100644 index 000000000..e0d84797e --- /dev/null +++ b/src/test/java/org/bytedeco/javacpp/indexer/HyperslabIndexTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014-2019 Samuel Audet + * + * Licensed either under the Apache License, Version 2.0, or (at your option) + * under the terms of the GNU General Public License as published by + * the Free Software Foundation (subject to the "Classpath" exception), + * either version 2, or any later version (collectively, 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 + * http://www.gnu.org/licenses/ + * http://www.gnu.org/software/classpath/license.html + * + * or as provided in the LICENSE.txt file that accompanied this code. + * 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.bytedeco.javacpp.indexer; + +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.bytedeco.javacpp.indexer.HyperslabIndex.hyperslab; +import static org.junit.Assert.assertEquals; + +public class HyperslabIndexTest { + + private static float[] ARRAY; + + @BeforeClass + public static void beforeClass() { + ARRAY = new float[12 * 10]; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + ARRAY[i * 10 + j] = i * 10f + j; + } + } + for (int i = 11; i < 12; i++) { + for (int j = 0; j < 10; j++) { + ARRAY[i * 10 + j] = -1f; + } + } + } + + @Test + public void testIndexI() { + long[] sizes = new long[]{120}; + Index index = hyperslab( + sizes, + new long[]{1}, + new long[]{4}, + new long[]{2}, + new long[]{3} + ); + FloatIndexer indexer1d = FloatIndexer.create(ARRAY, index); + + assertEquals(1f, indexer1d.get(0), 0f); + assertEquals(2f, indexer1d.get(1), 0f); + assertEquals(3f, indexer1d.get(2), 0f); + assertEquals(5f, indexer1d.get(3), 0f); + assertEquals(6f, indexer1d.get(4), 0f); + assertEquals(7f, indexer1d.get(5), 0f); + } + + @Test + public void testIndexIJ() { + long[] sizes = new long[]{12, 10}; + Index index = hyperslab( + sizes, + new long[]{1, 1}, + new long[]{4, 3}, + new long[]{2, 3}, + new long[]{3, 2} + ); + + FloatIndexer indexer2d = FloatIndexer.create(ARRAY, index); + + assertEquals(11f, indexer2d.get(0, 0), 0f); + assertEquals(21f, indexer2d.get(1, 0), 0f); + assertEquals(31f, indexer2d.get(2, 0), 0f); + assertEquals(51f, indexer2d.get(3, 0), 0f); + assertEquals(61f, indexer2d.get(4, 0), 0f); + assertEquals(71f, indexer2d.get(5, 0), 0f); + // + assertEquals(12f, indexer2d.get(0, 1), 0f); + assertEquals(22f, indexer2d.get(1, 1), 0f); + assertEquals(32f, indexer2d.get(2, 1), 0f); + assertEquals(52f, indexer2d.get(3, 1), 0f); + assertEquals(62f, indexer2d.get(4, 1), 0f); + assertEquals(72f, indexer2d.get(5, 1), 0f); + // + // + assertEquals(14f, indexer2d.get(0, 2), 0f); + assertEquals(24f, indexer2d.get(1, 2), 0f); + assertEquals(34f, indexer2d.get(2, 2), 0f); + assertEquals(54f, indexer2d.get(3, 2), 0f); + assertEquals(64f, indexer2d.get(4, 2), 0f); + assertEquals(74f, indexer2d.get(5, 2), 0f); + // + assertEquals(15f, indexer2d.get(0, 3), 0f); + assertEquals(25f, indexer2d.get(1, 3), 0f); + assertEquals(35f, indexer2d.get(2, 3), 0f); + assertEquals(55f, indexer2d.get(3, 3), 0f); + assertEquals(65f, indexer2d.get(4, 3), 0f); + assertEquals(75f, indexer2d.get(5, 3), 0f); + // + // + assertEquals(17f, indexer2d.get(0, 4), 0f); + assertEquals(27f, indexer2d.get(1, 4), 0f); + assertEquals(37f, indexer2d.get(2, 4), 0f); + assertEquals(57f, indexer2d.get(3, 4), 0f); + assertEquals(67f, indexer2d.get(4, 4), 0f); + assertEquals(77f, indexer2d.get(5, 4), 0f); + // + assertEquals(18f, indexer2d.get(0, 5), 0f); + assertEquals(28f, indexer2d.get(1, 5), 0f); + assertEquals(38f, indexer2d.get(2, 5), 0f); + assertEquals(58f, indexer2d.get(3, 5), 0f); + assertEquals(68f, indexer2d.get(4, 5), 0f); + assertEquals(78f, indexer2d.get(5, 5), 0f); + } + + @Test + public void testIndexIJK() { + } + + @Test + public void testIndexIndices() { + } +}