Baunsgaard commented on code in PR #2038:
URL: https://github.com/apache/systemds/pull/2038#discussion_r1664306304


##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {
+ 
+               // TODO: Verify matrix is symmetric
+               final double[] mainDiag = new double[in.rlen];
+               final double[] secDiag = new double[in.rlen - 1];
+
+               final MatrixBlock householderVectors = 
transformToTridiagonal(in, mainDiag, secDiag, threads);
+
+               // TODO: Consider using sparse blocks
+               final double[] hv = householderVectors.getDenseBlockValues();
+               MatrixBlock houseHolderMatrix = getQ(hv, mainDiag, secDiag);
+
+               MatrixBlock[] evResult = findEigenVectors(mainDiag, secDiag, 
houseHolderMatrix, EIGEN_MAX_ITER, threads);
+
+               MatrixBlock realEigenValues = evResult[0];
+               MatrixBlock eigenVectors = evResult[1];
+
+               realEigenValues.setNonZeros(realEigenValues.rlen * 
realEigenValues.rlen);
+               eigenVectors.setNonZeros(eigenVectors.rlen * eigenVectors.clen);
+
+               return new MatrixBlock[] { realEigenValues, eigenVectors };
+       }
+
+       private static MatrixBlock transformToTridiagonal(MatrixBlock matrix, 
double[] main, double[] secondary, int threads) {
+               final int m = matrix.rlen;
+
+               // MatrixBlock householderVectors = ;
+               MatrixBlock householderVectors = matrix.extractTriangular(new 
MatrixBlock(m, m, false), false, true, true);
+               if (householderVectors.isInSparseFormat()) {
+                       householderVectors.sparseToDense(threads);      
+               }
+
+               final double[] z = new double[m];
+
+               // TODO: Consider sparse block case
+               final double[] hv = householderVectors.getDenseBlockValues();
+
+               for (int k = 0; k < m - 1; k++) {
+                       final int k_kp1 = k * m + k + 1;
+                       final int km = k * m;
+
+                       // zero-out a row and a column simultaneously
+                       main[k] = hv[km + k];
+
+                       // TODO: may or may not improve, seems it does not
+                       // double xNormSqr = householderVectors.slice(k, k, k + 
1, m - 1).sumSq();
+                       // double xNormSqr = LibMatrixMult.dotProduct(hv, hv, 
k_kp1, k_kp1, m - (k + 1));
+                       double xNormSqr = 0;
+                       for (int j = k + 1; j < m; ++j) {

Review Comment:
   this looks like a square row sum, 
   this is an operation you can perform directly.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {
+ 
+               // TODO: Verify matrix is symmetric
+               final double[] mainDiag = new double[in.rlen];
+               final double[] secDiag = new double[in.rlen - 1];
+
+               final MatrixBlock householderVectors = 
transformToTridiagonal(in, mainDiag, secDiag, threads);
+
+               // TODO: Consider using sparse blocks
+               final double[] hv = householderVectors.getDenseBlockValues();
+               MatrixBlock houseHolderMatrix = getQ(hv, mainDiag, secDiag);
+
+               MatrixBlock[] evResult = findEigenVectors(mainDiag, secDiag, 
houseHolderMatrix, EIGEN_MAX_ITER, threads);
+
+               MatrixBlock realEigenValues = evResult[0];
+               MatrixBlock eigenVectors = evResult[1];
+
+               realEigenValues.setNonZeros(realEigenValues.rlen * 
realEigenValues.rlen);
+               eigenVectors.setNonZeros(eigenVectors.rlen * eigenVectors.clen);
+
+               return new MatrixBlock[] { realEigenValues, eigenVectors };
+       }
+
+       private static MatrixBlock transformToTridiagonal(MatrixBlock matrix, 
double[] main, double[] secondary, int threads) {
+               final int m = matrix.rlen;
+
+               // MatrixBlock householderVectors = ;
+               MatrixBlock householderVectors = matrix.extractTriangular(new 
MatrixBlock(m, m, false), false, true, true);
+               if (householderVectors.isInSparseFormat()) {
+                       householderVectors.sparseToDense(threads);      
+               }
+
+               final double[] z = new double[m];

Review Comment:
   This temporary allocation seems like the only thing that limits you from 
parallelizing the entire for loop.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -74,6 +79,8 @@ public class LibCommonsMath
        private static final Log LOG = 
LogFactory.getLog(LibCommonsMath.class.getName());
        private static final double RELATIVE_SYMMETRY_THRESHOLD = 1e-6;
        private static final double EIGEN_LAMBDA = 1e-8;
+       private static final double EIGEN_EPS = Precision.EPSILON;

Review Comment:
   Define this value directly without using commons math lib.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {
+ 
+               // TODO: Verify matrix is symmetric
+               final double[] mainDiag = new double[in.rlen];
+               final double[] secDiag = new double[in.rlen - 1];
+
+               final MatrixBlock householderVectors = 
transformToTridiagonal(in, mainDiag, secDiag, threads);
+
+               // TODO: Consider using sparse blocks
+               final double[] hv = householderVectors.getDenseBlockValues();
+               MatrixBlock houseHolderMatrix = getQ(hv, mainDiag, secDiag);
+
+               MatrixBlock[] evResult = findEigenVectors(mainDiag, secDiag, 
houseHolderMatrix, EIGEN_MAX_ITER, threads);
+
+               MatrixBlock realEigenValues = evResult[0];
+               MatrixBlock eigenVectors = evResult[1];
+
+               realEigenValues.setNonZeros(realEigenValues.rlen * 
realEigenValues.rlen);
+               eigenVectors.setNonZeros(eigenVectors.rlen * eigenVectors.clen);
+
+               return new MatrixBlock[] { realEigenValues, eigenVectors };
+       }
+
+       private static MatrixBlock transformToTridiagonal(MatrixBlock matrix, 
double[] main, double[] secondary, int threads) {
+               final int m = matrix.rlen;
+
+               // MatrixBlock householderVectors = ;
+               MatrixBlock householderVectors = matrix.extractTriangular(new 
MatrixBlock(m, m, false), false, true, true);
+               if (householderVectors.isInSparseFormat()) {
+                       householderVectors.sparseToDense(threads);      
+               }
+
+               final double[] z = new double[m];
+
+               // TODO: Consider sparse block case
+               final double[] hv = householderVectors.getDenseBlockValues();
+
+               for (int k = 0; k < m - 1; k++) {
+                       final int k_kp1 = k * m + k + 1;
+                       final int km = k * m;
+
+                       // zero-out a row and a column simultaneously
+                       main[k] = hv[km + k];
+
+                       // TODO: may or may not improve, seems it does not
+                       // double xNormSqr = householderVectors.slice(k, k, k + 
1, m - 1).sumSq();
+                       // double xNormSqr = LibMatrixMult.dotProduct(hv, hv, 
k_kp1, k_kp1, m - (k + 1));
+                       double xNormSqr = 0;
+                       for (int j = k + 1; j < m; ++j) {
+                       final double c = hv[k * m + j];
+                       xNormSqr += c * c;
+                       }
+
+                       final double a = (hv[k_kp1] > 0) ? 
-FastMath.sqrt(xNormSqr) : FastMath.sqrt(xNormSqr);
+
+                       secondary[k] = a;
+
+                       if (a != 0.0) {
+                       // apply Householder transform from left and right 
simultaneously
+                       hv[k_kp1] -= a;
+
+                       final double beta = -1 / (a * hv[k_kp1]);
+                       double gamma = 0;
+
+                       // compute a = beta A v, where v is the Householder 
vector
+                       // this loop is written in such a way
+                       // 1) only the upper triangular part of the matrix is 
accessed
+                       // 2) access is cache-friendly for a matrix stored in 
rows
+                       Arrays.fill(z, k + 1, m, 0);
+                       for (int i = k + 1; i < m; ++i) {
+                               final double hKI = hv[km + i];
+                               double zI = hv[i * m + i] * hKI;
+                               for (int j = i + 1; j < m; ++j) {
+                               final double hIJ = hv[i * m + j];
+                               zI += hIJ * hv[k * m + j];
+                               z[j] += hIJ * hKI;
+                               }
+                               z[i] = beta * (z[i] + zI);
+
+                               gamma += z[i] * hv[km + i];
+                       }
+
+                       gamma *= beta / 2;
+
+                       // compute z = z - gamma v
+                       // LibMatrixMult.vectMultiplyAdd(-gamma, hv, z, k_kp1, 
k + 1, m - (k + 1));
+                       for (int i = k + 1; i < m; ++i) {
+                               z[i] -= gamma * hv[km + i];
+                       }
+
+                       // update matrix: A = A - v zT - z vT
+                       // only the upper triangular part of the matrix is 
updated
+                       for (int i = k + 1; i < m; ++i) {
+                               final double hki = hv[km + i];
+                               for (int j = i; j < m; ++j) {
+                               final double hkj = hv[km + j];
+
+                               hv[i * m + j] -= (hki * z[j] + z[i] * hkj);
+                               }
+                       }
+                       }
+               }
+
+               main[m - 1] = hv[(m - 1) * m + m - 1];
+
+               return householderVectors;
+       }
+
+
+       /**
+        * Computes the orthogonal matrix Q using Householder transforms.
+        * The matrix Q is built by applying Householder transforms to the 
input vectors.
+        *
+        * @param hv        The input vector containing the Householder vectors.
+        * @param main      The main diagonal of the matrix.
+        * @param secondary The secondary diagonal of the matrix.
+        * @return The orthogonal matrix Q.
+        */
+       public static MatrixBlock getQ(final double[] hv, double[] main, 
double[] secondary) {
+               final int m = main.length;
+
+               // orthogonal matrix, most operations are column major (TODO)
+               DenseBlock qaB = DenseBlockFactory.createDenseBlock(m, m);
+               double[] qaV = qaB.valuesAt(0);
+
+               // build up first part of the matrix by applying Householder 
transforms
+               for (int k = m - 1; k >= 1; --k) {

Review Comment:
   is there a reason why it should be done in opposite order?



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {
+ 
+               // TODO: Verify matrix is symmetric
+               final double[] mainDiag = new double[in.rlen];
+               final double[] secDiag = new double[in.rlen - 1];
+
+               final MatrixBlock householderVectors = 
transformToTridiagonal(in, mainDiag, secDiag, threads);
+
+               // TODO: Consider using sparse blocks
+               final double[] hv = householderVectors.getDenseBlockValues();
+               MatrixBlock houseHolderMatrix = getQ(hv, mainDiag, secDiag);
+
+               MatrixBlock[] evResult = findEigenVectors(mainDiag, secDiag, 
houseHolderMatrix, EIGEN_MAX_ITER, threads);
+
+               MatrixBlock realEigenValues = evResult[0];
+               MatrixBlock eigenVectors = evResult[1];
+
+               realEigenValues.setNonZeros(realEigenValues.rlen * 
realEigenValues.rlen);
+               eigenVectors.setNonZeros(eigenVectors.rlen * eigenVectors.clen);
+
+               return new MatrixBlock[] { realEigenValues, eigenVectors };
+       }
+
+       private static MatrixBlock transformToTridiagonal(MatrixBlock matrix, 
double[] main, double[] secondary, int threads) {
+               final int m = matrix.rlen;
+
+               // MatrixBlock householderVectors = ;
+               MatrixBlock householderVectors = matrix.extractTriangular(new 
MatrixBlock(m, m, false), false, true, true);
+               if (householderVectors.isInSparseFormat()) {
+                       householderVectors.sparseToDense(threads);      
+               }
+
+               final double[] z = new double[m];
+
+               // TODO: Consider sparse block case
+               final double[] hv = householderVectors.getDenseBlockValues();
+
+               for (int k = 0; k < m - 1; k++) {
+                       final int k_kp1 = k * m + k + 1;
+                       final int km = k * m;
+
+                       // zero-out a row and a column simultaneously
+                       main[k] = hv[km + k];
+
+                       // TODO: may or may not improve, seems it does not
+                       // double xNormSqr = householderVectors.slice(k, k, k + 
1, m - 1).sumSq();
+                       // double xNormSqr = LibMatrixMult.dotProduct(hv, hv, 
k_kp1, k_kp1, m - (k + 1));
+                       double xNormSqr = 0;
+                       for (int j = k + 1; j < m; ++j) {
+                       final double c = hv[k * m + j];

Review Comment:
   please fix all the indentations, you can optionally use (i recommend this) 
our code formatting settings file and apply it on the code parts that you have 
added.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {
+ 
+               // TODO: Verify matrix is symmetric
+               final double[] mainDiag = new double[in.rlen];
+               final double[] secDiag = new double[in.rlen - 1];
+
+               final MatrixBlock householderVectors = 
transformToTridiagonal(in, mainDiag, secDiag, threads);
+
+               // TODO: Consider using sparse blocks
+               final double[] hv = householderVectors.getDenseBlockValues();
+               MatrixBlock houseHolderMatrix = getQ(hv, mainDiag, secDiag);
+
+               MatrixBlock[] evResult = findEigenVectors(mainDiag, secDiag, 
houseHolderMatrix, EIGEN_MAX_ITER, threads);
+
+               MatrixBlock realEigenValues = evResult[0];
+               MatrixBlock eigenVectors = evResult[1];
+
+               realEigenValues.setNonZeros(realEigenValues.rlen * 
realEigenValues.rlen);
+               eigenVectors.setNonZeros(eigenVectors.rlen * eigenVectors.clen);
+
+               return new MatrixBlock[] { realEigenValues, eigenVectors };
+       }
+
+       private static MatrixBlock transformToTridiagonal(MatrixBlock matrix, 
double[] main, double[] secondary, int threads) {
+               final int m = matrix.rlen;
+
+               // MatrixBlock householderVectors = ;
+               MatrixBlock householderVectors = matrix.extractTriangular(new 
MatrixBlock(m, m, false), false, true, true);
+               if (householderVectors.isInSparseFormat()) {
+                       householderVectors.sparseToDense(threads);      
+               }
+
+               final double[] z = new double[m];
+
+               // TODO: Consider sparse block case
+               final double[] hv = householderVectors.getDenseBlockValues();
+
+               for (int k = 0; k < m - 1; k++) {
+                       final int k_kp1 = k * m + k + 1;
+                       final int km = k * m;
+
+                       // zero-out a row and a column simultaneously
+                       main[k] = hv[km + k];
+
+                       // TODO: may or may not improve, seems it does not

Review Comment:
   remove todos that are already verified.



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {

Review Comment:
   i would like to know where the time is spend inside this function call.
   
   is it in transformToTridiagonal, getQ or findEigenVectors?



##########
src/main/java/org/apache/sysds/runtime/matrix/data/LibCommonsMath.java:
##########
@@ -209,6 +218,339 @@ private static MatrixBlock computeSolve(MatrixBlock in1, 
MatrixBlock in2) {
                
                return DataConverter.convertToMatrixBlock(solutionMatrix);
        }
+
+       /**
+        * Computes the eigen decomposition of a symmetric matrix.
+       *
+       * @param in The input matrix to compute the eigen decomposition on.
+       * @param threads The number of threads to use for computation.
+       * @return An array of MatrixBlock objects containing the real eigen 
values and eigen vectors.
+       */
+       public static MatrixBlock[] computeEigenDecompositionSymm(MatrixBlock 
in, int threads) {
+ 
+               // TODO: Verify matrix is symmetric
+               final double[] mainDiag = new double[in.rlen];
+               final double[] secDiag = new double[in.rlen - 1];
+
+               final MatrixBlock householderVectors = 
transformToTridiagonal(in, mainDiag, secDiag, threads);
+
+               // TODO: Consider using sparse blocks
+               final double[] hv = householderVectors.getDenseBlockValues();
+               MatrixBlock houseHolderMatrix = getQ(hv, mainDiag, secDiag);
+
+               MatrixBlock[] evResult = findEigenVectors(mainDiag, secDiag, 
houseHolderMatrix, EIGEN_MAX_ITER, threads);
+
+               MatrixBlock realEigenValues = evResult[0];
+               MatrixBlock eigenVectors = evResult[1];
+
+               realEigenValues.setNonZeros(realEigenValues.rlen * 
realEigenValues.rlen);
+               eigenVectors.setNonZeros(eigenVectors.rlen * eigenVectors.clen);
+
+               return new MatrixBlock[] { realEigenValues, eigenVectors };
+       }
+
+       private static MatrixBlock transformToTridiagonal(MatrixBlock matrix, 
double[] main, double[] secondary, int threads) {
+               final int m = matrix.rlen;
+
+               // MatrixBlock householderVectors = ;
+               MatrixBlock householderVectors = matrix.extractTriangular(new 
MatrixBlock(m, m, false), false, true, true);
+               if (householderVectors.isInSparseFormat()) {
+                       householderVectors.sparseToDense(threads);      
+               }
+
+               final double[] z = new double[m];
+
+               // TODO: Consider sparse block case
+               final double[] hv = householderVectors.getDenseBlockValues();
+
+               for (int k = 0; k < m - 1; k++) {
+                       final int k_kp1 = k * m + k + 1;
+                       final int km = k * m;
+
+                       // zero-out a row and a column simultaneously
+                       main[k] = hv[km + k];
+
+                       // TODO: may or may not improve, seems it does not
+                       // double xNormSqr = householderVectors.slice(k, k, k + 
1, m - 1).sumSq();
+                       // double xNormSqr = LibMatrixMult.dotProduct(hv, hv, 
k_kp1, k_kp1, m - (k + 1));
+                       double xNormSqr = 0;
+                       for (int j = k + 1; j < m; ++j) {
+                       final double c = hv[k * m + j];
+                       xNormSqr += c * c;
+                       }
+
+                       final double a = (hv[k_kp1] > 0) ? 
-FastMath.sqrt(xNormSqr) : FastMath.sqrt(xNormSqr);
+
+                       secondary[k] = a;
+
+                       if (a != 0.0) {
+                       // apply Householder transform from left and right 
simultaneously
+                       hv[k_kp1] -= a;
+
+                       final double beta = -1 / (a * hv[k_kp1]);
+                       double gamma = 0;
+
+                       // compute a = beta A v, where v is the Householder 
vector
+                       // this loop is written in such a way
+                       // 1) only the upper triangular part of the matrix is 
accessed
+                       // 2) access is cache-friendly for a matrix stored in 
rows
+                       Arrays.fill(z, k + 1, m, 0);
+                       for (int i = k + 1; i < m; ++i) {
+                               final double hKI = hv[km + i];
+                               double zI = hv[i * m + i] * hKI;
+                               for (int j = i + 1; j < m; ++j) {
+                               final double hIJ = hv[i * m + j];
+                               zI += hIJ * hv[k * m + j];
+                               z[j] += hIJ * hKI;
+                               }
+                               z[i] = beta * (z[i] + zI);
+
+                               gamma += z[i] * hv[km + i];
+                       }
+
+                       gamma *= beta / 2;
+
+                       // compute z = z - gamma v
+                       // LibMatrixMult.vectMultiplyAdd(-gamma, hv, z, k_kp1, 
k + 1, m - (k + 1));
+                       for (int i = k + 1; i < m; ++i) {
+                               z[i] -= gamma * hv[km + i];
+                       }
+
+                       // update matrix: A = A - v zT - z vT
+                       // only the upper triangular part of the matrix is 
updated
+                       for (int i = k + 1; i < m; ++i) {
+                               final double hki = hv[km + i];
+                               for (int j = i; j < m; ++j) {
+                               final double hkj = hv[km + j];
+
+                               hv[i * m + j] -= (hki * z[j] + z[i] * hkj);
+                               }
+                       }
+                       }
+               }
+
+               main[m - 1] = hv[(m - 1) * m + m - 1];
+
+               return householderVectors;
+       }
+
+
+       /**
+        * Computes the orthogonal matrix Q using Householder transforms.
+        * The matrix Q is built by applying Householder transforms to the 
input vectors.
+        *
+        * @param hv        The input vector containing the Householder vectors.
+        * @param main      The main diagonal of the matrix.
+        * @param secondary The secondary diagonal of the matrix.
+        * @return The orthogonal matrix Q.
+        */
+       public static MatrixBlock getQ(final double[] hv, double[] main, 
double[] secondary) {
+               final int m = main.length;
+
+               // orthogonal matrix, most operations are column major (TODO)
+               DenseBlock qaB = DenseBlockFactory.createDenseBlock(m, m);
+               double[] qaV = qaB.valuesAt(0);
+
+               // build up first part of the matrix by applying Householder 
transforms
+               for (int k = m - 1; k >= 1; --k) {
+                       final int km = k * m;
+                       final int km1m = (k - 1) * m;
+
+                       qaV[km + k] = 1.0;
+                       if (hv[km1m + k] != 0.0) {
+                       final double inv = 1.0 / (secondary[k - 1] * hv[km1m + 
k]);
+
+                       double beta = 1.0 / secondary[k - 1];
+
+                       qaV[km + k] = 1 + beta * hv[km1m + k];
+
+                       // TODO: may speedup vector operations
+                       for (int i = k + 1; i < m; ++i) {
+                               qaV[i * m + k] = beta * hv[km1m + i];
+                       }
+
+                       for (int j = k + 1; j < m; ++j) {
+                               beta = 0;
+                               for (int i = k + 1; i < m; ++i) {
+                               beta += qaV[m * i + j] * hv[km1m + i];
+                               }
+                               beta *= inv;
+                               qaV[m * k + j] = hv[km1m + k] * beta;
+
+                               for (int i = k + 1; i < m; ++i) {
+                               qaV[m * i + j] += beta * hv[km1m + i];
+                               }
+                       }
+                       }
+               }
+
+               qaV[0] = 1.0;
+               MatrixBlock res = new MatrixBlock(m, m, qaB);
+
+               return res;
+       }
+
+
+       /**
+        * Finds the eigen vectors corresponding to the given eigen values 
using the Householder transformation. 
+        * (Dubrulle et al., 1971).
+        *
+        * @param main      The main diagonal of the tridiagonal matrix.
+        * @param secondary The secondary diagonal of the tridiagonal matrix.
+        * @param hhMatrix  The Householder matrix.
+        * @param maxIter   The maximum number of iterations for convergence.
+        * @param threads   The number of threads to use for computation.
+        * @return  An array of two MatrixBlock objects: eigen values and eigen 
vectors.
+        * @throws MaxCountExceededException If the maximum number of 
iterations is exceeded and convergence fails.
+        */
+       private static MatrixBlock[] findEigenVectors(double[] main, double[] 
secondary, final MatrixBlock hhMatrix,
+                       final int maxIter, int threads) {
+
+               DenseBlock hhDense = hhMatrix.getDenseBlock();
+
+               final int n = hhMatrix.rlen;
+               MatrixBlock eigenValues = new MatrixBlock(n, 1, main);
+
+               double[] ev = eigenValues.denseBlock.valuesAt(0);
+               final double[] e = new double[n];
+
+               System.arraycopy(secondary, 0, e, 0, n - 1);
+               e[n - 1] = 0;
+
+               // Determine the largest main and secondary value in absolute 
term.
+               double maxAbsoluteValue = 0;
+               for (int i = 0; i < n; i++) {
+                       maxAbsoluteValue = FastMath.max(maxAbsoluteValue, 
FastMath.abs(ev[i]));
+                       maxAbsoluteValue = FastMath.max(maxAbsoluteValue, 
FastMath.abs(e[i]));
+               }
+               // Make null any main and secondary value too small to be 
significant
+               if (maxAbsoluteValue != 0) {
+                       for (int i = 0; i < n; i++) {
+                       if (FastMath.abs(ev[i]) <= EIGEN_EPS * maxAbsoluteValue 
&& ev[i] != 0.0) {
+                               ev[i] = 0;
+                       }
+                       if (FastMath.abs(e[i]) <= EIGEN_EPS * maxAbsoluteValue 
&& e[i] != 0.0) {
+                               e[i] = 0;
+                       }
+                       }
+               }
+
+               for (int j = 0; j < n; j++) {
+                       int its = 0;
+                       int m;
+                       do {

Review Comment:
   change the do while loops to while do. it is easier to read.



-- 
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-unsubscr...@systemds.apache.org

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

Reply via email to