0

I have a recursive function to calculate the inverse of an upper triangular matrix. I have divided the matrix into Top, Bottom and Corner sections and then followed the methodology as laid down in https://math.stackexchange.com/a/2333418. Here is a pseudocode form:

//A diagram structure of the Matrix
Matrix = [Top Corner]
         [0   Bottom]

Matrix multiply_matrix(Matrix A, Matrix B){
    Simple Code to multiply two matrices and return a Matrix
}

Matrix simple_inverse(Matrix A){
    Simple Code to get inverse of a 2x2 Matrix
}

Matrix inverse_matrix(Matrix A){
   //Creating an empty A_inv matrix of dimension equal to A
   Matrix A_inv;
   if(A.dimension == 2){
       A_inv = simple_inverse(A) 
   } 
   else{
       Top_inv = inverse_matrix(Top);
       (Code to check Top*Top_inv == Identity Matrix)

       Bottom_inv = inverse_matrix(Bottom);
       (Code to check Bottom*Bottom_inv == Identity Matrix)

       Corner_inv = multiply_matrix(Top_inv, Corner);
       Corner_inv = multiply_matrix(Corner_inv, Bottom_inv);
       Corner_inv = negate(Corner_inv);    //Just a function for negation of the matrix elements

       //Code to copy Top_inv, Bottom_inv and Corner_inv to A_inv
       ...
       ...
   }
   return A_inv;
}

int main(){
    matrix A = {An upper triangular matrix with random integers between 1 and 9};
    A_inv = inverse_matrix(A);
    test_matrix = multiply_matrix(A, A_inv);
    (Code to Raise error if test_matrix != Identity matrix)
}

For simplicity I have implemented the code such that only power of 2 dimension matrices are supported.

My problem is that I have tested this code for matrix dimensions of 2, 4, 8, 16, 32 and 64. All of these pass all of the assertion checks as shown in code. But for matrix dimension of 128 I get failure is the assertion in main(). And when I check, I observer that the test_matrix is not Identity matrix. Some non-diagonal elements are not equal to 0. I am wondering what could be the reason for this:-

  1. I am using C++ std::vector<std::vector<double>> for Matrix representation.
  2. Since the data type is double the non-diagonal elements of test_matrix for cases 2, 4, 8, ..., 64 do have some value but very small. For example, -9.58122e-14
  3. All my matrices at any recursion stage are square matrix
  4. I am performing checks that Top*Top_inv = Identity and Bottom*Bottom_inv = Identity.
  5. Finally, for dimensions 2, 4, ..., 64 I generated random numbers(b/w 1 and 10) to create my upper triangular matrix. Since, these cases passed, I guess my mathematical implementation is correct.

I feel like there is some aspect of C++ datatypes about double which I am unaware of that could be causing the error. Otherwise the sudden error from 64->128 doesn't make sense.

Tapojyoti Mandal
  • 742
  • 1
  • 5
  • 14
  • 1
    When increasing size, random matrices are more and more ill-conditioned, which increases final rouding errors, even with `double`. Here, you can evaluate it by calculating the ratio between the largest diagonal element and the smallest one (in absolute value). – Damien Feb 09 '20 at 07:26

1 Answers1

1

Could you please elaborate on how the matrix == identity operation is implemented? My guess is that the problem might be resumed to the floating point comparison.

The matrix inversion can be O(n^3) in the worst case. This means that, as the matrix size increases, the amount of computations involved also increase. Real numbers cannot be perfectly represented even when using 64 bit floating point, they are always an approximation.

For operations such as matrix inversion this can cause problems of numerical error propagation, due to the loss of precision on the accumulated multiply adds operations.

For this, there has been discussions already in the StackOverflow: How should I do floating point comparison?

EDIT: Other thing to consider if the full matrix is actually invertible. Perhaps the Top and/or Bottom matrices are invertible, but the full matrix (when composing with the Corner matrix) is not.

André Caceres
  • 719
  • 4
  • 15
  • I don't think that matrix==identity calculation has the bug. Because I have code to check the elements of "test_matrix". The test_matrix is supposed to be almost equivalent to Identity matrix, but that is what fails in my case. And what's interesting is that only elements in "Corner" region of matrix have value which is non-zero. So, "numerical error propagation" could be the issue, but my "Top" and "Bottom" matrices are correct, so not sure why the "Corner" matrix calculation would go haywire. – Tapojyoti Mandal Feb 09 '20 at 00:27
  • Then I might be way off here, but, what if top and bottom matrices are non-singular, but the full matrix is singular or has bad conditioning? – André Caceres Feb 09 '20 at 00:32
  • 1
    @Caceres I think your idea of "numerical error propagation" is correct. For experimentation I changed my datatype from "double" to float". And now I am getting errors for matrix dimensions of 32 and 64 as well. My guess is that, in matrix multiplication ```C[i][j] += A[i][k]*B[k][j];``` is where the error propagation is occurring. But I am not sure how to resolve this. – Tapojyoti Mandal Feb 09 '20 at 01:00
  • I'm afraid there is no well defined solution for this. However, I might suggest using an alternative solution by scaling. If the elements in the matrices you are multiplying are too large or too small (as the inverse matrices can be), you can apply a scale factor on the matrix to change their values to a more suitable interval ([0,1] for instance) before the multiplication, and then use the inverse scale on the result to get the correct answer. It adds more operations, however, as they are done with better conditioning, the precision will be better. – André Caceres Feb 09 '20 at 01:31
  • 1
    Note: triangular matroces are theoretically convertible when all diagonal elements are not null. The problem here seems ill-conditioning of large random matrices – Damien Feb 09 '20 at 07:30
  • 1
    @Damien Yeah, you are correct. My matrix is ill-conditioned. I think I am fine with this, as I understood what the underlying cause of the error is. Thanks!! – Tapojyoti Mandal Feb 11 '20 at 16:38