numerically stable inverse of a 2x2 matrix

2024/10/8 8:34:46

In a numerical solver I am working on in C, I need to invert a 2x2 matrix and it then gets multiplied on the right side by another matrix:

C = B . inv(A)

I have been using the following definition of an inverted 2x2 matrix:

a = A[0][0];
b = A[0][1];
c = A[1][0];
d = A[1][1];
invA[0][0] = d/(a*d-b*c);
invA[0][1] = -b/(a*d-b*c);
invA[1][0] = -c/(a*d-b*c);
invA[1][1] = a/(a*d-b*c);

In the first few iterations of my solver this seems to give the correct answers, however, after a few steps things start to grow and eventually explode.

Now, comparing to an implementation using SciPy, I found that the same math does not explode. The only difference I can find is that the SciPy code uses scipy.linalg.inv(), which internally uses LAPACK internally to perform the inversion.

When I replace the call to inv() with the above calculations the Python version does explode, so I'm pretty sure this is the problem. Small differences in the calculations are creeping in, which leads me to believe it is a numerical problem--not entirely surprising for an inversion operation.

I am using double-precision floats (64-bit), hoping that numerical issues would not be a problem, but apparently that is not the case.

But: I would like to solve this in my C code without needing to call out to a library like LAPACK, because the whole reason for porting it to pure C is to get it running on a target system. Moreover, I'd like to understand the problem, not just call out to a black box. Eventually I'd like to it run with single-precision too, if possible.

So, my question is, for such a small matrix, is there a numerically more stable way to calculate the inverse of A?

Thanks.

Edit: Currently trying to figure out if I can just avoid the inversion by solving for C.

Answer

Computing the determinant is not stable. A better way is to use Gauss-Jordan with partial pivoting, that you can work out explicitly easily here.

Solving a 2x2 system

Let us solve the system (use c, f = 1, 0 then c, f = 0, 1 to get the inverse)

a * x + b * y = c
d * x + e * y = f

In pseudo code, this reads

if a == 0 and d == 0 then "singular"if abs(a) >= abs(d):alpha <- d / abeta <- e - b * alphaif beta == 0 then "singular"gamma <- f - c * alphay <- gamma / betax <- (c - b * y) / a
elseswap((a, b, c), (d, e, f))restart

This is stabler than determinant + comatrix (beta is the determinant * some constant, computed in a stable way). You can work out the full pivoting equivalent (ie. potentially swapping x and y, so that the first division by a is such that a is the largest number in magnitude amongst a, b, d, e), and this may be stabler in some circumstances, but the above method has been working well for me.

This is equivalent to performing LU decomposition (store gamma, beta, a, b, c if you want to store this LU decomposition).

Computing the QR decomposition can also be done explicitly (and is also very stable provided you do it correctly), but it is slower (and involves taking square roots). The choice is yours.

Improving accuracy

If you need better accuracy (the above method is stable, but there is some roundoff error, proportional to the ratio of the eigenvalues), you can "solve for the correction".

Indeed, suppose you solved A * x = b for x with the above method. You now compute A * x, and you find that it does not quite equals b, that there is a slight error:

A * x - b = db

Now, if you solve for dx in A * dx = db, you have

A * (x - dx) = b + db - db - ddb = b - ddb

where ddb is the error induced by the numerical solving of A * dx = db, which is typically much smaller than db (since db is much smaller than b).

You can iterate the above procedure, but one step is typically required to restore full machine precision.

https://en.xdnf.cn/q/70142.html

Related Q&A

Type annotating class variable: in init or body?

Lets consider the two following syntax variations:class Foo:x: intdef __init__(self, an_int: int):self.x = an_intAndclass Foo:def __init__(self, an_int: int):self.x = an_intApparently the following cod…

decoding shift-jis: illegal multibyte sequence

Im trying to decode a shift-jis encoded string, like this:string.decode(shift-jis).encode(utf-8)to be able to view it in my program.When I come across 2 shift-jis characters, in hex "0x87 0x54&quo…

Add columns in pandas dataframe dynamically

I have following code to load dataframe import pandas as pdufo = pd.read_csv(csv_path) print(ufo.loc[[0,1,2] , :])which gives following output, see the structure of the csvCity Colors Reported Shape Re…

How do you add input from user into list in Python [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.Want to improve this question? Add details and clarify the problem by editing this post.Closed 9 years ago.Improve…

How to suppress matplotlib inline for a single cell in Jupyter Notebooks/Lab?

I was looking at matplotlib python inline on/off and this kind of solves the problem but when I do plt.ion() all of the Figures pop up (100s of figures). I want to keep them suppressed in a single cel…

Using django-filer, can I chose the folder that images go into, from Unsorted Uploads

Im using django-filer for the first time, and it looks great, and work pretty well.But all my images are being uploaded to the Unsorted Uploads folder, and I cant figure out a way to put them in a spec…

how to use distutils to create executable .zip file?

Python 2.6 and beyond has the ability to directly execute a .zip file if the zip file contains a __main__.py file at the top of the zip archive. Im wanting to leverage this feature to provide preview r…

Pass nested dictionary location as parameter in Python

If I have a nested dictionary I can get a key by indexing like so: >>> d = {a:{b:c}} >>> d[a][b] cAm I able to pass that indexing as a function parameter? def get_nested_value(d, pat…

Correct way to deprecate parameter alias in click

I want to deprecate a parameter alias in click (say, switch from underscores to dashes). For a while, I want both formulations to be valid, but throw a FutureWarning when the parameter is invoked with …

How to rename a file with non-ASCII character encoding to ASCII

I have the file name, "abc枚.xlsx", containing some kind of non-ASCII character encoding and Id like to remove all non-ASCII characters to rename it to "abc.xlsx".Here is what Ive t…