From c74ca83beec04684ab741e5737c35d6b406b8b0d Mon Sep 17 00:00:00 2001
From: jacob
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 26451c1f65c60a3f5e830f006de4cf8f000952a7..2c1d72bc94a95831f2d644265b6fa173f825555a 100644 GIT binary patch delta 25412 zcmZsD1z1#Vw>HcSFhh4q2uOD~NOzZXcStJ|Bdv4~ARyfcNQWRHNSA^jDIwh|BIrM} zeb4uu_guf%z*^6`SFdO98Qin?=VaE&R90MF4KM^74GoHhmRpsI%M3#P7Q6xFRHgHy z3!#WJx-g0qpo^l&0=giI;DWgR3h5ELJ0Sf3vJ5_F6?b8w{>uzP=^MsJ#d*s{O!&w>l_t;9l?p2bxUqqMCZUh#szmt;X
z@QI-RCbk%>v-{wgQq;}(UR2(suCLF%Y@3GR%aVGy1XT|v*O_fqlFk>>{s^H#`<0@{
zd{jwF+ ej|^#4cO-G1ZXBZFbB}x9
z9h!SQ6nhd!Ipy0e<1v*n`FnUTBX8*&_^~!Fe1m9a>|*v>j+`>q23J9FkODG5Peh$x
zx3oS!6vk)>SAT|UndMRRRIui% #4<0UDtqwk|!CTg1gk`A-S+FxBb
z!ib85q(9^kAdWo<0)`_b6L#S1lQ!9N21Dw&eWvt#g}XxC?35y!BwoT(&MG2GOW&rc
zrKz{p&dUXRm{nangb<+)k{lEd?>>9tIi#@O+~#n*nmhBQ`0~Y#GH3Ljr6p`gV{XT4
zUY7jB%=OIP+!FQAz%Y#l!P?=jlBi}0l`K#8Pkk50PCMkkTv)c5-@Y@1W3>)``|dgM
z1hHHw$!J}kcxWAVw&BwJCigpol}avcf=0J2Lj&d{WG0Zq7)wARYEPUDs#rg;-j-j`
z;8XIABO3l7_UKh%5XT8LaN1hCMY~uGOKy?jH`IxJVr1Z#lo{vRsYFR}ukK#bqU&SE
zBK!kxG?K #Xp()kf>RxGOzttMzQ|l^vOc{e?wH3(|om#y;-u%vRHPvmV(j(bMJl$npzzd;aKGZmSku%1d)rmEfZhH>1a+D6YTTD;AbO
zY=15ct%zweSPvKBoAM#y+hKM3WH6}}=Dut&y>38SG0hIh8a(LEK{DHUhWtknf1lA})=Po;_1
zMp)rjw~Jmvi(YE6w=-`&Hbo6S^+Xdyl;t-Dp6@PFiENHqJ>wAOu{E9j#(Mto;8nSb
zBt2U4g5~BD-1BI>H(vtSU&biSrV-27C}+y>LO)8x=kGApyYINsS?>oJwMt>$fxy0g
z+v*ba+o~cHieG8=@N87;eXUeHiZgK>ZSM9FZg>5M-FbNYBkYU+0JrP6w{`C(S-HPj
z%gJG^3omWGR73mv{`R;0#%=w*hF-lwSry_x6kK=xTuUCz!Ty9(=2htWpdT|X9;sl_
z$g^G+Vo%x9xi;K~27@uq<+FJbyYPlK+Efp<&DwB#wHO1_%{BW^2t~S1sWjM~qwEVQ
z^Wn@qG^aFMBP|%GMmIbg9Z^L(poO4$dhHMr3xxGk_n(|$1n=JMIa!pl%H-MX>yEH8
zv6lw(zP|Uq=%nzO*z&`eOC_P6CLV?!>I$mQKR$MXZWfLLvy`tnp)y2ZDT05ZC`bw1g`&Mm
z;6EsbZ
Sd_R0~&
z@ZDA->*eyw&eJyVUl7z{&gxBP{eB8RD7{6m3dI(^a}k7mTA~mo`eqj>(3!|c-BCvR
zQEicET+f*JdnFV5Q{VyY=wZnG10bfJWa1#Yamvb?&hHb>s9|KnHAV(grwGK8-6WeB
z@y^QBpRimnKpRzW&8qG&zx;%&`XI(@{}qz)+*UTsm%n453*zY)R$@sPZRK#t