diff --git a/src/main/java/org/flag4j/arrays/sparse/CooCTensor.java b/src/main/java/org/flag4j/arrays/sparse/CooCTensor.java
index bcd6e0497..b8f5ecfeb 100644
--- a/src/main/java/org/flag4j/arrays/sparse/CooCTensor.java
+++ b/src/main/java/org/flag4j/arrays/sparse/CooCTensor.java
@@ -276,20 +276,21 @@ public CooCTensor reshape(Shape newShape) {
newShape.makeStridesIfNull();
int rank = indices[0].length;
+ int newRank = newShape.getRank();
int nnz = entries.length;
int[] oldStrides = shape.getStrides();
int[] newStrides = newShape.getStrides();
- int[][] newIndices = new int[nnz][rank];
+ int[][] newIndices = new int[nnz][newRank];
- for (int i = 0; i < nnz; i++) {
+ for(int i=0; i
This method transposes the tensor by exchanges the first and last index + * of the tensor. Thus, for a rank 2 tensor, this method is equivalent to a matrix transpose.
+ * + *{@link #T(int, int)} and {@link #T(int...)} offer more general tensor transposes.
* * @return The transpose of this tensor. + * @see #transpose() + * @see #T(int, int) + * @see #T(int...) */ @Override public CooCTensor T() { @@ -870,7 +880,7 @@ public CooCTensor H(int axis1, int axis2) { } // Create sparse coo tensor and sort values lexicographically. - CooCTensor transpose = new CooCTensor(shape, transposeEntries, transposeIndices); + CooCTensor transpose = new CooCTensor(shape.swapAxes(axis1, axis2), transposeEntries, transposeIndices); transpose.sortIndices(); return transpose; @@ -908,7 +918,7 @@ public CooCTensor H(int... axes) { } // Create sparse coo tensor and sort values lexicographically. - CooCTensor transpose = new CooCTensor(shape, transposeEntries, transposeIndices); + CooCTensor transpose = new CooCTensor(shape.swapAxes(axes), transposeEntries, transposeIndices); transpose.sortIndices(); return transpose; diff --git a/src/main/java/org/flag4j/arrays/sparse/CooTensor.java b/src/main/java/org/flag4j/arrays/sparse/CooTensor.java index 3d9872e58..7c1c48ad6 100644 --- a/src/main/java/org/flag4j/arrays/sparse/CooTensor.java +++ b/src/main/java/org/flag4j/arrays/sparse/CooTensor.java @@ -282,12 +282,13 @@ public CooTensor reshape(Shape newShape) { newShape.makeStridesIfNull(); // Ensure this shape object has strides computed. int rank = indices[0].length; + int newRank = newShape.getRank(); int nnz = entries.length; int[] oldStrides = shape.getStrides(); int[] newStrides = newShape.getStrides(); - int[][] newIndices = new int[nnz][rank]; + int[][] newIndices = new int[nnz][newRank]; for (int i = 0; i < nnz; i++) { int flatIndex = 0; @@ -295,7 +296,11 @@ public CooTensor reshape(Shape newShape) { flatIndex += indices[i][j] * oldStrides[j]; } - for (int j = 0; j < rank; j++) { + for (int j = 0; j < newRank; j++) { + int[] arr1 = newIndices[i]; + int v1 = newIndices[i][j]; + int v2 = newStrides[j]; + newIndices[i][j] = flatIndex / newStrides[j]; flatIndex %= newStrides[j]; } @@ -337,6 +342,7 @@ public CooTensor flatten(int axis) { // Compute new shape. int[] destShape = new int[indices[0].length]; + Arrays.fill(destShape, 1); destShape[axis] = shape.totalEntries().intValueExact(); for(int i=0, size=entries.length; iThis method transposes the tensor by exchanges the first and last index + * of the tensor. Thus, for a rank 2 tensor, this method is equivalent to a matrix transpose.
+ * + *{@link #T(int, int)} and {@link #T(int...)} offer more general tensor transposes.
* * @return The transpose of this tensor. * @see #transpose() diff --git a/src/test/java/org/flag4j/sparse_complex_tensor/CooCTensorHermTransposeTests.java b/src/test/java/org/flag4j/sparse_complex_tensor/CooCTensorHermTransposeTests.java new file mode 100644 index 000000000..75340ddff --- /dev/null +++ b/src/test/java/org/flag4j/sparse_complex_tensor/CooCTensorHermTransposeTests.java @@ -0,0 +1,252 @@ +package org.flag4j.sparse_complex_tensor; + +import org.flag4j.arrays.sparse.CooCTensor; +import org.flag4j.complex_numbers.CNumber; +import org.flag4j.core.Shape; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class CooCTensorHermTransposeTests { + static CooCTensor A; + static Shape aShape; + static CNumber[] aEntries; + static int[][] aIndices; + + static CooCTensor exp; + static Shape expShape; + static CNumber[] expEntries; + static int[][] expIndices; + + @Test + void hermTransposeTests() { + // ----------------------- Sub-case 1 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new CNumber[]{new CNumber(0.6522, 0.3289), new CNumber(0.7167, 0.9757), new CNumber(0.7091, 0.0283), new CNumber(0.2897, 0.9174), new CNumber(0.2596, 0.4461), new CNumber(0.4028, 0.9296), new CNumber(0.9347, 0.0967), new CNumber(0.4156, 0.7123), new CNumber(0.5299, 0.2536), new CNumber(0.8344, 0.3449), new CNumber(0.3802, 0.6804)}; + aIndices = new int[][]{ + {0, 0, 0, 0, 2}, + {0, 2, 0, 0, 0}, + {1, 0, 0, 0, 3}, + {1, 1, 0, 0, 1}, + {1, 1, 1, 0, 3}, + {1, 3, 0, 0, 3}, + {1, 3, 1, 0, 4}, + {2, 1, 0, 0, 2}, + {2, 1, 0, 0, 3}, + {2, 1, 1, 0, 3}, + {2, 2, 1, 0, 3}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(5, 4, 2, 1, 3); + expEntries = new CNumber[]{new CNumber(0.7167, -0.9757), new CNumber(0.2897, -0.9174), new CNumber(0.6522, -0.3289), new CNumber(0.4156, -0.7123), new CNumber(0.7091, -0.0283), new CNumber(0.5299, -0.2536), new CNumber(0.2596, -0.4461), new CNumber(0.8344, -0.3449), new CNumber(0.3802, -0.6804), new CNumber(0.4028, -0.9296), new CNumber(0.9347, -0.0967)}; + expIndices = new int[][]{ + {0, 2, 0, 0, 0}, + {1, 1, 0, 0, 1}, + {2, 0, 0, 0, 0}, + {2, 1, 0, 0, 2}, + {3, 0, 0, 0, 1}, + {3, 1, 0, 0, 2}, + {3, 1, 1, 0, 1}, + {3, 1, 1, 0, 2}, + {3, 2, 1, 0, 2}, + {3, 3, 0, 0, 1}, + {4, 3, 1, 0, 1}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.H()); + + // ----------------------- Sub-case 2 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new CNumber[]{new CNumber(0.8546, 0.6631), new CNumber(0.8133, 0.2484), new CNumber(0.0033, 0.7366), new CNumber(0.0844, 0.3648), new CNumber(0.8295, 0.2401), new CNumber(0.1182, 0.7329), new CNumber(0.6894, 0.0494), new CNumber(0.4388, 0.4951), new CNumber(0.8198, 0.6859), new CNumber(0.8987, 0.6718), new CNumber(0.2785, 0.8425)}; + aIndices = new int[][]{ + {0, 2, 0, 0, 1}, + {0, 2, 1, 0, 0}, + {0, 3, 1, 0, 3}, + {1, 0, 0, 0, 3}, + {1, 0, 1, 0, 2}, + {1, 2, 1, 0, 4}, + {1, 3, 1, 0, 3}, + {2, 0, 1, 0, 1}, + {2, 0, 1, 0, 4}, + {2, 1, 1, 0, 0}, + {2, 1, 1, 0, 2}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 4, 3, 1, 5); + expEntries = new CNumber[]{new CNumber(0.0844, -0.3648), new CNumber(0.8546, -0.6631), new CNumber(0.8295, -0.2401), new CNumber(0.4388, -0.4951), new CNumber(0.8198, -0.6859), new CNumber(0.8987, -0.6718), new CNumber(0.2785, -0.8425), new CNumber(0.8133, -0.2484), new CNumber(0.1182, -0.7329), new CNumber(0.0033, -0.7366), new CNumber(0.6894, -0.0494)}; + expIndices = new int[][]{ + {0, 0, 1, 0, 3}, + {0, 2, 0, 0, 1}, + {1, 0, 1, 0, 2}, + {1, 0, 2, 0, 1}, + {1, 0, 2, 0, 4}, + {1, 1, 2, 0, 0}, + {1, 1, 2, 0, 2}, + {1, 2, 0, 0, 0}, + {1, 2, 1, 0, 4}, + {1, 3, 0, 0, 3}, + {1, 3, 1, 0, 3}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + + assertEquals(exp, A.H(0, 2)); + assertEquals(exp, A.H(2, 0)); + + // ----------------------- Sub-case 3 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new CNumber[]{new CNumber(0.2252, 0.8303), new CNumber(0.7022, 0.9162), new CNumber(0.6672, 0.2974), new CNumber(0.4421, 0.7193), new CNumber(0.3796, 0.9056), new CNumber(0.2784, 0.3588), new CNumber(0.3264, 0.909), new CNumber(0.1959, 0.2546), new CNumber(0.7772, 0.396), new CNumber(0.2936, 0.491), new CNumber(0.5877, 0.1148)}; + aIndices = new int[][]{ + {0, 0, 0, 0, 2}, + {0, 0, 1, 0, 2}, + {0, 3, 0, 0, 2}, + {1, 0, 1, 0, 1}, + {1, 0, 1, 0, 4}, + {1, 2, 1, 0, 4}, + {2, 0, 0, 0, 0}, + {2, 0, 1, 0, 2}, + {2, 2, 1, 0, 0}, + {2, 3, 1, 0, 2}, + {2, 3, 1, 0, 3}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(3, 1, 5, 4, 2); + expEntries = new CNumber[]{new CNumber(0.2252, -0.8303), new CNumber(0.7022, -0.9162), new CNumber(0.6672, -0.2974), new CNumber(0.4421, -0.7193), new CNumber(0.3796, -0.9056), new CNumber(0.2784, -0.3588), new CNumber(0.3264, -0.909), new CNumber(0.7772, -0.396), new CNumber(0.1959, -0.2546), new CNumber(0.2936, -0.491), new CNumber(0.5877, -0.1148)}; + expIndices = new int[][]{ + {0, 0, 2, 0, 0}, + {0, 0, 2, 0, 1}, + {0, 0, 2, 3, 0}, + {1, 0, 1, 0, 1}, + {1, 0, 4, 0, 1}, + {1, 0, 4, 2, 1}, + {2, 0, 0, 0, 0}, + {2, 0, 0, 2, 1}, + {2, 0, 2, 0, 1}, + {2, 0, 2, 3, 1}, + {2, 0, 3, 3, 1}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + + assertEquals(exp, A.H(0, 3, 4, 1, 2)); + + // ----------------------- Sub-case 4 ----------------------- + assertThrows(IllegalArgumentException.class, ()->A.H(0, 1, 3, 2)); + assertThrows(IllegalArgumentException.class, ()->A.H(0, 3, 4, 1, 2, 5)); + assertThrows(IllegalArgumentException.class, ()->A.H(0, 3, -4, 1, 2)); + assertThrows(IllegalArgumentException.class, ()->A.H(0, 15, 4, 1, 2)); + assertThrows(IndexOutOfBoundsException.class, ()->A.H(5, 1)); + } + + + @Test + void transposeTests() { + // ----------------------- Sub-case 1 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new CNumber[]{new CNumber(0.9613, 0.238), new CNumber(0.9947, 0.4532), new CNumber(0.1439, 0.7333), new CNumber(0.2738, 0.7492), new CNumber(0.0159, 0.6496), new CNumber(0.44, 0.5992), new CNumber(0.2544, 0.174), new CNumber(0.0317, 0.3052), new CNumber(0.3788, 0.4169), new CNumber(0.2586, 0.7146), new CNumber(0.148, 0.1819)}; + aIndices = new int[][]{ + {0, 0, 0, 0, 4}, + {0, 0, 1, 0, 1}, + {0, 1, 0, 0, 2}, + {0, 1, 1, 0, 3}, + {1, 1, 1, 0, 0}, + {1, 1, 1, 0, 4}, + {1, 2, 0, 0, 4}, + {1, 2, 1, 0, 1}, + {1, 2, 1, 0, 4}, + {2, 0, 1, 0, 4}, + {2, 1, 1, 0, 4}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(5, 4, 2, 1, 3); + expEntries = new CNumber[]{new CNumber(0.0159, 0.6496), new CNumber(0.9947, 0.4532), new CNumber(0.0317, 0.3052), new CNumber(0.1439, 0.7333), new CNumber(0.2738, 0.7492), new CNumber(0.9613, 0.238), new CNumber(0.2586, 0.7146), new CNumber(0.44, 0.5992), new CNumber(0.148, 0.1819), new CNumber(0.2544, 0.174), new CNumber(0.3788, 0.4169)}; + expIndices = new int[][]{ + {0, 1, 1, 0, 1}, + {1, 0, 1, 0, 0}, + {1, 2, 1, 0, 1}, + {2, 1, 0, 0, 0}, + {3, 1, 1, 0, 0}, + {4, 0, 0, 0, 0}, + {4, 0, 1, 0, 2}, + {4, 1, 1, 0, 1}, + {4, 1, 1, 0, 2}, + {4, 2, 0, 0, 1}, + {4, 2, 1, 0, 1}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.T()); + + // ----------------------- Sub-case 2 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new CNumber[]{new CNumber(0.5902, 0.9131), new CNumber(0.3367, 0.9463), new CNumber(0.4198, 0.1293), new CNumber(0.6835, 0.2796), new CNumber(0.5134, 0.2389), new CNumber(0.7717, 0.3427), new CNumber(0.7304, 0.4389), new CNumber(0.4974, 0.184), new CNumber(0.1768, 0.9627), new CNumber(0.5433, 0.2314), new CNumber(0.9679, 0.4831)}; + aIndices = new int[][]{ + {0, 1, 0, 0, 3}, + {0, 1, 1, 0, 4}, + {0, 2, 0, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 0, 0, 2}, + {1, 2, 0, 0, 3}, + {1, 3, 0, 0, 0}, + {2, 1, 0, 0, 4}, + {2, 1, 1, 0, 0}, + {2, 2, 0, 0, 3}, + {2, 3, 0, 0, 4}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 4, 3, 1, 5); + expEntries = new CNumber[]{new CNumber(0.6835, 0.2796), new CNumber(0.5134, 0.2389), new CNumber(0.5902, 0.9131), new CNumber(0.4974, 0.184), new CNumber(0.4198, 0.1293), new CNumber(0.7717, 0.3427), new CNumber(0.5433, 0.2314), new CNumber(0.7304, 0.4389), new CNumber(0.9679, 0.4831), new CNumber(0.3367, 0.9463), new CNumber(0.1768, 0.9627)}; + expIndices = new int[][]{ + {0, 0, 1, 0, 1}, + {0, 0, 1, 0, 2}, + {0, 1, 0, 0, 3}, + {0, 1, 2, 0, 4}, + {0, 2, 0, 0, 1}, + {0, 2, 1, 0, 3}, + {0, 2, 2, 0, 3}, + {0, 3, 1, 0, 0}, + {0, 3, 2, 0, 4}, + {1, 1, 0, 0, 4}, + {1, 1, 2, 0, 0}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + + assertEquals(exp, A.T(0, 2)); + assertEquals(exp, A.T(2, 0)); + + // ----------------------- Sub-case 3 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new CNumber[]{new CNumber(0.8834, 0.1986), new CNumber(0.3184, 0.3042), new CNumber(0.8551, 0.4776), new CNumber(0.7626, 0.7819), new CNumber(0.1152, 0.4055), new CNumber(0.6564, 0.7552), new CNumber(0.3097, 0.5647), new CNumber(0.3279, 0.7208), new CNumber(0.4838, 0.6065), new CNumber(0.8963, 0.7191), new CNumber(0.2443, 0.4567)}; + aIndices = new int[][]{ + {0, 0, 0, 0, 3}, + {0, 0, 1, 0, 0}, + {0, 1, 0, 0, 4}, + {0, 2, 0, 0, 2}, + {1, 0, 0, 0, 3}, + {1, 2, 0, 0, 0}, + {1, 2, 1, 0, 3}, + {2, 1, 1, 0, 4}, + {2, 2, 0, 0, 4}, + {2, 2, 1, 0, 0}, + {2, 3, 1, 0, 1}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(3, 1, 5, 4, 2); + expEntries = new CNumber[]{new CNumber(0.3184, 0.3042), new CNumber(0.7626, 0.7819), new CNumber(0.8834, 0.1986), new CNumber(0.8551, 0.4776), new CNumber(0.6564, 0.7552), new CNumber(0.1152, 0.4055), new CNumber(0.3097, 0.5647), new CNumber(0.8963, 0.7191), new CNumber(0.2443, 0.4567), new CNumber(0.3279, 0.7208), new CNumber(0.4838, 0.6065)}; + expIndices = new int[][]{ + {0, 0, 0, 0, 1}, + {0, 0, 2, 2, 0}, + {0, 0, 3, 0, 0}, + {0, 0, 4, 1, 0}, + {1, 0, 0, 2, 0}, + {1, 0, 3, 0, 0}, + {1, 0, 3, 2, 1}, + {2, 0, 0, 2, 1}, + {2, 0, 1, 3, 1}, + {2, 0, 4, 1, 1}, + {2, 0, 4, 2, 0}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + + assertEquals(exp, A.T(0, 3, 4, 1, 2)); + + // ----------------------- Sub-case 4 ----------------------- + assertThrows(IllegalArgumentException.class, ()->A.T(0, 1, 3, 2)); + assertThrows(IllegalArgumentException.class, ()->A.T(0, 3, 4, 1, 2, 5)); + assertThrows(IllegalArgumentException.class, ()->A.T(0, 3, -4, 1, 2)); + assertThrows(IllegalArgumentException.class, ()->A.T(0, 15, 4, 1, 2)); + assertThrows(IndexOutOfBoundsException.class, ()->A.T(5, 1)); + } +} diff --git a/src/test/java/org/flag4j/sparse_complex_tensor/CooCTensorReshapeTests.java b/src/test/java/org/flag4j/sparse_complex_tensor/CooCTensorReshapeTests.java new file mode 100644 index 000000000..39df27aba --- /dev/null +++ b/src/test/java/org/flag4j/sparse_complex_tensor/CooCTensorReshapeTests.java @@ -0,0 +1,218 @@ +package org.flag4j.sparse_complex_tensor; + +import org.flag4j.arrays.sparse.CooCTensor; +import org.flag4j.complex_numbers.CNumber; +import org.flag4j.core.Shape; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CooCTensorReshapeTests { + static CooCTensor A; + static Shape aShape; + static CNumber[] aEntries; + static int[][] aIndices; + + static CooCTensor exp; + static Shape expShape; + static CNumber[] expEntries; + static int[][] expIndices; + + @Test + void reshapeTests() { + // -------------------------- Sub-case 1 -------------------------- + aShape = new Shape(5, 4, 2, 1); + aEntries = new CNumber[]{new CNumber(0.2856, 0.1775), new CNumber(0.2455, 0.6139), new CNumber(0.9386, 0.8602), new CNumber(0.194, 0.921), new CNumber(0.8078, 0.4986), new CNumber(0.359, 0.5673)}; + aIndices = new int[][]{ + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + {3, 3, 0, 0}, + {4, 3, 0, 0}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 5, 2, 2); + expEntries = new CNumber[]{new CNumber(0.2856, 0.1775), new CNumber(0.2455, 0.6139), new CNumber(0.9386, 0.8602), new CNumber(0.194, 0.921), new CNumber(0.8078, 0.4986), new CNumber(0.359, 0.5673)}; + expIndices = new int[][]{ + {0, 0, 0, 0}, + {0, 0, 0, 1}, + {1, 0, 0, 1}, + {1, 0, 1, 1}, + {1, 2, 1, 0}, + {1, 4, 1, 0}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.reshape(2, 5, 2, 2)); + + // ----------------------------- Sub-case 2 ----------------------------- + aShape = new Shape(5, 4, 2, 3, 15); + aEntries = new CNumber[]{new CNumber(0.8103, 0.0203), new CNumber(0.5684, 0.4151), new CNumber(0.9044, 0.8734), new CNumber(0.201, 0.7032), new CNumber(0.9682, 0.2723), new CNumber(0.4699, 0.8203), new CNumber(0.3871, 0.3395), new CNumber(0.7851, 0.3768), new CNumber(0.2315, 0.7695), new CNumber(0.8333, 0.8837), new CNumber(0.0398, 0.559), new CNumber(0.0405, 0.9707), new CNumber(0.488, 0.8343), new CNumber(0.2441, 0.7806), new CNumber(0.3995, 0.6793), new CNumber(0.3689, 0.6126), new CNumber(0.0767, 0.9631), new CNumber(0.8007, 0.4023)}; + aIndices = new int[][]{ + {0, 0, 0, 0, 0}, + {0, 1, 0, 0, 7}, + {0, 2, 1, 2, 4}, + {0, 3, 0, 0, 11}, + {0, 3, 1, 0, 10}, + {0, 3, 1, 2, 6}, + {1, 1, 1, 0, 7}, + {2, 0, 0, 0, 8}, + {2, 0, 0, 0, 10}, + {2, 2, 0, 2, 12}, + {2, 2, 1, 1, 6}, + {3, 0, 0, 0, 2}, + {3, 0, 1, 1, 1}, + {4, 0, 0, 2, 10}, + {4, 0, 1, 0, 7}, + {4, 2, 1, 1, 8}, + {4, 3, 0, 0, 6}, + {4, 3, 1, 2, 13}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(15, 2, 4, 15); + expEntries = new CNumber[]{new CNumber(0.8103, 0.0203), new CNumber(0.5684, 0.4151), new CNumber(0.9044, 0.8734), new CNumber(0.201, 0.7032), new CNumber(0.9682, 0.2723), new CNumber(0.4699, 0.8203), new CNumber(0.3871, 0.3395), new CNumber(0.7851, 0.3768), new CNumber(0.2315, 0.7695), new CNumber(0.8333, 0.8837), new CNumber(0.0398, 0.559), new CNumber(0.0405, 0.9707), new CNumber(0.488, 0.8343), new CNumber(0.2441, 0.7806), new CNumber(0.3995, 0.6793), new CNumber(0.3689, 0.6126), new CNumber(0.0767, 0.9631), new CNumber(0.8007, 0.4023)}; + expIndices = new int[][]{ + {0, 0, 0, 0}, + {0, 1, 2, 7}, + {2, 0, 1, 4}, + {2, 0, 2, 11}, + {2, 1, 1, 10}, + {2, 1, 3, 6}, + {4, 0, 1, 7}, + {6, 0, 0, 8}, + {6, 0, 0, 10}, + {7, 1, 2, 12}, + {8, 0, 0, 6}, + {9, 0, 0, 2}, + {9, 1, 0, 1}, + {12, 0, 2, 10}, + {12, 0, 3, 7}, + {14, 0, 0, 8}, + {14, 0, 2, 6}, + {14, 1, 3, 13}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.reshape(15, 2, 4, 15)); + + // ----------------------------- Sub-case 3 ----------------------------- + aShape = new Shape(3, 16); + aShape = new Shape(3, 16); + aEntries = new CNumber[]{new CNumber(0.5938, 0.762), new CNumber(0.4295, 0.7988), new CNumber(0.0332, 0.3233), new CNumber(0.7022, 0.1686), new CNumber(0.7114, 0.6353), new CNumber(0.5935, 0.0851), new CNumber(0.7148, 0.5695)}; + aIndices = new int[][]{ + {1, 5}, + {1, 14}, + {1, 15}, + {2, 0}, + {2, 2}, + {2, 3}, + {2, 10}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 4, 3, 2); + expEntries = new CNumber[]{new CNumber(0.5938, 0.762), new CNumber(0.4295, 0.7988), new CNumber(0.0332, 0.3233), new CNumber(0.7022, 0.1686), new CNumber(0.7114, 0.6353), new CNumber(0.5935, 0.0851), new CNumber(0.7148, 0.5695)}; + expIndices = new int[][]{ + {0, 3, 1, 1}, + {1, 1, 0, 0}, + {1, 1, 0, 1}, + {1, 1, 1, 0}, + {1, 1, 2, 0}, + {1, 1, 2, 1}, + {1, 3, 0, 0}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.reshape(2, 4, 3, 2)); + + // ----------------------------- Sub-case 4 ----------------------------- + assertThrows(IllegalArgumentException.class, ()->A.reshape(150, 12)); + } + + + @Test + void flattenTests() { + // -------------------------- Sub-case 1 -------------------------- + aShape = new Shape(3, 16); + aEntries = new CNumber[]{ + new CNumber(1, -2), new CNumber(9.145, 0.00013), + new CNumber(234), new CNumber(0, 15)}; + aIndices = new int[][]{ + {0, 4}, + {0, 7}, + {1, 9}, + {2, 10}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(48); + expEntries = new CNumber[]{new CNumber(1, -2), new CNumber(9.145, 0.00013), + new CNumber(234), new CNumber(0, 15)}; + expIndices = new int[][]{ + {4}, + {7}, + {25}, + {42}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten()); + + // -------------------------- Sub-case 2 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new CNumber[]{new CNumber(0, 15), new CNumber(0), new CNumber(-9, 154)}; + aIndices = new int[][]{ + {0, 1, 3}, + {1, 0, 1}, + {1, 1, 0}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(24); + expEntries = new CNumber[]{new CNumber(0, 15), new CNumber(0), new CNumber(-9, 154)}; + expIndices = new int[][]{ + {7}, + {9}, + {12}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten()); + + // -------------------------- Sub-case 3 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new CNumber[]{new CNumber(0, 15), new CNumber(2), new CNumber(-9, 154)}; + aIndices = new int[][]{ + {1, 0, 1}, + {1, 1, 1}, + {2, 0, 1}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(1, 24, 1); + expEntries = new CNumber[]{new CNumber(0, 15), new CNumber(2), new CNumber(-9, 154)}; + expIndices = new int[][]{ + {0, 9, 0}, + {0, 13, 0}, + {0, 17, 0}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten(1)); + + // -------------------------- Sub-case 4 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new CNumber[]{new CNumber(0, 15), new CNumber(234), new CNumber(-9, 154)}; + aIndices = new int[][]{ + {1, 0, 1}, + {1, 1, 1}, + {2, 0, 1}}; + A = new CooCTensor(aShape, aEntries, aIndices); + + expShape = new Shape(1, 1, 24); + expEntries = new CNumber[]{new CNumber(0, 15), new CNumber(234), new CNumber(-9, 154)}; + expIndices = new int[][]{ + {0, 0, 9}, + {0, 0, 13}, + {0, 0, 17}}; + exp = new CooCTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten(2)); + + // -------------------------- Sub-case 5 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new CNumber[]{new CNumber(0, 15), new CNumber(234), new CNumber(-9, 154)}; + aIndices = new int[][]{ + {1, 0, 1}, + {1, 1, 1}, + {2, 0, 1}}; + A = new CooCTensor(aShape, aEntries, aIndices); + assertThrows(IndexOutOfBoundsException.class, ()->A.flatten(5)); + assertThrows(IndexOutOfBoundsException.class, ()->A.flatten(-1)); + } +} diff --git a/src/test/java/org/flag4j/sparse_tensor/CooTensorReshapeTests.java b/src/test/java/org/flag4j/sparse_tensor/CooTensorReshapeTests.java new file mode 100644 index 000000000..f2dfe6567 --- /dev/null +++ b/src/test/java/org/flag4j/sparse_tensor/CooTensorReshapeTests.java @@ -0,0 +1,209 @@ +package org.flag4j.sparse_tensor; + +import org.flag4j.arrays.sparse.CooTensor; +import org.flag4j.core.Shape; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CooTensorReshapeTests { + static CooTensor A; + static Shape aShape; + static double[] aEntries; + static int[][] aIndices; + + static CooTensor exp; + static Shape expShape; + static double[] expEntries; + static int[][] expIndices; + + @Test + void reshapeTests() { + // -------------------------- Sub-case 1 -------------------------- + aShape = new Shape(5, 4, 2, 1); + aEntries = new double[]{-0.2594625644447393, -0.11800739013805872, -1.8499182919471657}; + aIndices = new int[][]{ + {2, 2, 0, 0}, + {2, 3, 0, 0}, + {4, 1, 1, 0}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 5, 2, 2); + expEntries = new double[]{-0.2594625644447393, -0.11800739013805872, -1.8499182919471657}; + expIndices = new int[][]{ + {1, 0, 0, 0}, + {1, 0, 1, 0}, + {1, 3, 1, 1}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.reshape(2, 5, 2, 2)); + + // ----------------------------- Sub-case 2 ----------------------------- + aShape = new Shape(5, 4, 2, 3, 15); + aEntries = new double[]{-1.1499856217218563, -0.33276615768221923, -1.7712698524382784, 0.45988194186997083, -1.0000258840502727, -1.2896045900552038, -1.0495292341142137, 0.5653540034076624, 0.09844833075965526, 1.389726418783007, -0.03253455760212258, 0.8128434562240154, -0.5805363805458708, -0.9687145707590211, 0.005130776492485523, -1.1693463926292427, -0.18736097719279932, -0.588774063376806}; + aIndices = new int[][]{ + {0, 2, 1, 2, 8}, + {1, 0, 0, 0, 2}, + {1, 1, 0, 1, 9}, + {1, 2, 0, 2, 13}, + {1, 3, 1, 1, 3}, + {1, 3, 1, 1, 7}, + {2, 0, 0, 1, 9}, + {2, 2, 1, 0, 11}, + {2, 3, 1, 2, 10}, + {3, 0, 0, 1, 13}, + {3, 0, 1, 0, 6}, + {3, 1, 0, 0, 10}, + {3, 1, 1, 1, 9}, + {4, 0, 1, 0, 9}, + {4, 1, 1, 0, 14}, + {4, 2, 0, 0, 8}, + {4, 3, 0, 2, 6}, + {4, 3, 1, 2, 12}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(15, 2, 4, 15); + expEntries = new double[]{-1.1499856217218563, -0.33276615768221923, -1.7712698524382784, 0.45988194186997083, -1.0000258840502727, -1.2896045900552038, -1.0495292341142137, 0.5653540034076624, 0.09844833075965526, 1.389726418783007, -0.03253455760212258, 0.8128434562240154, -0.5805363805458708, -0.9687145707590211, 0.005130776492485523, -1.1693463926292427, -0.18736097719279932, -0.588774063376806}; + expIndices = new int[][]{ + {2, 0, 1, 8}, + {3, 0, 0, 2}, + {3, 1, 3, 9}, + {4, 1, 2, 13}, + {5, 1, 2, 3}, + {5, 1, 2, 7}, + {6, 0, 1, 9}, + {7, 1, 3, 11}, + {8, 1, 3, 10}, + {9, 0, 1, 13}, + {9, 0, 3, 6}, + {9, 1, 2, 10}, + {10, 0, 2, 9}, + {12, 0, 3, 9}, + {13, 0, 1, 14}, + {13, 1, 0, 8}, + {14, 1, 0, 6}, + {14, 1, 3, 12}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.reshape(15, 2, 4, 15)); + + // ----------------------------- Sub-case 3 ----------------------------- + aShape = new Shape(3, 16); + aEntries = new double[]{-0.5564583772612858, 1.3880160320768695, -0.041746799108138805, 0.22670438356409295}; + aIndices = new int[][]{ + {0, 7}, + {0, 8}, + {0, 15}, + {1, 7}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 4, 3, 2); + expEntries = new double[]{-0.5564583772612858, 1.3880160320768695, -0.041746799108138805, 0.22670438356409295}; + expIndices = new int[][]{ + {0, 1, 0, 1}, + {0, 1, 1, 0}, + {0, 2, 1, 1}, + {0, 3, 2, 1}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.reshape(2, 4, 3, 2)); + + // ----------------------------- Sub-case 4 ----------------------------- + aShape = new Shape(3, 16); + aEntries = new double[]{-0.5564583772612858, 1.3880160320768695, -0.041746799108138805, 0.22670438356409295}; + aIndices = new int[][]{ + {0, 7}, + {0, 8}, + {0, 15}, + {1, 7}}; + A = new CooTensor(aShape, aEntries, aIndices); + assertThrows(IllegalArgumentException.class, ()->A.reshape(150, 12)); + } + + + @Test + void flattenTests() { + // -------------------------- Sub-case 1 -------------------------- + aShape = new Shape(3, 16); + aEntries = new double[]{-0.4396095255063526, -0.008544443239199374, 1.6354416874939133, -0.7535470743266395}; + aIndices = new int[][]{ + {0, 4}, + {0, 7}, + {1, 9}, + {2, 10}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(48); + expEntries = new double[]{-0.4396095255063526, -0.008544443239199374, 1.6354416874939133, -0.7535470743266395}; + expIndices = new int[][]{ + {4}, + {7}, + {25}, + {42}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten()); + + // -------------------------- Sub-case 2 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new double[]{0.8809801303815625, 1.2884192212811383, 0.6540684159095426}; + aIndices = new int[][]{ + {0, 1, 3}, + {1, 0, 1}, + {1, 1, 0}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(24); + expEntries = new double[]{0.8809801303815625, 1.2884192212811383, 0.6540684159095426}; + expIndices = new int[][]{ + {7}, + {9}, + {12}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten()); + + // -------------------------- Sub-case 3 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new double[]{-0.2100281314624281, 1.4401356481011265, -0.1396976427551165}; + aIndices = new int[][]{ + {1, 0, 1}, + {1, 1, 1}, + {2, 0, 1}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(1, 24, 1); + expEntries = new double[]{-0.2100281314624281, 1.4401356481011265, -0.1396976427551165}; + expIndices = new int[][]{ + {0, 9, 0}, + {0, 13, 0}, + {0, 17, 0}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten(1)); + + // -------------------------- Sub-case 4 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new double[]{-0.2100281314624281, 1.4401356481011265, -0.1396976427551165}; + aIndices = new int[][]{ + {1, 0, 1}, + {1, 1, 1}, + {2, 0, 1}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(1, 1, 24); + expEntries = new double[]{-0.2100281314624281, 1.4401356481011265, -0.1396976427551165}; + expIndices = new int[][]{ + {0, 0, 9}, + {0, 0, 13}, + {0, 0, 17}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.flatten(2)); + + // -------------------------- Sub-case 5 -------------------------- + aShape = new Shape(3, 2, 4); + aEntries = new double[]{-0.2100281314624281, 1.4401356481011265, -0.1396976427551165}; + aIndices = new int[][]{ + {1, 0, 1}, + {1, 1, 1}, + {2, 0, 1}}; + A = new CooTensor(aShape, aEntries, aIndices); + assertThrows(IndexOutOfBoundsException.class, ()->A.flatten(5)); + assertThrows(IndexOutOfBoundsException.class, ()->A.flatten(-1)); + } +} diff --git a/src/test/java/org/flag4j/sparse_tensor/CooTensorTransposeTests.java b/src/test/java/org/flag4j/sparse_tensor/CooTensorTransposeTests.java new file mode 100644 index 000000000..b875ee008 --- /dev/null +++ b/src/test/java/org/flag4j/sparse_tensor/CooTensorTransposeTests.java @@ -0,0 +1,147 @@ +package org.flag4j.sparse_tensor; + +import org.flag4j.arrays.sparse.CooTensor; +import org.flag4j.core.Shape; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class CooTensorTransposeTests { + static CooTensor A; + static Shape aShape; + static double[] aEntries; + static int[][] aIndices; + + static CooTensor exp; + static Shape expShape; + static double[] expEntries; + static int[][] expIndices; + + @Test + void transposeTests() { + // ----------------------- Sub-case 1 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new double[]{0.3369876012099134, -1.2778944176165061, 0.3003526634585191, -2.871698370528301, -0.7476330328637798, 0.0005862743350540067, 0.27050784380653264, -0.8804057494085602, 0.3433759561302188, -0.6271337465977211, -0.535101554634142, -1.9109729935630098, 0.7218896402785697, 0.8404528180001959, 0.5203214826154133, 0.3371173022767966, -0.6726729311708143, 0.08353784066932919}; + aIndices = new int[][]{ + {0, 0, 1, 0, 1}, + {0, 1, 1, 0, 4}, + {0, 2, 0, 0, 0}, + {0, 2, 1, 0, 1}, + {0, 3, 0, 0, 2}, + {1, 1, 0, 0, 0}, + {1, 1, 1, 0, 0}, + {1, 1, 1, 0, 2}, + {1, 2, 1, 0, 0}, + {1, 2, 1, 0, 4}, + {2, 0, 0, 0, 0}, + {2, 0, 0, 0, 4}, + {2, 0, 1, 0, 4}, + {2, 1, 0, 0, 0}, + {2, 1, 1, 0, 1}, + {2, 1, 1, 0, 3}, + {2, 1, 1, 0, 4}, + {2, 3, 0, 0, 2}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(5, 4, 2, 1, 3); + expEntries = new double[]{-0.535101554634142, 0.0005862743350540067, 0.8404528180001959, 0.27050784380653264, 0.3003526634585191, 0.3433759561302188, 0.3369876012099134, 0.5203214826154133, -2.871698370528301, -0.8804057494085602, -0.7476330328637798, 0.08353784066932919, 0.3371173022767966, -1.9109729935630098, 0.7218896402785697, -1.2778944176165061, -0.6726729311708143, -0.6271337465977211}; + expIndices = new int[][]{ + {0, 0, 0, 0, 2}, + {0, 1, 0, 0, 1}, + {0, 1, 0, 0, 2}, + {0, 1, 1, 0, 1}, + {0, 2, 0, 0, 0}, + {0, 2, 1, 0, 1}, + {1, 0, 1, 0, 0}, + {1, 1, 1, 0, 2}, + {1, 2, 1, 0, 0}, + {2, 1, 1, 0, 1}, + {2, 3, 0, 0, 0}, + {2, 3, 0, 0, 2}, + {3, 1, 1, 0, 2}, + {4, 0, 0, 0, 2}, + {4, 0, 1, 0, 2}, + {4, 1, 1, 0, 0}, + {4, 1, 1, 0, 2}, + {4, 2, 1, 0, 1}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.T()); + + // ----------------------- Sub-case 2 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new double[]{0.5495928325292689, -0.4063964781150276, -2.059856306563159, 0.21626315719045072, 0.700470594502127, -0.9551549318514719, 0.20625241662218816, -0.002902831572102285, 0.027379206391192006, -0.048618618464467335, -0.062183293526625626}; + aIndices = new int[][]{ + {0, 1, 0, 0, 1}, + {0, 1, 0, 0, 2}, + {0, 1, 1, 0, 3}, + {1, 0, 1, 0, 0}, + {1, 1, 0, 0, 0}, + {1, 2, 0, 0, 1}, + {2, 0, 1, 0, 1}, + {2, 0, 1, 0, 3}, + {2, 0, 1, 0, 4}, + {2, 1, 1, 0, 3}, + {2, 2, 1, 0, 1}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(2, 4, 3, 1, 5); + expEntries = new double[]{0.5495928325292689, -0.4063964781150276, 0.700470594502127, -0.9551549318514719, 0.21626315719045072, 0.20625241662218816, -0.002902831572102285, 0.027379206391192006, -2.059856306563159, -0.048618618464467335, -0.062183293526625626}; + expIndices = new int[][]{ + {0, 1, 0, 0, 1}, + {0, 1, 0, 0, 2}, + {0, 1, 1, 0, 0}, + {0, 2, 1, 0, 1}, + {1, 0, 1, 0, 0}, + {1, 0, 2, 0, 1}, + {1, 0, 2, 0, 3}, + {1, 0, 2, 0, 4}, + {1, 1, 0, 0, 3}, + {1, 1, 2, 0, 3}, + {1, 2, 2, 0, 1}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.T(0, 2)); + assertEquals(exp, A.T(2, 0)); + + // ----------------------- Sub-case 3 ----------------------- + aShape = new Shape(3, 4, 2, 1, 5); + aEntries = new double[]{0.7755080687938627, -0.35048451266628083, -1.1870851252844012, 0.7738863613063384, 1.486547192285357, 0.2252740863565129, -0.2975058226231608, -0.09472050340155494, -0.15340207810250436, 2.84248590850813, -1.7279407634814916}; + aIndices = new int[][]{ + {0, 1, 0, 0, 2}, + {0, 1, 0, 0, 3}, + {0, 1, 1, 0, 2}, + {0, 3, 1, 0, 1}, + {1, 0, 0, 0, 2}, + {1, 1, 1, 0, 0}, + {2, 0, 0, 0, 0}, + {2, 0, 0, 0, 3}, + {2, 3, 0, 0, 0}, + {2, 3, 0, 0, 1}, + {2, 3, 1, 0, 0}}; + A = new CooTensor(aShape, aEntries, aIndices); + + expShape = new Shape(3, 1, 5, 4, 2); + expEntries = new double[]{0.7738863613063384, 0.7755080687938627, -1.1870851252844012, -0.35048451266628083, 0.2252740863565129, 1.486547192285357, -0.2975058226231608, -0.15340207810250436, -1.7279407634814916, 2.84248590850813, -0.09472050340155494}; + expIndices = new int[][]{ + {0, 0, 1, 3, 1}, + {0, 0, 2, 1, 0}, + {0, 0, 2, 1, 1}, + {0, 0, 3, 1, 0}, + {1, 0, 0, 1, 1}, + {1, 0, 2, 0, 0}, + {2, 0, 0, 0, 0}, + {2, 0, 0, 3, 0}, + {2, 0, 0, 3, 1}, + {2, 0, 1, 3, 0}, + {2, 0, 3, 0, 0}}; + exp = new CooTensor(expShape, expEntries, expIndices); + assertEquals(exp, A.T(0, 3, 4, 1, 2)); + + // ----------------------- Sub-case 4 ----------------------- + assertThrows(IllegalArgumentException.class, ()->A.T(0, 1, 3, 2)); + assertThrows(IllegalArgumentException.class, ()->A.T(0, 3, 4, 1, 2, 5)); + assertThrows(IllegalArgumentException.class, ()->A.T(0, 3, -4, 1, 2)); + assertThrows(IllegalArgumentException.class, ()->A.T(0, 15, 4, 1, 2)); + assertThrows(IndexOutOfBoundsException.class, ()->A.T(5, 1)); + } +} diff --git a/target/flag4j-v0.1.0-beta.jar b/target/flag4j-v0.1.0-beta.jar index 26451c1f6..2c1d72bc9 100644 Binary files a/target/flag4j-v0.1.0-beta.jar and b/target/flag4j-v0.1.0-beta.jar differ