-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
linalg: Matrix Inverse #828
base: master
Are you sure you want to change the base?
Conversation
As far as this is my first review for |
Great idea @loiseaujc, thanks!
|
From Fortran Monthly call:
|
Am1 = A | ||
|
||
! Invert matrix | ||
call invert(Am1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use this example to show how to use the subroutine interface with the optional output matrix:
Am1 = A | |
! Invert matrix | |
call invert(Am1) | |
! Invert matrix without modifying the original matrix | |
Am1 = A | |
call invert(Am1) | |
! Which would be equivalent to: call invert(A,Am1) |
@@ -0,0 +1,22 @@ | |||
! Matrix inversion example: operator interface | |||
program example_inverse1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would propose to give explicit names to the example files such as:
example_inverse_operator, example_inverse_function, example_inverse_subroutine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @perazz . On overall LGTM. Here are some suggestions.
@@ -777,7 +777,8 @@ Result vector `x` returns the approximate solution that minimizes the 2-norm \( | |||
|
|||
`cond` (optional): Shall be a scalar `real` value cut-off threshold for rank evaluation: `s_i >= cond*maxval(s), i=1:rank`. Shall be a scalar, `intent(in)` argument. | |||
|
|||
`singvals` (optional): Shall be a `real` rank-1 array of the same kind `a` and size at least `minval(shape(a))`, returning the list of singular values `s(i)>=cond*maxval(s)`, in descending order of magnitude. It is an `intent(out)` argument. | |||
`singvals` (optional): Shall be a `real` rank-1 array of the same kind `a` and size at least `m |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a typo?
This operator returns the inverse of a `real` or `complex` square matrix \( A \). | ||
The inverse \( A^{-1} \) is defined such that \( A \cdot A^{-1} = A^{-1} \cdot A = I_n \). | ||
|
||
This interface is equivalent to the function version of [[stdlib_linalg(module):inv(interface)]]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface is equivalent to the function version of [[stdlib_linalg(module):inv(interface)]]. | |
This interface is equivalent to the function [[stdlib_linalg(module):inv(interface)]]. |
{!example/linalg/example_inverse1.f90!} | ||
``` | ||
|
||
## `invert` - Inversion of a square matrix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
## `invert` - Inversion of a square matrix. | |
## `invert` - Inversion of a square matrix |
`inva` (optional): Shall be a rank-2, square, `real` or `complex` array with the same size, and kind as `a`. | ||
On output, it contains the inverse of `a`. | ||
|
||
`pivot` (optional): Shall be a rank-1 array of the same kind and matrix dimension as `a`, providing storage for the diagonal pivot indices. It is an `intent(inout)` arguments, and returns the diagonal pivot indices. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`pivot` (optional): Shall be a rank-1 array of the same kind and matrix dimension as `a`, providing storage for the diagonal pivot indices. It is an `intent(inout)` arguments, and returns the diagonal pivot indices. | |
`pivot` (optional): Shall be a rank-1 array of the same kind and matrix dimension as `a`, that contains the diagonal pivot indices on return. It is an `intent(inout)` argument. |
|
||
### Return value | ||
|
||
Replaces matrix \( A \) with its inverse, \(A^{-1}\). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is not always the case
Replaces matrix \( A \) with its inverse, \(A^{-1}\). | |
Computes the inverse of the matrix \( A \), \(A^{-1}\, and returns it either in \( A \) or in another matrix. |
|
||
`a`: Shall be a rank-2, square, `real` or `complex` array containing the coefficient matrix. It is an `intent(inout)` argument. | ||
|
||
`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument. | |
`err` (optional): Shall be a `type(linalg_state_type)` value. It is an `intent(out)` argument. |
|
||
! Has a pre-allocated pivots storage array been provided? | ||
if (present(pivot)) then | ||
ipiv => pivot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe to allow larger vectors, could something like this be useful:
ipiv => pivot | |
ipiv => pivot(1:n) |
|
||
#:for rk,rt,ri in RC_KINDS_TYPES | ||
#:if rk!="xdp" | ||
tests = [tests,new_unittest("${ri}$_eye_inverse",test_${ri}$_eye_inverse), & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose to add a test for random SPD matrices. In my own implementation I have something like that:
do i = 2, ndim
orimat = 0
call random_number(mat(1:i, 1:i))
orimat(1:i, 1:i) = 0.5_real64 * matmul(mat(1:i, 1:i), transpose(mat(1:i, 1:)))
mat = orimat
call inv(mat)
!identity matrix
identity(1:i, 1:i) = reshape([(merge(1._real64, 0._real64, j/i.eq.mod(j,i)), j = 0, i**2 - 1)], [i, i])
mat(1:i, 1:i) = matmul(mat(1:i, 1:i), orimat(1:i, 1:i))
call check(error , all(abs(mat(1:i, 1:i) - identity(1:i, 1:i)) < tol_real64) &
, 'inv_pd: wrong inverse for '//value2char(i))
if(allocated(error))return
enddo
|
||
! Get optimal worksize (returned in work(1)) (inflate by a 5% safety margin) | ||
nb = stdlib_ilaenv(1,'${ri}$getri',' ',n,-1,-1,-1) | ||
lwork = ceiling(1.05*n*nb,kind=ilp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be careful with integer overflow in this case (I have been bitten several times ;). It might be good to have a check for lwork
Compute the multiplicative inverse of a$A \cdot A^{-1} = A^{-1} \cdot A = I_n$ .
real
orcomplex
square matrix:Based on LAPACK General factorization (
*GETRF
) and inversion (*GETRI
).xdp
subroutine
interfacePrior art
B = inv(A)
inv(A, overwrite_a=False, check_finite=True)
.i.A
Proposed implementation
B = inv(A [, err])
function interfacecall invert(A [, pivot] [, err])
in-place (no-allocation) subroutine interface (optionalpivot
array).inv.A
operator interfacecc: @jalvesz @jvdp1 @loiseaujc @fortran-lang/stdlib