diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d769462 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2af576d --- /dev/null +++ b/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + org.example + MultiDim + 1.0-SNAPSHOT + + + 20 + 20 + UTF-8 + + + + + org.junit.jupiter + junit-jupiter-engine + 5.9.3 + test + + + org.openjdk.jmh + jmh-core + 1.36 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.36 + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 9 + 9 + 9 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + benchmark + + + org.openjdk.jmh.Main + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/github/shautvast/multidim/Int2dArray.class b/src/main/java/com/github/shautvast/multidim/Int2dArray.class new file mode 100644 index 0000000..de1ec81 Binary files /dev/null and b/src/main/java/com/github/shautvast/multidim/Int2dArray.class differ diff --git a/src/main/java/com/github/shautvast/multidim/Int2dArray.java b/src/main/java/com/github/shautvast/multidim/Int2dArray.java new file mode 100644 index 0000000..8af9a4c --- /dev/null +++ b/src/main/java/com/github/shautvast/multidim/Int2dArray.java @@ -0,0 +1,30 @@ +package com.github.shautvast.multidim; + +/** + * Any dimensional int array, stored as an int[] + * No runtime checks! Easy to shoot yourself in the foot! + */ +public class Int2dArray { + private final int[] data; + private int cols; + + public Int2dArray(int rows, int cols) { + data = new int[rows * cols]; + this.cols = cols; + } + + public int get(int row, int col) { + return row * cols + col; + } + + public void set(int row, int col, int val) { + data[row * cols + col] = val; + } + + int internalSize() { + return data.length; + } + + +} + diff --git a/src/main/java/com/github/shautvast/multidim/IntArray.java b/src/main/java/com/github/shautvast/multidim/IntArray.java new file mode 100644 index 0000000..701bee5 --- /dev/null +++ b/src/main/java/com/github/shautvast/multidim/IntArray.java @@ -0,0 +1,62 @@ +package com.github.shautvast.multidim; + +/** + * Any dimensional int array, stored as an int[] + * No runtime checks! Easy to shoot yourself in the foot! + */ +public class IntArray { + private final int[] data; + private final int[] dims; + + public IntArray(int... dims) { + if (dims.length < 1) { + throw new IllegalArgumentException("array cannot have " + dims.length + " dimensions"); + } + this.dims = dims; + int size = 1; + for (int dim : dims) { + size *= dim; + } + data = new int[size]; + } + + public int get(int... coords) { + if (coords.length < 1) { + throw new IllegalArgumentException("must supply at least one coordinate"); + } + int index = 0; + if (coords.length > 1) { + for (int i = coords.length - 2; i >= 0; i--) { + index += coords[i] * dims[i + 1]; + } + } + + return data[index + coords[coords.length - 1]]; + } + + /** + * 'smart' use of varargs int: first values are the coordinates, last is the value itself + * + * @param coordsVal, all coordinates and the value to set + */ + public void set(int... coordsVal) { + if (coordsVal.length < 2) { + throw new IllegalArgumentException("must supply at least one coordinate and a value to set"); + } + int index = 0; + if (coordsVal.length > 2) { + for (int i = coordsVal.length - 3; i >= 0; i--) { + index += coordsVal[i] * dims[i + 1]; + } + } + + data[index + coordsVal[coordsVal.length - 2]] = coordsVal[coordsVal.length - 1]; + } + + int internalSize() { + return data.length; + } + + +} + diff --git a/src/main/java/com/github/shautvast/multidim/JmhBenchmark.java b/src/main/java/com/github/shautvast/multidim/JmhBenchmark.java new file mode 100644 index 0000000..e8cebb7 --- /dev/null +++ b/src/main/java/com/github/shautvast/multidim/JmhBenchmark.java @@ -0,0 +1,130 @@ +package com.github.shautvast.multidim; + +import org.openjdk.jmh.annotations.*; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 1) +public class JmhBenchmark { + + private static final int ROWS = 100; + private static final int COLS = 100; + + + @org.openjdk.jmh.annotations.State(Scope.Thread) + public static class State { + Int2dArray seqInt2DArray; + IntArray intArray; + int[][] ints; + + @Setup(Level.Iteration) + public void doSetup() { + long seed = System.currentTimeMillis(); + Random random = new Random(seed); + ints = new int[COLS][ROWS]; + intArray = new IntArray(COLS, ROWS); + seqInt2DArray = new Int2dArray(COLS, ROWS); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int i = random.nextInt(); + intArray.set(r, c, i); + seqInt2DArray.set(r, c, i); + } + } + } + + } + + //@Benchmark + public Int2dArray seq2DArraySetTDLR(State state) { + Int2dArray d2Array = new Int2dArray(ROWS, COLS); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + d2Array.set(r, c, r * c); + } + } + return d2Array; + } + + //@Benchmark + public int[][] classicArraySet(State state) { + int[][] d2Array = new int[ROWS][COLS]; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + d2Array[r][c] = r * c; + } + } + return d2Array; + } + + @Benchmark + public int classicArrayGetTDLR(State state) { + int t = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + t += state.ints[r][c]; + } + } + + return t; + } + + @Benchmark + public int classicArrayGetLRTD(State state) { + int t = 0; + for (int c = 0; c < COLS; c++) { + for (int r = 0; r < ROWS; r++) { + t += state.ints[r][c]; + } + } + return t; + } + +// @Benchmark + public int seq2DArrayGetTDLR(State state) { + int t = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + t += state.seqInt2DArray.get(r, c); + } + } + return t; + } + + //@Benchmark + public int seq2DArrayGetLRTD(State state) { + int t = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + t += state.seqInt2DArray.get(r, c); + } + } + return t; + } + + //@Benchmark + public int seqMultArrayGetLRTD(State state) { + int t = 0xFFFFFFFF; + for (int c = 0; c < COLS; c++) { + for (int r = 0; r < ROWS; r++) { + t = state.intArray.get(r, c); + } + } + return t; + } + + //@Benchmark + public int seqMultArrayGetTDLR(State state) { + int t = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + t = state.intArray.get(r, c); + } + } + return t; + } +} \ No newline at end of file diff --git a/src/test/java/com/github/shautvast/multidim/IntArrayTest.java b/src/test/java/com/github/shautvast/multidim/IntArrayTest.java new file mode 100644 index 0000000..3108289 --- /dev/null +++ b/src/test/java/com/github/shautvast/multidim/IntArrayTest.java @@ -0,0 +1,28 @@ +package com.github.shautvast.multidim; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class IntArrayTest { + @Test + void test() { + IntArray intArray = new IntArray(2, 3, 5); + assertEquals(30, intArray.internalSize()); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 5; k++) { + intArray.set(i, j, k, 2 * 3 * i + 3 * j + k); + } + } + } + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 3; j++) { + for (int k = 0; k < 5; k++) { + assertEquals(2 * 3 * i, 3 * j + k, intArray.get(i, j, k)); + } + } + } + } +}