-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from HHS/indexer_migration
Indexer migration
- Loading branch information
Showing
10 changed files
with
672 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package util.indexer; | ||
|
||
import net.jcip.annotations.ThreadSafe; | ||
import util.errors.ContractException; | ||
|
||
/** | ||
* A thread safe, immutable index converter that supports treating a 2D array as | ||
* a 1D array. | ||
*/ | ||
|
||
@ThreadSafe | ||
public final class Indexer2 { | ||
|
||
private final int size; | ||
|
||
private final int p1; | ||
|
||
/** | ||
* Constructs an 2D indexer from the given dimension sizes | ||
* | ||
* @throws ContractException | ||
* <ul> | ||
* <li>{@linkplain IndexerError#NEGATIVE_DIMENSION_SIZE} | ||
* if any dimension has a negative size</li> | ||
* <li>{@linkplain IndexerError#EXCEEDS_MAX_ARRAY_SIZE} | ||
* if the product of the dimensions exceeds max | ||
* int</li> | ||
* </ul> | ||
* | ||
* | ||
*/ | ||
public Indexer2(final int dim1, final int dim2) { | ||
if (dim1 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim2 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
try { | ||
p1 = dim2; | ||
size = Math.multiplyExact(p1, dim1); | ||
} catch (ArithmeticException e) { | ||
throw new ContractException(IndexerError.EXCEEDS_MAX_ARRAY_SIZE); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the combined index = index1*dim2+index2 from the given index values. | ||
* No validation of the indexes or the result is provided. | ||
*/ | ||
public int index(final int index1, final int index2) { | ||
return index1 * p1 + index2; | ||
} | ||
|
||
/** | ||
* Returns the size (product of the dimensions) of the array supported by this | ||
* index. | ||
*/ | ||
public int size() { | ||
return size; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package util.indexer; | ||
|
||
import util.errors.ContractException; | ||
|
||
/** | ||
* A thread safe, immutable index converter that supports treating a 3D array as | ||
* a 1D array. | ||
*/ | ||
public final class Indexer3 { | ||
private final int size; | ||
private final int p1; | ||
private final int p2; | ||
|
||
/** | ||
* Constructs an 3D indexer from the given dimension sizes | ||
* | ||
* @throws ContractException | ||
* <ul> | ||
* <li>{@linkplain IndexerError#NEGATIVE_DIMENSION_SIZE} | ||
* if any dimension has a negative size</li> | ||
* <li>{@linkplain IndexerError#EXCEEDS_MAX_ARRAY_SIZE} | ||
* if the product of the dimensions exceeds max | ||
* int</li> | ||
* </ul> | ||
* | ||
* | ||
*/ | ||
public Indexer3(final int dim1, final int dim2, final int dim3) { | ||
if (dim1 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim2 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim3 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
|
||
try { | ||
p2 = dim3; | ||
p1 = Math.multiplyExact(p2, dim2); | ||
size = Math.multiplyExact(p1, dim1); | ||
} catch (ArithmeticException e) { | ||
throw new ContractException(IndexerError.EXCEEDS_MAX_ARRAY_SIZE); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the combined index = (index1*dim2 +index2)*dim3+index3 from the given | ||
* index values. No validation of the indexes or the result is provided. | ||
*/ | ||
public int index(final int index1, final int index2, final int index3) { | ||
return index1 * p1 + index2 * p2 + index3; | ||
} | ||
|
||
/** | ||
* Returns the size (product of the dimensions) of the array supported by this | ||
* index. | ||
*/ | ||
public int size() { | ||
return size; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package util.indexer; | ||
|
||
import util.errors.ContractException; | ||
|
||
/** | ||
* A thread safe, immutable index converter that supports treating a 4D array as | ||
* a 1D array. | ||
*/ | ||
public final class Indexer4 { | ||
private final int size; | ||
private final int p1; | ||
private final int p2; | ||
private final int p3; | ||
|
||
/** | ||
* Constructs an 4D indexer from the given dimension sizes | ||
* | ||
* @throws ContractException | ||
* <ul> | ||
* <li>{@linkplain IndexerError#NEGATIVE_DIMENSION_SIZE} | ||
* if any dimension has a negative size</li> | ||
* <li>{@linkplain IndexerError#EXCEEDS_MAX_ARRAY_SIZE} | ||
* if the product of the dimensions exceeds max | ||
* int</li> | ||
* </ul> | ||
* | ||
* | ||
*/ | ||
public Indexer4(final int dim1, final int dim2, final int dim3, final int dim4) { | ||
if (dim1 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim2 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim3 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim4 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
|
||
try { | ||
p3 = dim4; | ||
p2 = Math.multiplyExact(p3, dim3); | ||
p1 = Math.multiplyExact(p2, dim2); | ||
size = Math.multiplyExact(p1, dim1); | ||
} catch (ArithmeticException e) { | ||
throw new ContractException(IndexerError.EXCEEDS_MAX_ARRAY_SIZE); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the combined index = ((index1*dim2 +index2)*dim3+index3)*dim4+index4 | ||
* from the given index values. No validation of the indexes or the result is | ||
* provided. | ||
*/ | ||
public int index(final int index1, final int index2, final int index3, final int index4) { | ||
return index1 * p1 + index2 * p2 + index3 * p3 + index4; | ||
} | ||
|
||
/** | ||
* Returns the size (product of the dimensions) of the array supported by this | ||
* index. | ||
*/ | ||
public int size() { | ||
return size; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package util.indexer; | ||
|
||
import util.errors.ContractException; | ||
|
||
/** | ||
* A thread safe, immutable index converter that supports treating a 5D array as | ||
* a 1D array. | ||
*/ | ||
public final class Indexer5 { | ||
private final int size; | ||
private final int p1; | ||
private final int p2; | ||
private final int p3; | ||
private final int p4; | ||
|
||
/** | ||
* Constructs an 5D indexer from the given dimension sizes | ||
* | ||
* @throws ContractException | ||
* <ul> | ||
* <li>{@linkplain IndexerError#NEGATIVE_DIMENSION_SIZE} | ||
* if any dimension has a negative size</li> | ||
* <li>{@linkplain IndexerError#EXCEEDS_MAX_ARRAY_SIZE} | ||
* if the product of the dimensions exceeds max | ||
* int</li> | ||
* </ul> | ||
* | ||
* | ||
*/ | ||
public Indexer5(final int dim1, final int dim2, final int dim3, final int dim4, final int dim5) { | ||
if (dim1 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim2 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim3 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim4 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
if (dim5 < 0) { | ||
throw new ContractException(IndexerError.NEGATIVE_DIMENSION_SIZE); | ||
} | ||
|
||
try { | ||
p4 = dim5; | ||
p3 = Math.multiplyExact(p4, dim4); | ||
p2 = Math.multiplyExact(p3, dim3); | ||
p1 = Math.multiplyExact(p2, dim2); | ||
size = Math.multiplyExact(p1, dim1); | ||
} catch (ArithmeticException e) { | ||
throw new ContractException(IndexerError.EXCEEDS_MAX_ARRAY_SIZE); | ||
} | ||
|
||
} | ||
|
||
/** | ||
* Returns the combined index = (((index1*dim2 | ||
* +index2)*dim3+index3)*dim4+index4)*dim5+index5 from the given index values. | ||
* No validation of the indexes or the result is provided. | ||
*/ | ||
public int index(final int index1, final int index2, final int index3, final int index4, final int index5) { | ||
return index1 * p1 + index2 * p2 + index3 * p3 + index4 * p4 + index5; | ||
} | ||
|
||
/** | ||
* Returns the size (product of the dimensions) of the array supported by this | ||
* index. | ||
*/ | ||
public int size() { | ||
return size; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package util.indexer; | ||
|
||
import util.errors.ContractError; | ||
import util.errors.ContractException; | ||
|
||
/** | ||
* An enumeration supporting {@link ContractException} that acts as a general | ||
* description of the exception. | ||
*/ | ||
public enum IndexerError implements ContractError { | ||
NEGATIVE_DIMENSION_SIZE("Negative dimension size"), | ||
EXCEEDS_MAX_ARRAY_SIZE("The size exceeds max int"), | ||
; | ||
|
||
|
||
|
||
private final String description; | ||
|
||
private IndexerError(final String description) { | ||
this.description = description; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return description; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package util.indexer; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
import org.apache.commons.math3.random.RandomGenerator; | ||
import org.apache.commons.math3.util.FastMath; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import util.annotations.UnitTestConstructor; | ||
import util.annotations.UnitTestMethod; | ||
import util.errors.ContractException; | ||
import util.random.RandomGeneratorProvider; | ||
|
||
public class AT_Indexer2 { | ||
@Test | ||
@UnitTestConstructor(target = Indexer2.class, args = { int.class, int.class }) | ||
public void testIndexer2() { | ||
|
||
// precondition test: if any dimension has a negative size | ||
|
||
ContractException contractException = assertThrows(ContractException.class, () -> new Indexer2(-1, 1)); | ||
assertEquals(IndexerError.NEGATIVE_DIMENSION_SIZE, contractException.getErrorType()); | ||
|
||
contractException = assertThrows(ContractException.class, () -> new Indexer2(1, -1)); | ||
assertEquals(IndexerError.NEGATIVE_DIMENSION_SIZE, contractException.getErrorType()); | ||
|
||
// precondition test: if the product of the dimensions exceeds max int | ||
int n = (int) FastMath.pow(Integer.MAX_VALUE, 1.0 / 2) + 1; | ||
|
||
contractException = assertThrows(ContractException.class, () -> new Indexer2(n, n)); | ||
assertEquals(IndexerError.EXCEEDS_MAX_ARRAY_SIZE, contractException.getErrorType()); | ||
|
||
} | ||
|
||
@Test | ||
@UnitTestMethod(target = Indexer2.class, name = "index", args = { int.class, int.class }) | ||
public void testIndex() { | ||
RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(6937151566492160140L); | ||
|
||
//show that index = index1*dim2+index2 | ||
|
||
for (int i = 0; i < 30; i++) { | ||
int dim1 = randomGenerator.nextInt(30) + 1; | ||
int dim2 = randomGenerator.nextInt(30) + 1; | ||
|
||
Indexer2 indexer2 = new Indexer2(dim1, dim2); | ||
|
||
for (int j = 0; j < 100; j++) { | ||
|
||
int index1 = randomGenerator.nextInt(dim1); | ||
int index2 = randomGenerator.nextInt(dim2); | ||
|
||
assertEquals(index1 * dim2 + index2, indexer2.index(index1, index2)); | ||
} | ||
} | ||
} | ||
|
||
@Test | ||
@UnitTestMethod(target = Indexer2.class, name = "size", args = {}) | ||
public void testSize() { | ||
RandomGenerator randomGenerator = RandomGeneratorProvider.getRandomGenerator(1286993379829775736L); | ||
|
||
for (int i = 0; i < 30; i++) { | ||
int dim1 = randomGenerator.nextInt(30) + 1; | ||
int dim2 = randomGenerator.nextInt(30) + 1; | ||
|
||
Indexer2 indexer2 = new Indexer2(dim1, dim2); | ||
|
||
assertEquals(dim1*dim2, indexer2.size()); | ||
} | ||
} | ||
} |
Oops, something went wrong.