You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@systemds.apache.org by "fzoepffel (via GitHub)" <gi...@apache.org> on 2024/01/15 18:19:54 UTC

[PR] DML Integration of FFT and IFFT [systemds]

fzoepffel opened a new pull request, #1983:
URL: https://github.com/apache/systemds/pull/1983

   ## Overview 
   
   Java functions for FFT and IFFT for one and 2dimensional inputs were added and integrated into DML.  The IFFT and FFT DML functions both are currently only implemented for real inputs. An exemplory dml script can be found in tmp/test.dml. 
   
   ## Testing
    Tests were added, as well. One test is meant to compare the correctness and speed of the FFT implementation with the corresponding numpy implementation. To run this test (to be found in FourierTestWithFiles.java) run the python script in FourierTestData.py and copy the generated files to the root of the project.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460445086


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 
+    // and add the generated files to the root of the project.
+    @Test
+    public void testFftWithNumpyData() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]);
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            MatrixBlock[] actualBlocks = fft(input);
+            long endTime = System.nanoTime();
+
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in): Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+
+            // Validate the FFT results
+            validateFftResults(expected, actualBlocks, lineNumber);
+        }
+
+        reader.close();
+        
+    }
+
+    private void validateFftResults(double[][] expected, MatrixBlock[] actualBlocks, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualBlocks[0].getValueDenseUnsafe(0, i);
+            double imagActual = actualBlocks[1].getValueDenseUnsafe(0, i);
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("fft(double[][][] in): Finished processing line " + lineNumber);
+        }
+        
+    }
+
+    @Test
+    public void testFftExecutionTime() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]); // Real part
+                input[1][0][i] = Double.parseDouble(values[n + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            fft(input, false);
+            long endTime = System.nanoTime();
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in, boolean calcInv) Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+        }
+
+        reader.close();
+    }
+
+    @Test
+    public void testFftExecutionTimeOfOneDimFFT() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 2;
+            double[][] input = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][i] = Double.parseDouble(values[i]); // Real part
+                input[1][i] = Double.parseDouble(values[n + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            fft_one_dim(input);
+            long endTime = System.nanoTime();
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft_one_dim: Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s ");
+                }
+            }
+        }
+
+        reader.close();
+    }
+
+
+    // prior to executing this test it is necessary to run the Numpy Script in FourierTestData.py and add the generated file to the root of the project.
+    @Test
+    public void testIfftWithRealNumpyData() throws IOException {
+        String filename = "ifft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+    
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+    
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]); // Real part of input
+                // Imaginary part of input is assumed to be 0
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part of expected output
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part of expected output
+            }
+    
+            double[][][] actualResult = fft(input, true); // Perform IFFT
+        
+            // Validate the IFFT results
+            validateFftResults(expected, actualResult, lineNumber);
+        }
+    
+        reader.close();
+    }
+    
+    private void validateFftResults(double[][] expected, double[][][] actualResult, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualResult[0][0][i];
+            double imagActual = actualResult[1][0][i];
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("ifft(real input): Finished processing line " + lineNumber);
+        }
+        
+    }
+    
+
+
+    @Test
+public void testIfftWithComplexNumpyData() throws IOException {

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460442035


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443130


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443130


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443505


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460441630


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -252,6 +258,25 @@ private static EigenDecomposition computeEigenRegularized(MatrixBlock in) {
 			DataConverter.convertToArray2DRowRealMatrix(in2));
 	}
 
+	private static MatrixBlock[] computeFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false) )
+			throw new DMLRuntimeException("Invalid empty block");
+
+		//run fft
+		return fft(in);
+	}
+
+	private static MatrixBlock[] computeIFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false))
+			throw new DMLRuntimeException("Invalid empty block");
+		int rows = in.getNumRows();
+		int cols = in.getNumColumns();
+
+		MatrixBlock inIm = new MatrixBlock(rows, cols, new double[cols*rows]);

Review Comment:
   TODO: two inputs from DML
   remaining resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460440574


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -49,6 +49,8 @@
 import org.apache.sysds.runtime.matrix.operators.BinaryOperator;
 import org.apache.sysds.runtime.util.DataConverter;
 
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444772


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();
+        }
+
+        for(int k = 0; k < 2 ; k++){
+            for(int i = 0; i < res[0].length; i++) {
+                assertArrayEquals(expected[k][i], res[k][i], 0.0001);
+            }
+        }
+    }
+
+    @Test
+    public void simple_test_one_dim_ifft() {
+
+        double[][] in = {{1, -2, 3, -4},{0, 0, 0, 0}};
+
+        double[][] res_fft = fft_one_dim(in);
+        double[][] res = ifft_one_dim(res_fft);
+
+        assertArrayEquals(in[0], res[0], 0.0001);
+        assertArrayEquals(in[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void matrix_block_one_dim_test(){
+
+        double[] in = {0, 18, -15, 3};
+
+        double[] expected_re = {6,15,-36,15};
+        double[] expected_im = {0,-15,0,15};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(expected_re, res_re, 0.0001);
+        assertArrayEquals(expected_im, res_im, 0.0001);
+    }
+    @Test
+    public void matrix_block_two_dim_test(){
+
+        double[][][] in = {{{0, 18},{-15, 3}}};
+
+        double[] flattened_expected_re = {6,-36, 30,0};
+        double[] flattened_expected_im = {0,0,0,0};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(flattened_expected_re, res_re, 0.0001);
+        assertArrayEquals(flattened_expected_im, res_im, 0.0001);
+    }
+
+}

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460442196


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444347


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};

Review Comment:
   resolved



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();

Review Comment:
   resolved



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443775


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460441756


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444933


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "fzoepffel (via GitHub)" <gi...@apache.org>.
fzoepffel commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1461655069


##########
src/main/java/org/apache/sysds/runtime/instructions/cp/MultiReturnBuiltinCPInstruction.java:
##########
@@ -90,6 +90,23 @@ else if ( opcode.equalsIgnoreCase("eigen") ) {
 			return new MultiReturnBuiltinCPInstruction(null, in1, outputs, opcode, str);
 			
 		}
+		else if ( opcode.equalsIgnoreCase("fft") ) {
+			// one input and two outputs
+			CPOperand in1 = new CPOperand(parts[1]);
+			outputs.add ( new CPOperand(parts[2], ValueType.FP64, DataType.MATRIX) );
+			outputs.add ( new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX) );
+
+			return new MultiReturnBuiltinCPInstruction(null, in1, outputs, opcode, str);
+
+		}		
+		else if ( opcode.equalsIgnoreCase("ifft") ) {
+			// one input and two outputs
+			CPOperand in1 = new CPOperand(parts[1]);
+			outputs.add ( new CPOperand(parts[2], ValueType.FP64, DataType.MATRIX) );
+			outputs.add ( new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX) );
+
+			return new MultiReturnBuiltinCPInstruction(null, in1, outputs, opcode, str);

Review Comment:
   ifft is not handled here anymore. Instead a new MultiReturnComplexMatrixBuiltinCPInstruction was added to allow for 1 or 2 inputs for ifft. 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "j143 (via GitHub)" <gi...@apache.org>.
j143 commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1934115318

   Hello @fzoepffel , @jessicapriebe -- Thanks a lot for contributing to SystemDS. 😄 ✨ 
   
   
   Hi @Baunsgaard -- will it be good for 3.2.0 release? thanks. Will be announcing code freeze tomorrow.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1495091532


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -440,4 +444,18 @@ public static MatrixBlock[] ifft_linearized(MatrixBlock re, int threads) {
 			threads);
 	}
 
+	private static double sin(double angle){
+		if (!sinCache.containsKey(angle)) {

Review Comment:
   I think my comment was unclear.
   
   1. You should reuse the same cached hash map every invocation.
   2. The soft reference is just wrapping your allocated caches.
   3. Because it takes extra time to get your cached angles (the HashMap) out of the soft reference, we need to get it out at a different location. Therefore i suggested to materialize it as a variable inside "fft_one_dim_sub", meaning taking it out of the soft reference there, or materializing a new hash map if the soft reference is empty.
   
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444347


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444171


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443973


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "j143 (via GitHub)" <gi...@apache.org>.
j143 commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1999826299

   Hi @jessicapriebe thanks for addressing the comments.
   
   If this changeset has the sufficient functionality, it can be merged.
   
   And we can add subsequent improvements with new PRs.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard closed pull request #1983: [SYSTEMDS-3685] DML Integration of FFT and IFFT
URL: https://github.com/apache/systemds/pull/1983


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-2037691429

   Thank you for the PR, 
   While merging I have fixed the parallelization threads propagation through the compiler.
   Future work is to fix the STFT, to integrate with the DML language again, since this did not merge nicely, and add documentation for the existence of FFT and STFT. in the dml language reference docs.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "fzoepffel (via GitHub)" <gi...@apache.org>.
fzoepffel commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1934106230

   The remaining conflicts were just resolved. Now the PR should be ready to merge. Further validation(e.g. empty inputs, differing dimensions of imaginary and real inputs, etc.)  and minor bug fixes like the handling of only zero input matrices will come in a separate PR for the integrated python tests. Currently the workflows are waiting for this PR are awaiting approval.  Hopefully the integrationtests that were failing before will succeed now. We are assuming that these integration tests are not related to us. Please let us know if you think differently. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "fzoepffel (via GitHub)" <gi...@apache.org>.
fzoepffel commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1934494397

   > > The remaining conflicts were just resolved. Now the PR should be ready to merge. Further validation(e.g. empty inputs, differing dimensions of imaginary and real inputs, etc.) and minor bug fixes like the handling of only zero input matrices will come in a separate PR for the integrated python tests. Currently the workflows are waiting for this PR are awaiting approval. Hopefully the integrationtests that were failing before will succeed now. We are assuming that these integration tests are not related to us. Please let us know if you think differently.
   > 
   > Hi @fzoepffel
   > 
   > The code passes all tests, great.
   > 
   > I think your codeformatter ran in many of the PR files. Can we revert this? We try to avoid formatting existing files (even if the format is wrong) unless we do major changes.
   
   I just saw. I am a little unsure however, how I can revert this. When I run the formatter (which I configured to use the CodeStyle_eclipse.xml file) it does not necessarily reverse to what it was before. Could it be that some of the files had not been formatted accordingly before? And should these still be reversed now? 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460442979


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){
+
+        int rows = in[0].length;
+
+        double[][] col = new double[2][rows];
+        // get row
+        for (int i = 0; i < rows; i++){
+            for( int k = 0; k < 2; k++){
+                col[k][i] = in[k][i][j];
+            }
+        }
+        return col;
+    }
+
+    private static boolean isPowerOfTwo(int n){
+        return ((n != 0) && ((n & (n - 1)) == 0)) || n == 1;
+    }
+
+    public static MatrixBlock[] fft(double[] in){
+        double[][][] arr = new double[2][1][in.length];
+        arr[0][0] = in;
+        return fft(convertToMatrixBlocks(arr));
+    }
+
+    public static MatrixBlock[] fft(double[][][] in){
+        return fft(convertToMatrixBlocks(in));
+    }
+
+    public static MatrixBlock[] fft(MatrixBlock[] in){
+        return fft(in[0], in[1]);
+    }
+
+    public static MatrixBlock[] fft(MatrixBlock re){
+        return fft(re, getZeroMatrixBlock(re.getNumRows(), re.getNumColumns()));

Review Comment:
   we didn't used new MatrixBlock(rows,cols, true), bc .getDenseBlockValues returned null
   but we resolved it otherwise



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460440699


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -71,7 +73,7 @@ public static boolean isSupportedUnaryOperation( String opcode ) {
 	}
 	
 	public static boolean isSupportedMultiReturnOperation( String opcode ) {
-		return ( opcode.equals("qr") || opcode.equals("lu") || opcode.equals("eigen") || opcode.equals("svd") );
+		return ( opcode.equals("qr") || opcode.equals("lu") || opcode.equals("eigen") || opcode.equals("fft") || opcode.equals("ifft") || opcode.equals("svd") );

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -252,6 +258,25 @@ private static EigenDecomposition computeEigenRegularized(MatrixBlock in) {
 			DataConverter.convertToArray2DRowRealMatrix(in2));
 	}
 
+	private static MatrixBlock[] computeFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false) )
+			throw new DMLRuntimeException("Invalid empty block");
+
+		//run fft

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443198


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443505


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444395


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444832


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-2023066179

   Taking over the merge of this PR in #2009


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1492390108


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+
+public class LibMatrixFourier {
+
+	/**
+	 * Function to perform FFT for two given matrices. The first one represents the real values and the second one the
+	 * imaginary values. The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		fft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, true);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform IFFT for two given matrices. The first one represents the real values and the second one the
+	 * imaginary values. The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		ifft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, true);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform FFT for each row of two given matrices. The first one represents the real values and the
+	 * second one the imaginary values. The output also contains one matrix for the real and one for the imaginary
+	 * values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] fft_linearized(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		fft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, false);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform IFFT for each row of two given matrices. The first one represents the real values and the
+	 * second one the imaginary values. The output also contains one matrix for the real and one for the imaginary
+	 * values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] ifft_linearized(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		ifft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, false);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform FFT for two given double arrays. The first one represents the real values and the second one
+	 * the imaginary values. Both arrays get updated and contain the result.
+	 *
+	 * @param re          array representing the real values
+	 * @param im          array representing the imaginary values
+	 * @param rows        number of rows
+	 * @param cols        number of rows
+	 * @param inclColCalc if true, fft is also calculated for each column, otherwise only for each row
+	 */
+	public static void fft(double[] re, double[] im, int rows, int cols, boolean inclColCalc) {
+
+		double[] re_inter = new double[rows * cols];
+		double[] im_inter = new double[rows * cols];
+
+		for(int i = 0; i < rows; i++) {
+			fft_one_dim(re, im, re_inter, im_inter, i * cols, (i + 1) * cols, cols, 1);
+		}
+
+		if(inclColCalc) {
+			for(int j = 0; j < cols; j++) {
+				fft_one_dim(re, im, re_inter, im_inter, j, j + rows * cols, rows, cols);
+			}
+		}
+
+	}
+
+	/**
+	 * Function to perform IFFT for two given double arrays. The first one represents the real values and the second one
+	 * the imaginary values. Both arrays get updated and contain the result.
+	 *
+	 * @param re          array representing the real values
+	 * @param im          array representing the imaginary values
+	 * @param rows        number of rows
+	 * @param cols        number of rows
+	 * @param inclColCalc if true, fft is also calculated for each column, otherwise only for each row
+	 */
+	public static void ifft(double[] re, double[] im, int rows, int cols, boolean inclColCalc) {
+
+		double[] re_inter = new double[rows * cols];
+		double[] im_inter = new double[rows * cols];
+
+		if(inclColCalc) {
+			for(int j = 0; j < cols; j++) {
+				ifft_one_dim(re, im, re_inter, im_inter, j, j + rows * cols, rows, cols);
+			}
+		}
+
+		for(int i = 0; i < rows; i++) {
+			ifft_one_dim(re, im, re_inter, im_inter, i * cols, (i + 1) * cols, cols, 1);

Review Comment:
   full example of parallel execution: 
   https://github.com/apache/systemds/blob/f4b7a47cbba9951210eef45263dc4a927b59225c/src/main/java/org/apache/sysds/runtime/frame/data/lib/FrameLibDetectSchema.java#L84



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443238


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460442273


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460440184


##########
pom.xml:
##########
@@ -875,6 +875,12 @@
 	</profiles>
 
 	<dependencies>
+		<dependency>
+			<groupId>org.json</groupId>
+				<artifactId>json</artifactId>
+			<version>20210307</version>
+		</dependency>

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444607


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();
+        }
+
+        for(int k = 0; k < 2 ; k++){
+            for(int i = 0; i < res[0].length; i++) {
+                assertArrayEquals(expected[k][i], res[k][i], 0.0001);
+            }
+        }
+    }
+
+    @Test
+    public void simple_test_one_dim_ifft() {
+
+        double[][] in = {{1, -2, 3, -4},{0, 0, 0, 0}};
+
+        double[][] res_fft = fft_one_dim(in);
+        double[][] res = ifft_one_dim(res_fft);
+
+        assertArrayEquals(in[0], res[0], 0.0001);
+        assertArrayEquals(in[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void matrix_block_one_dim_test(){
+
+        double[] in = {0, 18, -15, 3};
+
+        double[] expected_re = {6,15,-36,15};
+        double[] expected_im = {0,-15,0,15};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(expected_re, res_re, 0.0001);
+        assertArrayEquals(expected_im, res_im, 0.0001);
+    }
+    @Test

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444447


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444772


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();
+        }
+
+        for(int k = 0; k < 2 ; k++){
+            for(int i = 0; i < res[0].length; i++) {
+                assertArrayEquals(expected[k][i], res[k][i], 0.0001);
+            }
+        }
+    }
+
+    @Test
+    public void simple_test_one_dim_ifft() {
+
+        double[][] in = {{1, -2, 3, -4},{0, 0, 0, 0}};
+
+        double[][] res_fft = fft_one_dim(in);
+        double[][] res = ifft_one_dim(res_fft);
+
+        assertArrayEquals(in[0], res[0], 0.0001);
+        assertArrayEquals(in[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void matrix_block_one_dim_test(){
+
+        double[] in = {0, 18, -15, 3};
+
+        double[] expected_re = {6,15,-36,15};
+        double[] expected_im = {0,-15,0,15};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(expected_re, res_re, 0.0001);
+        assertArrayEquals(expected_im, res_im, 0.0001);
+    }
+    @Test
+    public void matrix_block_two_dim_test(){
+
+        double[][][] in = {{{0, 18},{-15, 3}}};
+
+        double[] flattened_expected_re = {6,-36, 30,0};
+        double[] flattened_expected_im = {0,0,0,0};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(flattened_expected_re, res_re, 0.0001);
+        assertArrayEquals(flattened_expected_im, res_im, 0.0001);
+    }
+
+}

Review Comment:
   resolved



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444607


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();
+        }
+
+        for(int k = 0; k < 2 ; k++){
+            for(int i = 0; i < res[0].length; i++) {
+                assertArrayEquals(expected[k][i], res[k][i], 0.0001);
+            }
+        }
+    }
+
+    @Test
+    public void simple_test_one_dim_ifft() {
+
+        double[][] in = {{1, -2, 3, -4},{0, 0, 0, 0}};
+
+        double[][] res_fft = fft_one_dim(in);
+        double[][] res = ifft_one_dim(res_fft);
+
+        assertArrayEquals(in[0], res[0], 0.0001);
+        assertArrayEquals(in[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void matrix_block_one_dim_test(){
+
+        double[] in = {0, 18, -15, 3};
+
+        double[] expected_re = {6,15,-36,15};
+        double[] expected_im = {0,-15,0,15};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(expected_re, res_re, 0.0001);
+        assertArrayEquals(expected_im, res_im, 0.0001);
+    }
+    @Test

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460441630


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -252,6 +258,25 @@ private static EigenDecomposition computeEigenRegularized(MatrixBlock in) {
 			DataConverter.convertToArray2DRowRealMatrix(in2));
 	}
 
+	private static MatrixBlock[] computeFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false) )
+			throw new DMLRuntimeException("Invalid empty block");
+
+		//run fft
+		return fft(in);
+	}
+
+	private static MatrixBlock[] computeIFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false))
+			throw new DMLRuntimeException("Invalid empty block");
+		int rows = in.getNumRows();
+		int cols = in.getNumColumns();
+
+		MatrixBlock inIm = new MatrixBlock(rows, cols, new double[cols*rows]);

Review Comment:
   TODO: two inputs from DML
   remaining resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444171


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "fzoepffel (via GitHub)" <gi...@apache.org>.
fzoepffel commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1467604744


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 
+    // and add the generated files to the root of the project.
+    @Test
+    public void testFftWithNumpyData() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]);
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            MatrixBlock[] actualBlocks = fft(input);
+            long endTime = System.nanoTime();
+
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in): Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+
+            // Validate the FFT results
+            validateFftResults(expected, actualBlocks, lineNumber);
+        }
+
+        reader.close();
+        
+    }
+
+    private void validateFftResults(double[][] expected, MatrixBlock[] actualBlocks, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualBlocks[0].getValueDenseUnsafe(0, i);
+            double imagActual = actualBlocks[1].getValueDenseUnsafe(0, i);
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("fft(double[][][] in): Finished processing line " + lineNumber);
+        }
+        
+    }
+
+    @Test
+    public void testFftExecutionTime() throws IOException {

Review Comment:
   this will be done in the PR for the python tests



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1934355601

   > The remaining conflicts were just resolved. Now the PR should be ready to merge. Further validation(e.g. empty inputs, differing dimensions of imaginary and real inputs, etc.) and minor bug fixes like the handling of only zero input matrices will come in a separate PR for the integrated python tests. Currently the workflows are waiting for this PR are awaiting approval. Hopefully the integrationtests that were failing before will succeed now. We are assuming that these integration tests are not related to us. Please let us know if you think differently.
   
   Hi @fzoepffel 
   
   The code passes all tests, great.
   
   I think your codeformatter ran in many of the PR files. Can we revert this?
   We try to avoid formatting existing files (even if the format is wrong) unless we do major changes.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1934508053

   > > > The remaining conflicts were just resolved. Now the PR should be ready to merge. Further validation(e.g. empty inputs, differing dimensions of imaginary and real inputs, etc.) and minor bug fixes like the handling of only zero input matrices will come in a separate PR for the integrated python tests. Currently the workflows are waiting for this PR are awaiting approval. Hopefully the integrationtests that were failing before will succeed now. We are assuming that these integration tests are not related to us. Please let us know if you think differently.
   > > 
   > > 
   > > Hi @fzoepffel
   > > The code passes all tests, great.
   > > I think your codeformatter ran in many of the PR files. Can we revert this? We try to avoid formatting existing files (even if the format is wrong) unless we do major changes.
   > 
   > I just saw. I am a little unsure however, how I can revert this. When I run the formatter (which I configured to use the CodeStyle_eclipse.xml file) it does not necessarily reverse to what it was before.
   
   The files was just not formatted before. Not everyone formats the files, and we have some legacy/old code that we would rather have refer to the original authors rather than change the format of it. Therefore i have configured my IDE only for format on request not automatically.
   
   A concrete way of handling it is a bit more tricky. I suggest going back through commits and figuring out which commit did the formatting, and then revert the formatting without breaking the changes that you wanted to do. There probably is a smarter way, but I am unaware of such.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460442225


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443775


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;

Review Comment:
   resolved



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460445086


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 
+    // and add the generated files to the root of the project.
+    @Test
+    public void testFftWithNumpyData() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]);
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            MatrixBlock[] actualBlocks = fft(input);
+            long endTime = System.nanoTime();
+
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in): Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+
+            // Validate the FFT results
+            validateFftResults(expected, actualBlocks, lineNumber);
+        }
+
+        reader.close();
+        
+    }
+
+    private void validateFftResults(double[][] expected, MatrixBlock[] actualBlocks, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualBlocks[0].getValueDenseUnsafe(0, i);
+            double imagActual = actualBlocks[1].getValueDenseUnsafe(0, i);
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("fft(double[][][] in): Finished processing line " + lineNumber);
+        }
+        
+    }
+
+    @Test
+    public void testFftExecutionTime() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]); // Real part
+                input[1][0][i] = Double.parseDouble(values[n + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            fft(input, false);
+            long endTime = System.nanoTime();
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in, boolean calcInv) Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+        }
+
+        reader.close();
+    }
+
+    @Test
+    public void testFftExecutionTimeOfOneDimFFT() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 2;
+            double[][] input = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][i] = Double.parseDouble(values[i]); // Real part
+                input[1][i] = Double.parseDouble(values[n + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            fft_one_dim(input);
+            long endTime = System.nanoTime();
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft_one_dim: Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s ");
+                }
+            }
+        }
+
+        reader.close();
+    }
+
+
+    // prior to executing this test it is necessary to run the Numpy Script in FourierTestData.py and add the generated file to the root of the project.
+    @Test
+    public void testIfftWithRealNumpyData() throws IOException {
+        String filename = "ifft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+    
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+    
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]); // Real part of input
+                // Imaginary part of input is assumed to be 0
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part of expected output
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part of expected output
+            }
+    
+            double[][][] actualResult = fft(input, true); // Perform IFFT
+        
+            // Validate the IFFT results
+            validateFftResults(expected, actualResult, lineNumber);
+        }
+    
+        reader.close();
+    }
+    
+    private void validateFftResults(double[][] expected, double[][][] actualResult, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualResult[0][0][i];
+            double imagActual = actualResult[1][0][i];
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("ifft(real input): Finished processing line " + lineNumber);
+        }
+        
+    }
+    
+
+
+    @Test
+public void testIfftWithComplexNumpyData() throws IOException {

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1452814727


##########
src/main/java/org/apache/sysds/parser/BuiltinFunctionExpression.java:
##########
@@ -355,6 +355,62 @@ public void validateExpression(MultiAssignmentStatement stmt, HashMap<String, Da
 			
 			break;
 		}
+		case FFT: 
+		{
+			checkNumParameters(1);
+			checkMatrixParam(getFirstExpr());
+
+			// setup output properties
+			DataIdentifier fftOut1 = (DataIdentifier) getOutputs()[0];
+			DataIdentifier fftOut2 = (DataIdentifier) getOutputs()[1];
+			
+			// if (getFirstExpr().getOutput().getDim2() != 1 ||  getFirstExpr().getOutput().getDim2() != 2) {
+			// 	raiseValidateError("Eigen Decomposition can only be done on a square matrix. Input matrix is rectangular (rows=" + getFirstExpr().getOutput().getDim1() + ", cols="+ getFirstExpr().getOutput().getDim2() +")", conditional);
+			// }

Review Comment:
   initially change this to a TODO: add verification check.



##########
pom.xml:
##########
@@ -875,6 +875,12 @@
 	</profiles>
 
 	<dependencies>
+		<dependency>
+			<groupId>org.json</groupId>
+				<artifactId>json</artifactId>
+			<version>20210307</version>
+		</dependency>

Review Comment:
   use Jackson instead if you need to parse JSON, we use the Jackson dependency already.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;

Review Comment:
   license missing



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -252,6 +258,25 @@ private static EigenDecomposition computeEigenRegularized(MatrixBlock in) {
 			DataConverter.convertToArray2DRowRealMatrix(in2));
 	}
 
+	private static MatrixBlock[] computeFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false) )
+			throw new DMLRuntimeException("Invalid empty block");
+
+		//run fft

Review Comment:
   add a sparseToDense call.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();

Review Comment:
   this also allocate.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;

Review Comment:
   license



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */

Review Comment:
   java doc require you to define  `param`  and `returns`, see other java doc examples.
   
   I suggest adding it for all public methods.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestData.py:
##########
@@ -0,0 +1,165 @@
+import numpy as np

Review Comment:
   add license, if we want to keep this file.
   
   Unfortunately it is complicated  for us to run this script before we run the Fourier test, and therefore
   the tests would not parse in the cloud because of missing input.
   
   We need to decided what to do. 
   
   1. include the generated files in git. (i can live with this if they are fairly small, but i would prefer not to)
   2. Move the tests to execute fully in our PythonAPI, this would be cool, but some effort to write new test cases there, and add a shallow wrapper fft function (3-8 lines of code). If you want to do this i can help out quickly in  a call to fix it.
   3. Remove it and use smaller controlled test cases in the java test that have known outputs that you hard code (we need a few more of these hard coded cases anyway in my opinion )



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();

Review Comment:
   allocate



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 
+    // and add the generated files to the root of the project.
+    @Test
+    public void testFftWithNumpyData() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]);
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            MatrixBlock[] actualBlocks = fft(input);
+            long endTime = System.nanoTime();
+
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in): Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+
+            // Validate the FFT results
+            validateFftResults(expected, actualBlocks, lineNumber);
+        }
+
+        reader.close();
+        
+    }
+
+    private void validateFftResults(double[][] expected, MatrixBlock[] actualBlocks, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualBlocks[0].getValueDenseUnsafe(0, i);
+            double imagActual = actualBlocks[1].getValueDenseUnsafe(0, i);
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("fft(double[][][] in): Finished processing line " + lineNumber);
+        }
+        
+    }
+
+    @Test
+    public void testFftExecutionTime() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]); // Real part
+                input[1][0][i] = Double.parseDouble(values[n + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            fft(input, false);
+            long endTime = System.nanoTime();
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in, boolean calcInv) Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+        }
+
+        reader.close();
+    }
+
+    @Test
+    public void testFftExecutionTimeOfOneDimFFT() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 2;
+            double[][] input = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][i] = Double.parseDouble(values[i]); // Real part
+                input[1][i] = Double.parseDouble(values[n + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            fft_one_dim(input);
+            long endTime = System.nanoTime();
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft_one_dim: Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s ");
+                }
+            }
+        }
+
+        reader.close();
+    }
+
+
+    // prior to executing this test it is necessary to run the Numpy Script in FourierTestData.py and add the generated file to the root of the project.
+    @Test
+    public void testIfftWithRealNumpyData() throws IOException {
+        String filename = "ifft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+    
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+    
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]); // Real part of input
+                // Imaginary part of input is assumed to be 0
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part of expected output
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part of expected output
+            }
+    
+            double[][][] actualResult = fft(input, true); // Perform IFFT
+        
+            // Validate the IFFT results
+            validateFftResults(expected, actualResult, lineNumber);
+        }
+    
+        reader.close();
+    }
+    
+    private void validateFftResults(double[][] expected, double[][][] actualResult, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualResult[0][0][i];
+            double imagActual = actualResult[1][0][i];
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("ifft(real input): Finished processing line " + lineNumber);
+        }
+        
+    }
+    
+
+
+    @Test
+public void testIfftWithComplexNumpyData() throws IOException {

Review Comment:
   indentation



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];

Review Comment:
   if possible can we use the already allocated res matrix, and index into cells not calculated yet? 



##########
src/main/java/org/apache/sysds/runtime/instructions/cp/MultiReturnBuiltinCPInstruction.java:
##########
@@ -90,6 +90,23 @@ else if ( opcode.equalsIgnoreCase("eigen") ) {
 			return new MultiReturnBuiltinCPInstruction(null, in1, outputs, opcode, str);
 			
 		}
+		else if ( opcode.equalsIgnoreCase("fft") ) {
+			// one input and two outputs
+			CPOperand in1 = new CPOperand(parts[1]);
+			outputs.add ( new CPOperand(parts[2], ValueType.FP64, DataType.MATRIX) );
+			outputs.add ( new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX) );
+
+			return new MultiReturnBuiltinCPInstruction(null, in1, outputs, opcode, str);
+
+		}		
+		else if ( opcode.equalsIgnoreCase("ifft") ) {
+			// one input and two outputs
+			CPOperand in1 = new CPOperand(parts[1]);
+			outputs.add ( new CPOperand(parts[2], ValueType.FP64, DataType.MATRIX) );
+			outputs.add ( new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX) );
+
+			return new MultiReturnBuiltinCPInstruction(null, in1, outputs, opcode, str);

Review Comment:
   these two can probably share code.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);

Review Comment:
   This is a good change but we need to change a few things. 
   
   The convertToArray together with convertToMatrixBlocks is dominating the execution time,
   since the implementation now allocate new double[][] arrays in the size of input and output, and then convert the output once again. In total the algorithm allocate ~6x the original input.
   
   Instead of please take the input MatrixBlock and call .getDenseBlockValues()
   This return an already allocated linearized double[] array of the values contained.
   
   The algorithm should only allocate two output real double[] and imaginary double[] array making the total allocation 2x.
   do not use double[][] nor double[][][] in location of the algorithm implementation.
   
   
   The change should not take that long, since most of the loops then become some modification of calculating indexes in the matrices while the FFT computation is the same.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -71,7 +73,7 @@ public static boolean isSupportedUnaryOperation( String opcode ) {
 	}
 	
 	public static boolean isSupportedMultiReturnOperation( String opcode ) {
-		return ( opcode.equals("qr") || opcode.equals("lu") || opcode.equals("eigen") || opcode.equals("svd") );
+		return ( opcode.equals("qr") || opcode.equals("lu") || opcode.equals("eigen") || opcode.equals("fft") || opcode.equals("ifft") || opcode.equals("svd") );

Review Comment:
   could you change this entire method to a switch statement thanks.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -49,6 +49,8 @@
 import org.apache.sysds.runtime.matrix.operators.BinaryOperator;
 import org.apache.sysds.runtime.util.DataConverter;
 
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;

Review Comment:
   we do not allow wildcard imports. you probably have to configure your IDE



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -252,6 +258,25 @@ private static EigenDecomposition computeEigenRegularized(MatrixBlock in) {
 			DataConverter.convertToArray2DRowRealMatrix(in2));
 	}
 
+	private static MatrixBlock[] computeFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false) )
+			throw new DMLRuntimeException("Invalid empty block");
+
+		//run fft
+		return fft(in);
+	}
+
+	private static MatrixBlock[] computeIFFT(MatrixBlock in) {
+		if( in == null || in.isEmptyBlock(false))
+			throw new DMLRuntimeException("Invalid empty block");
+		int rows = in.getNumRows();
+		int cols = in.getNumColumns();
+
+		MatrixBlock inIm = new MatrixBlock(rows, cols, new double[cols*rows]);

Review Comment:
   is it possible not to allocate this, maybe we need two different kernels?
   
   the allocation of this I part is very expensive.
   
   also  you probably want to modify the IFFT to optionally allow two inputs from DML script level. 



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){

Review Comment:
   remove this method.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){

Review Comment:
   avoid, and remove



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){

Review Comment:
   remove, and avoid this



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){
+
+        int rows = in[0].length;
+
+        double[][] col = new double[2][rows];
+        // get row
+        for (int i = 0; i < rows; i++){
+            for( int k = 0; k < 2; k++){
+                col[k][i] = in[k][i][j];
+            }
+        }
+        return col;
+    }
+
+    private static boolean isPowerOfTwo(int n){
+        return ((n != 0) && ((n & (n - 1)) == 0)) || n == 1;
+    }
+
+    public static MatrixBlock[] fft(double[] in){
+        double[][][] arr = new double[2][1][in.length];
+        arr[0][0] = in;
+        return fft(convertToMatrixBlocks(arr));
+    }
+
+    public static MatrixBlock[] fft(double[][][] in){
+        return fft(convertToMatrixBlocks(in));
+    }
+
+    public static MatrixBlock[] fft(MatrixBlock[] in){
+        return fft(in[0], in[1]);
+    }
+
+    public static MatrixBlock[] fft(MatrixBlock re){
+        return fft(re, getZeroMatrixBlock(re.getNumRows(), re.getNumColumns()));

Review Comment:
   a zero matrix block is the default, and we do not have to allocate the double array underneath, because we can simply use an sparse / empty matrix. (The only way you would know this is by knowing the system) 
   
   simply write `new MatrixBlock(rows,cols, true);`



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();

Review Comment:
   another allocation



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){

Review Comment:
   we should avoid this as well, since it simply index into the matrix, and extract the cells.
   This only makes the implementation slow, and trade a bit of coding.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test

Review Comment:
   change indentation to tabs



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){

Review Comment:
   index into the input, and remove as well.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){
+
+        int rows = in[0].length;
+
+        double[][] col = new double[2][rows];
+        // get row
+        for (int i = 0; i < rows; i++){
+            for( int k = 0; k < 2; k++){
+                col[k][i] = in[k][i][j];
+            }
+        }
+        return col;
+    }
+
+    private static boolean isPowerOfTwo(int n){
+        return ((n != 0) && ((n & (n - 1)) == 0)) || n == 1;

Review Comment:
   `(n != 0) && ((n & (n - 1)) == 0)` 
   is sufficient.
   
   also consider if you ever would input 0.
   
   imagine putting in n = 1, then the second part is 1 & 0 == 0, which is true.
   
   



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;

Review Comment:
   no wildcard imports



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};

Review Comment:
   we need to change the test inputs to MatrixBlock, or linearized double[] arrays.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**

Review Comment:
   change indentation to tabs



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();

Review Comment:
   As a general rule in testing (at least from my point of view) never print.
   the only thing you print is if there is an error. and then you print only the needed information to understand the error.
   
   The reason is we run ~1 million tests 20+ times a day and we do not want to read and store the output prints of tests from each execution. We only want to know, what tests are failing, and why.
   
   Therefore make the test construct a string, that you add as argument to the assertArrayEquals such that if the check fails, it prints the information, otherwise not.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();
+        }
+
+        for(int k = 0; k < 2 ; k++){
+            for(int i = 0; i < res[0].length; i++) {
+                assertArrayEquals(expected[k][i], res[k][i], 0.0001);
+            }
+        }
+    }
+
+    @Test
+    public void simple_test_one_dim_ifft() {
+
+        double[][] in = {{1, -2, 3, -4},{0, 0, 0, 0}};
+
+        double[][] res_fft = fft_one_dim(in);
+        double[][] res = ifft_one_dim(res_fft);
+
+        assertArrayEquals(in[0], res[0], 0.0001);
+        assertArrayEquals(in[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void matrix_block_one_dim_test(){
+
+        double[] in = {0, 18, -15, 3};
+
+        double[] expected_re = {6,15,-36,15};
+        double[] expected_im = {0,-15,0,15};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(expected_re, res_re, 0.0001);
+        assertArrayEquals(expected_im, res_im, 0.0001);
+    }
+    @Test

Review Comment:
   a new line between end of methods and new test declarations.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();

Review Comment:
   remove prints.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;

Review Comment:
   add licence



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestData.py:
##########
@@ -0,0 +1,165 @@
+import numpy as np
+import csv
+import time
+
+def generate_inputs(num_inputs, max_power):
+    for _ in range(num_inputs):
+        power = np.random.randint(1, max_power+1)
+        length = 2 ** power
+        yield np.random.rand(length)  # generate array of random floats
+
+def generate_complex_inputs(num_inputs, max_power):
+    for _ in range(num_inputs):
+        power = np.random.randint(1, max_power+1)
+        length = 2 ** power
+        real_part = np.random.rand(length)
+        imag_part = np.random.rand(length)
+        complex_array = real_part + 1j * imag_part
+        yield complex_array
+        
+
+def compute_fft(inputs):
+    total_time = 0
+    num_calculations = 0
+
+    for input_array in inputs:
+        start_time = time.time()
+        result = np.fft.fft(input_array)
+        end_time = time.time()
+
+        total_time += end_time - start_time
+        num_calculations += 1
+
+        if num_calculations % 1000 == 0:
+            average_time = total_time / num_calculations
+            print(f"Average execution time after {num_calculations} calculations: {average_time:.6f} seconds")
+
+        yield result
+
+def compute_ifft(inputs):
+    total_time = 0
+    num_calculations = 0
+
+    for input_array in inputs:
+        start_time = time.time()
+        result = np.fft.ifft(input_array)
+        end_time = time.time()
+
+        total_time += end_time - start_time
+        num_calculations += 1
+
+        if num_calculations % 1000 == 0:
+            average_time = total_time / num_calculations
+            print(f"Average execution time after {num_calculations} calculations: {average_time:.6f} seconds")
+
+        yield result
+        
+
+
+def save_to_file(inputs, outputs, filename, mode='a'):
+    with open(filename, mode, newline='') as file:
+        writer = csv.writer(file)
+        for input_array, output_array in zip(inputs, outputs):
+            flattened_data = np.concatenate((input_array, output_array.real, output_array.imag))
+            writer.writerow(flattened_data)
+
+
+def save_to_file_complex(inputs, outputs, filename, mode='a'):
+    with open(filename, mode, newline='') as file:
+        writer = csv.writer(file)
+        for input_array, output_array in zip(inputs, outputs):
+            flattened_data = np.concatenate((input_array.real, input_array.imag, output_array.real, output_array.imag))
+            writer.writerow(flattened_data)
+            
+def generate_complex_inputs_2d(num_inputs, max_power):
+    for _ in range(num_inputs):
+        power = np.random.randint(1, max_power+1)
+        rows = 2 ** power
+        cols = 2 ** power
+        real_part = np.random.rand(rows, cols)
+        imag_part = np.random.rand(rows, cols)
+        complex_array = real_part + 1j * imag_part
+        yield complex_array
+
+def compute_ifft_2d(inputs):
+
+    total_time = 0
+    num_calculations = 0
+
+    for input_array in inputs:
+        start_time = time.time()
+        result = np.fft.ifft2(input_array)
+        end_time = time.time()
+
+        total_time += end_time - start_time
+        num_calculations += 1
+
+        if num_calculations % 1000 == 0:
+            average_time = total_time / num_calculations
+            print(f"Average execution time after {num_calculations} calculations: {average_time:.6f} seconds")
+
+        yield result
+
+def save_to_file_complex_2d(inputs, outputs, filename, mode='a'):
+    with open(filename, mode, newline='') as file:
+        writer = csv.writer(file)
+        for input_array, output_array in zip(inputs, outputs):
+            flattened_input = np.concatenate((input_array.real.flatten(), input_array.imag.flatten()))
+            flattened_output = np.concatenate((output_array.real.flatten(), output_array.imag.flatten()))
+            writer.writerow(np.concatenate((flattened_input, flattened_output)))
+
+
+# Parameters
+num_inputs = 100000

Review Comment:
   add a
   
   `if __name__ == "__main__":`
   
   and indent the rest of the lines. 
   
   We do this to potentially allow other files to reuse some of your methods.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 
+    // and add the generated files to the root of the project.
+    @Test
+    public void testFftWithNumpyData() throws IOException {
+        String filename = "fft_data.csv"; // Path to your CSV file
+        BufferedReader reader = new BufferedReader(new FileReader(filename));
+        String line;
+        int lineNumber = 0;
+        long totalTime = 0; // Total time for all FFT computations
+        int numCalculations = 0; // Number of FFT computations
+
+        while ((line = reader.readLine()) != null) {
+            lineNumber++;
+
+            String[] values = line.split(",");
+            int n = values.length / 3;
+            double[][][] input = new double[2][1][n];
+            double[][] expected = new double[2][n]; // First row for real, second row for imaginary parts
+
+            for (int i = 0; i < n; i++) {
+                input[0][0][i] = Double.parseDouble(values[i]);
+                expected[0][i] = Double.parseDouble(values[n + i]); // Real part
+                expected[1][i] = Double.parseDouble(values[n * 2 + i]); // Imaginary part
+            }
+
+            long startTime = System.nanoTime();
+            MatrixBlock[] actualBlocks = fft(input);
+            long endTime = System.nanoTime();
+
+            if(lineNumber > 1000){
+                totalTime += (endTime - startTime);
+                numCalculations++;
+
+                if (numCalculations % progressInterval == 0) {
+                    double averageTime = (totalTime / 1e6) / numCalculations; // Average time in milliseconds
+                    System.out.println("fft(double[][][] in): Average execution time after " + numCalculations + " calculations: " + String.format("%.8f", averageTime/1000) + " s");
+                }
+            }
+
+            // Validate the FFT results
+            validateFftResults(expected, actualBlocks, lineNumber);
+        }
+
+        reader.close();
+        
+    }
+
+    private void validateFftResults(double[][] expected, MatrixBlock[] actualBlocks, int lineNumber) {
+        int length = expected[0].length;
+        for (int i = 0; i < length; i++) {
+            double realActual = actualBlocks[0].getValueDenseUnsafe(0, i);
+            double imagActual = actualBlocks[1].getValueDenseUnsafe(0, i);
+            assertEquals("Mismatch in real part at index " + i + " in line " + lineNumber, expected[0][i], realActual, 1e-9);
+            assertEquals("Mismatch in imaginary part at index " + i + " in line " + lineNumber, expected[1][i], imagActual, 1e-9);
+        }
+        if(lineNumber % progressInterval == 0){
+            System.out.println("fft(double[][][] in): Finished processing line " + lineNumber);
+        }
+        
+    }
+
+    @Test
+    public void testFftExecutionTime() throws IOException {

Review Comment:
   instead of evaluating time here, add a Performance script in: 
   
   `src/test/java/org/apache/sysds/performance/micro`
   
   this allows a bit more control for the experiment if you want it, instead of relying on the test framework for measurements.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test
+    public void simple_test_one_dim() {
+        // 1st row real part, 2nd row imaginary part
+        double[][] in = {{0, 18, -15, 3},{0, 0, 0, 0}};
+        double[][] expected = {{6, 15, -36, 15},{0, -15, 0, 15}};
+
+        double[][] res = fft_one_dim(in);
+        for(double[] row : res){
+            for (double elem : row){
+                System.out.print(elem + " ");
+            }
+            System.out.println();
+        }
+        assertArrayEquals(expected[0], res[0], 0.0001);
+        assertArrayEquals(expected[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void simple_test_two_dim() {
+        // tested with numpy
+        double[][][] in = {{{0, 18},{-15, 3}},{{0, 0},{0, 0}}};
+
+        double[][][] expected = {{{6, -36},{30, 0}},{{0, 0},{0, 0}}};
+
+        double[][][] res = fft(in, false);
+
+        for(double[][] matrix : res){
+            for(double[] row : matrix) {
+                for (double elem : row) {
+                    System.out.print(elem + " ");
+                }
+                System.out.println();
+            }
+            System.out.println();
+        }
+
+        for(int k = 0; k < 2 ; k++){
+            for(int i = 0; i < res[0].length; i++) {
+                assertArrayEquals(expected[k][i], res[k][i], 0.0001);
+            }
+        }
+    }
+
+    @Test
+    public void simple_test_one_dim_ifft() {
+
+        double[][] in = {{1, -2, 3, -4},{0, 0, 0, 0}};
+
+        double[][] res_fft = fft_one_dim(in);
+        double[][] res = ifft_one_dim(res_fft);
+
+        assertArrayEquals(in[0], res[0], 0.0001);
+        assertArrayEquals(in[1], res[1], 0.0001);
+    }
+
+    @Test
+    public void matrix_block_one_dim_test(){
+
+        double[] in = {0, 18, -15, 3};
+
+        double[] expected_re = {6,15,-36,15};
+        double[] expected_im = {0,-15,0,15};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(expected_re, res_re, 0.0001);
+        assertArrayEquals(expected_im, res_im, 0.0001);
+    }
+    @Test
+    public void matrix_block_two_dim_test(){
+
+        double[][][] in = {{{0, 18},{-15, 3}}};
+
+        double[] flattened_expected_re = {6,-36, 30,0};
+        double[] flattened_expected_im = {0,0,0,0};
+
+        MatrixBlock[] res = fft(in);
+        double[] res_re = res[0].getDenseBlockValues();
+        double[] res_im = res[1].getDenseBlockValues();
+
+        for(double elem : res_re){
+            System.out.print(elem+" ");
+        }
+        System.out.println();
+        for(double elem : res_im){
+            System.out.print(elem+" ");
+        }
+
+        assertArrayEquals(flattened_expected_re, res_re, 0.0001);
+        assertArrayEquals(flattened_expected_im, res_im, 0.0001);
+    }
+
+}

Review Comment:
   add a blank newline in the end of files.



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 

Review Comment:
   indent with tabs.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1934336859

   we move this to next release thanks for the initiative @j143 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460440574


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -49,6 +49,8 @@
 import org.apache.sysds.runtime.matrix.operators.BinaryOperator;
 import org.apache.sysds.runtime.util.DataConverter;
 
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460440184


##########
pom.xml:
##########
@@ -875,6 +875,12 @@
 	</profiles>
 
 	<dependencies>
+		<dependency>
+			<groupId>org.json</groupId>
+				<artifactId>json</artifactId>
+			<version>20210307</version>
+		</dependency>

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1902099929

   Clicking into the test runs you can see what fails in the cloud.
   
   It seems lie the IFFT fails.
   
   ```txt
   Error:  Failures: 
   Error:  org.apache.sysds.test.component.matrix.FourierTestLarge.testIfft2dWithGeneratedData
   Error:    Run 1: FourierTestLarge.testIfft2dWithGeneratedData:1513->assertComplexEquals:1191 Mismatch at [0][0] - Mismatch in real part. Expected: 2.810273443180434, Actual: 0.7025683607951085
   Error:    Run 2: FourierTestLarge.testIfft2dWithGeneratedData:1513->assertComplexEquals:1191 Mismatch at [0][0] - Mismatch in real part. Expected: 2.810273443180434, Actual: 0.7025683607951085
   Error:    Run 3: FourierTestLarge.testIfft2dWithGeneratedData:1513->assertComplexEquals:1191 Mismatch at [0][0] - Mismatch in real part. Expected: 2.810273443180434, Actual: 0.7025683607951085
   [INFO] 
   Error:  org.apache.sysds.test.component.matrix.FourierTestLarge.testIfftWithComplexNumpyData
   Error:    Run 1: FourierTestLarge.testIfftWithComplexNumpyData:1159->validateComplexIFftResults:1170->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5554009454874607, Actual: 0.6517737991465031
   Error:    Run 2: FourierTestLarge.testIfftWithComplexNumpyData:1159->validateComplexIFftResults:1170->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5554009454874607, Actual: 0.6517737991465031
   Error:    Run 3: FourierTestLarge.testIfftWithComplexNumpyData:1159->validateComplexIFftResults:1170->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5554009454874607, Actual: 0.6517737991465031
   [INFO] 
   Error:  org.apache.sysds.test.component.matrix.FourierTestLarge.testIfftWithRealNumpyData
   Error:    Run 1: FourierTestLarge.testIfftWithRealNumpyData:729->validateFftResults:386->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5613143313659362, Actual: 0.2806571656829681
   Error:    Run 2: FourierTestLarge.testIfftWithRealNumpyData:729->validateFftResults:386->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5613143313659362, Actual: 0.2806571656829681
   Error:    Run 3: FourierTestLarge.testIfftWithRealNumpyData:729->validateFftResults:386->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5613143313659362, Actual: 0.2806571656829681
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1492377862


##########
src/main/java/org/apache/sysds/runtime/instructions/cp/MultiReturnComplexMatrixBuiltinCPInstruction.java:
##########
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.runtime.instructions.cp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.sysds.common.Types.DataType;
+import org.apache.sysds.common.Types.ValueType;
+import org.apache.sysds.runtime.DMLRuntimeException;
+import org.apache.sysds.runtime.controlprogram.context.ExecutionContext;
+import org.apache.sysds.runtime.instructions.InstructionUtils;
+import org.apache.sysds.runtime.lineage.LineageItem;
+import org.apache.sysds.runtime.lineage.LineageItemUtils;
+import org.apache.sysds.runtime.matrix.data.LibCommonsMath;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.matrix.operators.Operator;
+
+public class MultiReturnComplexMatrixBuiltinCPInstruction extends ComputationCPInstruction {
+
+    protected ArrayList<CPOperand> _outputs;
+
+    private MultiReturnComplexMatrixBuiltinCPInstruction(Operator op, CPOperand input1, CPOperand input2,
+            ArrayList<CPOperand> outputs, String opcode,
+            String istr) {
+        super(CPType.MultiReturnBuiltin, op, input1, input2, outputs.get(0), opcode, istr);
+        _outputs = outputs;
+    }
+
+    private MultiReturnComplexMatrixBuiltinCPInstruction(Operator op, CPOperand input1, ArrayList<CPOperand> outputs,
+            String opcode,
+            String istr) {
+        super(CPType.MultiReturnBuiltin, op, input1, null, outputs.get(0), opcode, istr);
+        _outputs = outputs;
+    }
+
+    public CPOperand getOutput(int i) {
+        return _outputs.get(i);
+    }
+
+    public List<CPOperand> getOutputs() {
+        return _outputs;
+    }
+
+    public String[] getOutputNames() {
+        return _outputs.parallelStream().map(output -> output.getName()).toArray(String[]::new);
+    }
+
+    public static MultiReturnComplexMatrixBuiltinCPInstruction parseInstruction(String str) {
+        String[] parts = InstructionUtils.getInstructionPartsWithValueType(str);
+        ArrayList<CPOperand> outputs = new ArrayList<>();
+        // first part is always the opcode
+        String opcode = parts[0];
+
+        if (parts.length == 5 && opcode.equalsIgnoreCase("ifft")) {
+            // one input and two outputs
+            CPOperand in1 = new CPOperand(parts[1]);
+            CPOperand in2 = new CPOperand(parts[2]);
+            outputs.add(new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX));
+            outputs.add(new CPOperand(parts[4], ValueType.FP64, DataType.MATRIX));
+
+            return new MultiReturnComplexMatrixBuiltinCPInstruction(null, in1, in2, outputs, opcode, str);
+        } else if (parts.length == 4 && opcode.equalsIgnoreCase("ifft")) {
+            // one input and two outputs
+            CPOperand in1 = new CPOperand(parts[1]);
+            outputs.add(new CPOperand(parts[2], ValueType.FP64, DataType.MATRIX));
+            outputs.add(new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX));
+
+            return new MultiReturnComplexMatrixBuiltinCPInstruction(null, in1, outputs, opcode, str);
+        } else if (parts.length == 5 && opcode.equalsIgnoreCase("ifft_linearized")) {
+            // one input and two outputs
+            CPOperand in1 = new CPOperand(parts[1]);
+            CPOperand in2 = new CPOperand(parts[2]);
+            outputs.add(new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX));
+            outputs.add(new CPOperand(parts[4], ValueType.FP64, DataType.MATRIX));
+
+            return new MultiReturnComplexMatrixBuiltinCPInstruction(null, in1, in2, outputs, opcode, str);
+        } else if (parts.length == 4 && opcode.equalsIgnoreCase("ifft_linearized")) {
+            // one input and two outputs
+            CPOperand in1 = new CPOperand(parts[1]);
+            outputs.add(new CPOperand(parts[2], ValueType.FP64, DataType.MATRIX));
+            outputs.add(new CPOperand(parts[3], ValueType.FP64, DataType.MATRIX));
+
+            return new MultiReturnComplexMatrixBuiltinCPInstruction(null, in1, outputs, opcode, str);
+        }
+
+        {

Review Comment:
   this bracket does not make sense



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+
+public class LibMatrixFourier {
+
+	/**
+	 * Function to perform FFT for two given matrices. The first one represents the real values and the second one the
+	 * imaginary values. The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		fft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, true);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform IFFT for two given matrices. The first one represents the real values and the second one the
+	 * imaginary values. The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		ifft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, true);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform FFT for each row of two given matrices. The first one represents the real values and the
+	 * second one the imaginary values. The output also contains one matrix for the real and one for the imaginary
+	 * values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] fft_linearized(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		fft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, false);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform IFFT for each row of two given matrices. The first one represents the real values and the
+	 * second one the imaginary values. The output also contains one matrix for the real and one for the imaginary
+	 * values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] ifft_linearized(MatrixBlock re, MatrixBlock im) {
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(cols))
+			throw new RuntimeException("false dimensions");
+
+		ifft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols, false);
+
+		return new MatrixBlock[] {re, im};
+	}
+
+	/**
+	 * Function to perform FFT for two given double arrays. The first one represents the real values and the second one
+	 * the imaginary values. Both arrays get updated and contain the result.
+	 *
+	 * @param re          array representing the real values
+	 * @param im          array representing the imaginary values
+	 * @param rows        number of rows
+	 * @param cols        number of rows
+	 * @param inclColCalc if true, fft is also calculated for each column, otherwise only for each row
+	 */
+	public static void fft(double[] re, double[] im, int rows, int cols, boolean inclColCalc) {
+
+		double[] re_inter = new double[rows * cols];
+		double[] im_inter = new double[rows * cols];
+
+		for(int i = 0; i < rows; i++) {
+			fft_one_dim(re, im, re_inter, im_inter, i * cols, (i + 1) * cols, cols, 1);
+		}
+
+		if(inclColCalc) {
+			for(int j = 0; j < cols; j++) {
+				fft_one_dim(re, im, re_inter, im_inter, j, j + rows * cols, rows, cols);
+			}
+		}
+
+	}
+
+	/**
+	 * Function to perform IFFT for two given double arrays. The first one represents the real values and the second one
+	 * the imaginary values. Both arrays get updated and contain the result.
+	 *
+	 * @param re          array representing the real values
+	 * @param im          array representing the imaginary values
+	 * @param rows        number of rows
+	 * @param cols        number of rows
+	 * @param inclColCalc if true, fft is also calculated for each column, otherwise only for each row
+	 */
+	public static void ifft(double[] re, double[] im, int rows, int cols, boolean inclColCalc) {
+
+		double[] re_inter = new double[rows * cols];
+		double[] im_inter = new double[rows * cols];
+
+		if(inclColCalc) {
+			for(int j = 0; j < cols; j++) {
+				ifft_one_dim(re, im, re_inter, im_inter, j, j + rows * cols, rows, cols);
+			}
+		}
+
+		for(int i = 0; i < rows; i++) {
+			ifft_one_dim(re, im, re_inter, im_inter, i * cols, (i + 1) * cols, cols, 1);

Review Comment:
   consider if this call can be parallel:
   
   The code would be something along the lines of:
   
   ```
   ExecutionContext pool = CommonThreadPool.get(k)
   for( ...) {
   pool.submit( () -> ifft_one_dim(re,im,re_inter, im_inter ...)
   }
   ```
   
   k is number of threads, and you can get that argument from CommonMath file.
   
   Thanks



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -252,6 +295,104 @@ private static EigenDecomposition computeEigenRegularized(MatrixBlock in) {
 			DataConverter.convertToArray2DRowRealMatrix(in2));
 	}
 
+	/**
+	 * Function to perform FFT on a given matrix.
+	 *
+	 * @param re matrix object
+	 * @return array of matrix blocks
+	 */
+	private static MatrixBlock[] computeFFT(MatrixBlock re) {
+		if(re == null)
+			throw new DMLRuntimeException("Invalid empty block");
+		if (re.isEmptyBlock(false)) {
+			// Return the original matrix as the result
+			return new MatrixBlock[]{re, new MatrixBlock(re.getNumRows(), re.getNumColumns(), true)}; // Assuming you need to return two matrices: the real part and an imaginary part initialized to 0.
+		}
+		// run fft
+		re.sparseToDense();
+		return fft(re);
+	}
+
+	private static boolean isMatrixAllZeros(MatrixBlock matrix) {

Review Comment:
   This is not a good check, please use isEmpty() and nonzeros count to verify if there is values in the matrix.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -113,9 +134,31 @@ else if (opcode.equals("eigen_qr"))
 			return computeEigenQR(in, threads);
 		else if (opcode.equals("svd"))
 			return computeSvd(in);
+		else if (opcode.equals("fft"))
+			return computeFFT(in);
+		else if (opcode.equals("ifft"))
+			return computeIFFT(in, null);

Review Comment:
   you can overload the computeIFFT function to remove this null argument.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1495003135


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -440,4 +444,18 @@ public static MatrixBlock[] ifft_linearized(MatrixBlock re, int threads) {
 			threads);
 	}
 
+	private static double sin(double angle){
+		if (!sinCache.containsKey(angle)) {

Review Comment:
   please limit the cache to contain only a subset of values (max 1000), since the map can grow to large.
   also we need to hide it behind a SoftReference since we want to allow java to remove it from memory if we are under memory pressure.
   
   Therefore to use it extract the HashMap and materialize it as a variable inside fft_one_dim_sub(), and put that hashmap in as an argument to your calls to cos and sin.
   
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460442116


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460441756


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460440699


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -71,7 +73,7 @@ public static boolean isSupportedUnaryOperation( String opcode ) {
 	}
 	
 	public static boolean isSupportedMultiReturnOperation( String opcode ) {
-		return ( opcode.equals("qr") || opcode.equals("lu") || opcode.equals("eigen") || opcode.equals("svd") );
+		return ( opcode.equals("qr") || opcode.equals("lu") || opcode.equals("eigen") || opcode.equals("fft") || opcode.equals("ifft") || opcode.equals("svd") );

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443563


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){
+
+        int rows = in[0].length;
+
+        double[][] col = new double[2][rows];
+        // get row
+        for (int i = 0; i < rows; i++){
+            for( int k = 0; k < 2; k++){
+                col[k][i] = in[k][i][j];
+            }
+        }
+        return col;
+    }
+
+    private static boolean isPowerOfTwo(int n){
+        return ((n != 0) && ((n & (n - 1)) == 0)) || n == 1;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [SYSTEMDS-3685] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460444933


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTestWithFiles.java:
##########
@@ -0,0 +1,377 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertTrue;
+
+public class FourierTestWithFiles {
+    int progressInterval = 5000;
+
+    // prior to executing the following tests it is necessary to run the Numpy Script in FourierTestData.py 

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1495039456


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -440,4 +444,18 @@ public static MatrixBlock[] ifft_linearized(MatrixBlock re, int threads) {
 			threads);
 	}
 
+	private static double sin(double angle){
+		if (!sinCache.containsKey(angle)) {

Review Comment:
   Would it also be fine to materialize the cache inside of fft() or fft_one_dim()? As far as I can see, cos or sin is never computed for the same values in fft_one_dim_sub() and therefore there would be no benefit.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1898549097

   when you handle comments, feel free to mark them as resolved.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443713


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){
+
+        int rows = in[0].length;
+
+        double[][] col = new double[2][rows];
+        // get row
+        for (int i = 0; i < rows; i++){
+            for( int k = 0; k < 2; k++){
+                col[k][i] = in[k][i][j];
+            }
+        }
+        return col;
+    }
+
+    private static boolean isPowerOfTwo(int n){
+        return ((n != 0) && ((n & (n - 1)) == 0)) || n == 1;

Review Comment:
   resolved



##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443563


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**
+     * Function to perform Fast Fourier Transformation
+     */
+
+    public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, false);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+        int rows = re.getNumRows();
+        int cols = re.getNumColumns();
+
+        double[][][] in = new double[2][rows][cols];
+        in[0] = convertToArray(re);
+        in[1] = convertToArray(im);
+
+        double[][][] res = fft(in, true);
+
+        return convertToMatrixBlocks(res);
+    }
+
+    public static double[][][] fft(double[][][] in, boolean calcInv){
+
+        int rows = in[0].length;
+        int cols = in[0][0].length;
+
+        double[][][] res = new double[2][rows][cols];
+
+        for(int i = 0; i < rows; i++){
+            // use fft or ifft on each row
+            double[][] res_row = calcInv? ifft_one_dim(get_complex_row(in, i)) : fft_one_dim(get_complex_row(in, i));
+
+            // set res row
+            for (int j = 0; j < cols; j++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_row[k][j];
+                }
+            }
+        }
+
+        if(rows == 1) return res;
+
+        for(int j = 0; j < cols; j++){
+            // use fft on each col
+            double[][] res_col = calcInv? ifft_one_dim(get_complex_col(res, j)) : fft_one_dim(get_complex_col(res, j));
+
+            // set res col
+            for (int i = 0; i < rows; i++){
+                for( int k = 0; k < 2; k++){
+                    res[k][i][j] = res_col[k][i];
+                }
+            }
+        }
+
+        return res;
+    }
+
+    public static double[][] fft_one_dim(double[][] in){
+        // 1st row real part, 2nd row imaginary part
+        if(in == null || in.length != 2 || in[0].length != in[1].length) throw new RuntimeException("in false dimensions");
+
+        int cols = in[0].length;
+        if(cols == 1) return in;
+
+        double angle = -2*FastMath.PI/cols;
+
+        // split values depending on index
+        double[][] even = new double[2][cols/2];
+        double[][] odd = new double[2][cols/2];
+
+        for(int i = 0; i < 2; i++){
+            for (int j = 0; j < cols/2; j++){
+                even[i][j] = in[i][j*2];
+                odd[i][j] = in[i][j*2+1];
+            }
+        }
+        double[][] res_even = fft_one_dim(even);
+        double[][] res_odd = fft_one_dim(odd);
+
+        double[][] res = new double[2][cols];
+
+        for(int j=0; j < cols/2; j++){
+            double[] omega_pow = new double[]{FastMath.cos(j*angle), FastMath.sin(j*angle)};
+
+            // m = omega * res_odd[j]
+            double[] m = new double[]{
+                    omega_pow[0] * res_odd[0][j] - omega_pow[1] * res_odd[1][j],
+                    omega_pow[0] * res_odd[1][j] + omega_pow[1] * res_odd[0][j]};
+
+            // res[j] = res_even + m;
+            // res[j+cols/2] = res_even - m;
+            for(int i = 0; i < 2; i++){
+                res[i][j] = res_even[i][j] + m[i];
+                res[i][j+cols/2] = res_even[i][j] - m[i];
+            }
+        }
+
+        return res;
+
+    }
+
+    public static double[][] ifft_one_dim(double[][] in) {
+
+        // cols[0] is real part, cols[1] is imaginary part
+        int cols = in[0].length;
+
+        // conjugate input
+        in[1] = Arrays.stream(in[1]).map(i -> -i).toArray();
+
+        // apply fft
+        double[][] res = fft_one_dim(in);
+
+        // conjugate and scale result
+        res[0] = Arrays.stream(res[0]).map(i -> i/cols).toArray();
+        res[1] = Arrays.stream(res[1]).map(i -> -i/cols).toArray();
+
+        return res;
+    }
+
+    private static MatrixBlock[] convertToMatrixBlocks(double[][][] in){
+
+        int cols = in[0][0].length;
+        int rows = in[0].length;
+
+        double[] flattened_re = Arrays.stream(in[0]).flatMapToDouble(Arrays::stream).toArray();
+        double[] flattened_im = new double[rows*cols];
+        if(in.length > 1){
+            flattened_im = Arrays.stream(in[1]).flatMapToDouble(Arrays::stream).toArray();
+        }
+
+        MatrixBlock re = new MatrixBlock(rows, cols, flattened_re);
+        MatrixBlock im = new MatrixBlock(rows, cols, flattened_im);
+
+        return new MatrixBlock[]{re, im};
+    }
+
+    private static MatrixBlock getZeroMatrixBlock(int rows, int cols){
+
+        return new MatrixBlock(rows, cols, new double[cols*rows]);
+
+    }
+
+    private static double[][] convertToArray(MatrixBlock in){
+
+        int rows = in.getNumRows();
+        int cols = in.getNumColumns();
+
+        double[][] out = new double[rows][cols];
+        for(int i = 0; i < rows; i++){
+            out[i] = Arrays.copyOfRange(in.getDenseBlockValues(), i * cols, (i+1) * cols);
+        }
+
+        return out;
+    }
+    private static double[][][] convertToArray(MatrixBlock[] in){
+
+        int rows = in[0].getNumRows();
+        int cols = in[0].getNumColumns();
+
+        double[][][] out = new double[2][rows][cols];
+        for(int k = 0; k < 2; k++){
+            for(int i = 0; i < rows; i++){
+                out[k][i] = Arrays.copyOfRange(in[k].getDenseBlockValues(), i * cols, (i+1) * cols);
+            }
+        }
+
+        return out;
+    }
+
+    public static double[][] get_complex_row(double[][][] in, int i){
+
+        int cols = in[0][0].length;
+
+        double[][] row = new double[2][cols];
+        // get row
+        for (int j = 0; j < cols; j++){
+            for( int k = 0; k < 2; k++){
+                row[k][j] = in[k][i][j];
+            }
+        }
+        return row;
+    }
+    public static double[][] get_complex_col(double[][][] in, int j){

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460443973


##########
src/test/java/org/apache/sysds/test/component/matrix/FourierTest.java:
##########
@@ -0,0 +1,112 @@
+package org.apache.sysds.test.component.matrix;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.junit.Test;
+import static org.apache.sysds.runtime.matrix.data.LibMatrixFourier.*;
+import static org.junit.Assert.assertArrayEquals;
+
+public class FourierTest {
+
+    @Test

Review Comment:
   resolved



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,236 @@
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+import java.util.Arrays;
+
+public class LibMatrixFourier {
+
+    /**

Review Comment:
   resolved



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "Baunsgaard (via GitHub)" <gi...@apache.org>.
Baunsgaard commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1460449522


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+
+public class LibMatrixFourier {
+
+	/**
+	 * Function to perform FFT on two given matrices.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols)) throw new RuntimeException("false dimensions");
+
+		fft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols);
+
+		return new MatrixBlock[]{re, im};
+	}
+
+	/**
+	 * Function to perform IFFT on two given matrices.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols)) throw new RuntimeException("false dimensions");
+
+		ifft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols);
+
+		return new MatrixBlock[]{re, im};
+	}
+
+	/**
+	 * Function to perform FFT on two given double arrays.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * Both arrays get updated and contain the result.
+	 *
+	 * @param re array representing the real values
+	 * @param im array representing the imaginary values
+	 * @param rows number of rows
+	 * @param cols number of rows
+	 */
+	public static void fft(double[] re, double[] im, int rows, int cols) {
+
+		double[] re_inter = new double[rows*cols];
+		double[] im_inter = new double[rows*cols];
+
+		for(int i = 0; i < rows; i++){
+			fft_one_dim(re, im, re_inter, im_inter, i*cols, 1, cols, cols);
+		}
+
+		for(int j = 0; j < cols; j++){
+			fft_one_dim(re, im, re_inter, im_inter, j, cols, rows, rows*cols);
+		}
+
+	}
+
+	/**
+	 * Function to perform IFFT on two given double arrays.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * Both arrays get updated and contain the result.
+	 *
+	 * @param re array representing the real values
+	 * @param im array representing the imaginary values
+	 * @param rows number of rows
+	 * @param cols number of rows
+	 */
+	public static void ifft(double[] re, double[] im, int rows, int cols) {
+
+		double[] re_inter = new double[rows*cols];
+		double[] im_inter = new double[rows*cols];
+
+		for(int j = 0; j < cols; j++){
+			ifft_one_dim(re, im, re_inter, im_inter, j, cols, rows, rows*cols);
+		}
+
+		for(int i = 0; i < rows; i++){
+			ifft_one_dim(re, im, re_inter, im_inter, i*cols, 1, cols, cols);
+		}
+
+	}
+
+	private static void fft_one_dim(double[] re, double[] im, double[] re_inter, double[] im_inter, int start, int step, int num, int subArraySize) {
+
+		if(num == 1) return;
+		double angle = -2*FastMath.PI/num;
+
+		// fft for even indices
+		fft_one_dim(re, im, re_inter, im_inter, start, step*2, num/2, subArraySize);
+		// fft for odd indices
+		fft_one_dim(re, im, re_inter, im_inter,start+step, step*2, num/2, subArraySize);

Review Comment:
   Great!
   
   this solution should already be much faster, i am looking forward to see some performance numbers.
   
   To get even faster, and help java we can transform the "recursive code" into "iterative code".
   
   https://stackoverflow.com/questions/159590/way-to-go-from-recursion-to-iteration
   
   This helps for some java specific reasons, because each of your function calls gets put on top of the stack, it makes it hard for the JVM to JIT compile the method calls. 
   
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "jessicapriebe (via GitHub)" <gi...@apache.org>.
jessicapriebe commented on code in PR #1983:
URL: https://github.com/apache/systemds/pull/1983#discussion_r1461794646


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibMatrixFourier.java:
##########
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sysds.runtime.matrix.data;
+
+import org.apache.commons.math3.util.FastMath;
+
+public class LibMatrixFourier {
+
+	/**
+	 * Function to perform FFT on two given matrices.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] fft(MatrixBlock re, MatrixBlock im){
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols)) throw new RuntimeException("false dimensions");
+
+		fft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols);
+
+		return new MatrixBlock[]{re, im};
+	}
+
+	/**
+	 * Function to perform IFFT on two given matrices.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * The output also contains one matrix for the real and one for the imaginary values.
+	 *
+	 * @param re matrix object representing the real values
+	 * @param im matrix object representing the imaginary values
+	 * @return array of two matrix blocks
+	 */
+	public static MatrixBlock[] ifft(MatrixBlock re, MatrixBlock im){
+
+		int rows = re.getNumRows();
+		int cols = re.getNumColumns();
+		if(!isPowerOfTwo(rows) || !isPowerOfTwo(cols)) throw new RuntimeException("false dimensions");
+
+		ifft(re.getDenseBlockValues(), im.getDenseBlockValues(), rows, cols);
+
+		return new MatrixBlock[]{re, im};
+	}
+
+	/**
+	 * Function to perform FFT on two given double arrays.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * Both arrays get updated and contain the result.
+	 *
+	 * @param re array representing the real values
+	 * @param im array representing the imaginary values
+	 * @param rows number of rows
+	 * @param cols number of rows
+	 */
+	public static void fft(double[] re, double[] im, int rows, int cols) {
+
+		double[] re_inter = new double[rows*cols];
+		double[] im_inter = new double[rows*cols];
+
+		for(int i = 0; i < rows; i++){
+			fft_one_dim(re, im, re_inter, im_inter, i*cols, 1, cols, cols);
+		}
+
+		for(int j = 0; j < cols; j++){
+			fft_one_dim(re, im, re_inter, im_inter, j, cols, rows, rows*cols);
+		}
+
+	}
+
+	/**
+	 * Function to perform IFFT on two given double arrays.
+	 * The first one represents the real values and the second one the imaginary values.
+	 * Both arrays get updated and contain the result.
+	 *
+	 * @param re array representing the real values
+	 * @param im array representing the imaginary values
+	 * @param rows number of rows
+	 * @param cols number of rows
+	 */
+	public static void ifft(double[] re, double[] im, int rows, int cols) {
+
+		double[] re_inter = new double[rows*cols];
+		double[] im_inter = new double[rows*cols];
+
+		for(int j = 0; j < cols; j++){
+			ifft_one_dim(re, im, re_inter, im_inter, j, cols, rows, rows*cols);
+		}
+
+		for(int i = 0; i < rows; i++){
+			ifft_one_dim(re, im, re_inter, im_inter, i*cols, 1, cols, cols);
+		}
+
+	}
+
+	private static void fft_one_dim(double[] re, double[] im, double[] re_inter, double[] im_inter, int start, int step, int num, int subArraySize) {
+
+		if(num == 1) return;
+		double angle = -2*FastMath.PI/num;
+
+		// fft for even indices
+		fft_one_dim(re, im, re_inter, im_inter, start, step*2, num/2, subArraySize);
+		// fft for odd indices
+		fft_one_dim(re, im, re_inter, im_inter,start+step, step*2, num/2, subArraySize);

Review Comment:
   done, fft is now implemented iteratively



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "fzoepffel (via GitHub)" <gi...@apache.org>.
fzoepffel commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1903694078

   > Clicking into the test runs you can see what fails in the cloud.
   > 
   > It seems lie the IFFT fails.
   > 
   > ```
   > Error:  Failures: 
   > Error:  org.apache.sysds.test.component.matrix.FourierTestLarge.testIfft2dWithGeneratedData
   > Error:    Run 1: FourierTestLarge.testIfft2dWithGeneratedData:1513->assertComplexEquals:1191 Mismatch at [0][0] - Mismatch in real part. Expected: 2.810273443180434, Actual: 0.7025683607951085
   > Error:    Run 2: FourierTestLarge.testIfft2dWithGeneratedData:1513->assertComplexEquals:1191 Mismatch at [0][0] - Mismatch in real part. Expected: 2.810273443180434, Actual: 0.7025683607951085
   > Error:    Run 3: FourierTestLarge.testIfft2dWithGeneratedData:1513->assertComplexEquals:1191 Mismatch at [0][0] - Mismatch in real part. Expected: 2.810273443180434, Actual: 0.7025683607951085
   > [INFO] 
   > Error:  org.apache.sysds.test.component.matrix.FourierTestLarge.testIfftWithComplexNumpyData
   > Error:    Run 1: FourierTestLarge.testIfftWithComplexNumpyData:1159->validateComplexIFftResults:1170->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5554009454874607, Actual: 0.6517737991465031
   > Error:    Run 2: FourierTestLarge.testIfftWithComplexNumpyData:1159->validateComplexIFftResults:1170->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5554009454874607, Actual: 0.6517737991465031
   > Error:    Run 3: FourierTestLarge.testIfftWithComplexNumpyData:1159->validateComplexIFftResults:1170->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5554009454874607, Actual: 0.6517737991465031
   > [INFO] 
   > Error:  org.apache.sysds.test.component.matrix.FourierTestLarge.testIfftWithRealNumpyData
   > Error:    Run 1: FourierTestLarge.testIfftWithRealNumpyData:729->validateFftResults:386->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5613143313659362, Actual: 0.2806571656829681
   > Error:    Run 2: FourierTestLarge.testIfftWithRealNumpyData:729->validateFftResults:386->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5613143313659362, Actual: 0.2806571656829681
   > Error:    Run 3: FourierTestLarge.testIfftWithRealNumpyData:729->validateFftResults:386->assertEquals:1184 Mismatch in real part at index 0 in line 1 - Expected: 0.5613143313659362, Actual: 0.2806571656829681
   > ```
   
   The tests have to be adjusted again. currently there is a problem with the data. The tests will be adjusted to use the Java Python interface to compare with the numpy data directly


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] DML Integration of FFT and IFFT [systemds]

Posted by "fzoepffel (via GitHub)" <gi...@apache.org>.
fzoepffel commented on PR #1983:
URL: https://github.com/apache/systemds/pull/1983#issuecomment-1935589905

   > > > > The remaining conflicts were just resolved. Now the PR should be ready to merge. Further validation(e.g. empty inputs, differing dimensions of imaginary and real inputs, etc.) and minor bug fixes like the handling of only zero input matrices will come in a separate PR for the integrated python tests. Currently the workflows are waiting for this PR are awaiting approval. Hopefully the integrationtests that were failing before will succeed now. We are assuming that these integration tests are not related to us. Please let us know if you think differently.
   > > > 
   > > > 
   > > > Hi @fzoepffel
   > > > The code passes all tests, great.
   > > > I think your codeformatter ran in many of the PR files. Can we revert this? We try to avoid formatting existing files (even if the format is wrong) unless we do major changes.
   > > 
   > > 
   > > I just saw. I am a little unsure however, how I can revert this. When I run the formatter (which I configured to use the CodeStyle_eclipse.xml file) it does not necessarily reverse to what it was before.
   > 
   > The files was just not formatted before. Not everyone formats the files, and we have some legacy/old code that we would rather have refer to the original authors rather than change the format of it. Therefore i have configured my IDE only for format on request not automatically.
   > 
   > A concrete way of handling it is a bit more tricky. I suggest going back through commits and figuring out which commit did the formatting, and then revert the formatting without breaking the changes that you wanted to do. There probably is a smarter way, but I am unaware of such.
   
   The legacy had mainly been formatted in three commits. I reversed the hunks of these commits that were not related to our fft implementation. Since I had to do this for each file individually I added a "reverse formatting" commit for each file. Unfortunately two tests are failing now (see [**.functions.federated.monitoring.**,**.functions.federated.multitenant.**](https://github.com/apache/systemds/actions/runs/7837353259/job/21398216259?pr=1983#logs)
   [**.component.c**.**](https://github.com/apache/systemds/actions/runs/7837353259/job/21398211615?pr=1983#logs)). 
   I think that these tests have nothing to with our code though. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@systemds.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org