diff --git a/pom.xml b/pom.xml index ccc76c79c834426b21a4cc030259812f2b78c86f..e68ef3989c3e7d4f3a9b531146363b6f86ebbc85 100644 --- a/pom.xml +++ b/pom.xml @@ -85,7 +85,7 @@ <groupId>cz.it4i</groupId> <artifactId>QcmpCompression</artifactId> - <version>0.5-SNAPSHOT</version> + <version>0.5.5-EXP-SNAPSHOT</version> <build> <plugins> <plugin> @@ -157,7 +157,7 @@ <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> - <version>RELEASE</version> + <version>5.7.0</version> <scope>test</scope> </dependency> </dependencies> diff --git a/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java b/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java index 5d99107ca84674d8bf564c85f938b06287cf58eb..00b69d86277656cead551f7b4fb691a0488d1119 100644 --- a/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java +++ b/src/main/java/cz/it4i/qcmp/benchmark/SQBenchmark.java @@ -37,6 +37,7 @@ public class SQBenchmark extends BenchmarkBase { if (planes.length < 1) { return; } + final boolean dirCreated = new File(this.outputDirectory).mkdirs(); System.out.println(String.format("|CODEBOOK| = %d", codebookSize)); ScalarQuantizer quantizer = null; diff --git a/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java b/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java index 101a5f5d2099fdc3a62a00558f22d7be5127296c..258de2d57e5ff9496177f1a65abd9c7284b67ecd 100644 --- a/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java +++ b/src/main/java/cz/it4i/qcmp/data/HyperStackDimensions.java @@ -1,5 +1,7 @@ package cz.it4i.qcmp.data; +import cz.it4i.qcmp.utilities.Utils; + import java.util.Objects; /** @@ -11,6 +13,7 @@ public class HyperStackDimensions { private final int height; private final int planeCount; private final int numberOfTimepoints; + private final int numberOfChannels; /** * Create HyperStackDimensions. @@ -19,37 +22,34 @@ public class HyperStackDimensions { * @param height Height of the plane. * @param planeCount Plane count in the stack. * @param numberOfTimepoints Number of stack timepoints. + * @param channelCount Number of image channels. */ - public HyperStackDimensions(final int width, final int height, final int planeCount, final int numberOfTimepoints) { + public HyperStackDimensions(final int width, + final int height, + final int planeCount, + final int numberOfTimepoints, + final int channelCount) { + assert (channelCount == 1) : "QcmpCompressionLibrary support only single channel datasets."; this.width = width; this.height = height; this.planeCount = planeCount; this.numberOfTimepoints = numberOfTimepoints; + this.numberOfChannels = channelCount; } /** - * Get number of elements in hyperstack with dimensionality = dimension. - * When calculating the element count, overflow is checked. This is because result of this - * function is usually used in places where we want to allocate memory. + * Create HyperStackDimensions. * - * @param dimension Maximum dimension. - * @return Number of elements. + * @param width Width of the plane. + * @param height Height of the plane. + * @param planeCount Plane count in the stack. + * @param numberOfTimepoints Number of stack timepoints. */ - @SuppressWarnings("DuplicateExpressions") - public int getNumberOfElementsInDimension(final int dimension) { - switch (dimension) { - case 1: - return width; - case 2: - return Math.multiplyExact(width, height); - case 3: - return Math.multiplyExact(planeCount, Math.multiplyExact(width, height)); - case 4: - return Math.multiplyExact(numberOfTimepoints, Math.multiplyExact(planeCount, Math.multiplyExact(width, height))); - default: - assert (false) : "Wrong dimension in getNumberOfElementsInDimension"; - return -1; - } + public HyperStackDimensions(final int width, + final int height, + final int planeCount, + final int numberOfTimepoints) { + this(width, height, planeCount, numberOfTimepoints, 1); } /** @@ -60,7 +60,7 @@ public class HyperStackDimensions { * @param planeCount Plane count in the stack. */ public HyperStackDimensions(final int width, final int height, final int planeCount) { - this(width, height, planeCount, 1); + this(width, height, planeCount, 1, 1); } /** @@ -70,7 +70,46 @@ public class HyperStackDimensions { * @param height Height of the plane. */ public HyperStackDimensions(final int width, final int height) { - this(width, height, 1, 1); + this(width, height, 1, 1, 1); + } + + /** + * Create HyperStackDimensions from ij.ImagePlus dimensions array. + * + * @param imagePlusDimensions ImagePlus dimensions. + * @return Correct HyperStackDimensions. + */ + public static HyperStackDimensions createFromImagePlusDimensions(final int[] imagePlusDimensions) { + // NOTE(Moravec): ij.ImagePlus dimensions array = (width, height, nChannels, nSlices, nFrames) + return new HyperStackDimensions(imagePlusDimensions[0], + imagePlusDimensions[1], + imagePlusDimensions[3], + imagePlusDimensions[4], + imagePlusDimensions[2]); + } + + /** + * Get number of elements in hyperstack with dimensionality = dimension. + * When calculating the element count, overflow is checked. This is because result of this + * function is usually used in places where we want to allocate memory. + * + * @param dimension Maximum dimension. + * @return Number of elements. + */ + public int getNumberOfElementsInDimension(final int dimension) { + switch (dimension) { + case 1: + return width; + case 2: + return Math.multiplyExact(width, height); + case 3: + return Utils.multiplyExact(width, height, planeCount); + case 4: + return Utils.multiplyExact(width, height, planeCount, numberOfChannels); + default: + assert (false) : "Wrong dimension in getNumberOfElementsInDimension"; + return -1; + } } /** @@ -109,6 +148,14 @@ public class HyperStackDimensions { return new V2i(width, height); } + /** + * Get number of channels in the dataset. + * + * @return Channel count. + */ + public int getNumberOfChannels() { + return numberOfChannels; + } /** * Get number of timepoints of the stack. diff --git a/src/main/java/cz/it4i/qcmp/utilities/Utils.java b/src/main/java/cz/it4i/qcmp/utilities/Utils.java index 3730c98670b4c585dca700e70fa46de29b14bc87..6d71079b747518e5bbd098cb6d5f6ca55be7a1f9 100644 --- a/src/main/java/cz/it4i/qcmp/utilities/Utils.java +++ b/src/main/java/cz/it4i/qcmp/utilities/Utils.java @@ -160,4 +160,36 @@ public class Utils { } return Math.sqrt(sum); } + + /** + * Returns the product of the arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param numbers values to multiply + * @return the result + * @throws ArithmeticException if the result overflows an int + */ + public static int multiplyExact(final int... numbers) throws ArithmeticException { + int result = numbers[0]; + for (int i = 1; i < numbers.length; i++) { + result = Math.multiplyExact(result, numbers[i]); + } + return result; + } + + /** + * Returns the product of the arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param numbers values to multiply + * @return the result + * @throws ArithmeticException if the result overflows an int + */ + public static long multiplyExact(final long... numbers) throws ArithmeticException { + long result = numbers[0]; + for (int i = 1; i < numbers.length; i++) { + result = Math.multiplyExact(result, numbers[i]); + } + return result; + } } \ No newline at end of file diff --git a/src/test/java/cz/it4i/qcmp/utilities/UtilsTest.java b/src/test/java/cz/it4i/qcmp/utilities/UtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6b6de6c0a15cbbf1858f76cd98d6f29ac800a2d1 --- /dev/null +++ b/src/test/java/cz/it4i/qcmp/utilities/UtilsTest.java @@ -0,0 +1,18 @@ +package cz.it4i.qcmp.utilities; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class UtilsTest { + + @Test + void multiplyExact() { + final int a = 200; + final int b = 54; + final int c = 783; + + final int refResult = Math.multiplyExact(a, Math.multiplyExact(b, c)); + final int result = Utils.multiplyExact(a, b, c); + Assertions.assertEquals(refResult, result); + } +} \ No newline at end of file