Skip to content

Commit 3bdcc82

Browse files
authored
Merge pull request #806 from perazz/linalg_solve
linalg: solve
2 parents 60ce18f + 5832df5 commit 3bdcc82

11 files changed

+653
-3
lines changed

doc/specs/stdlib_linalg.md

+101
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,107 @@ Specifically, upper Hessenberg matrices satisfy `a_ij = 0` when `j < i-1`, and l
600600
{!example/linalg/example_is_hessenberg.f90!}
601601
```
602602

603+
## `solve` - Solves a linear matrix equation or a linear system of equations.
604+
605+
### Status
606+
607+
Experimental
608+
609+
### Description
610+
611+
This function computes the solution to a linear matrix equation \( A \cdot x = b \), where \( A \) is a square, full-rank, `real` or `complex` matrix.
612+
613+
Result vector or array `x` returns the exact solution to within numerical precision, provided that the matrix is not ill-conditioned.
614+
An error is returned if the matrix is rank-deficient or singular to working precision.
615+
The solver is based on LAPACK's `*GESV` backends.
616+
617+
### Syntax
618+
619+
`Pure` interface:
620+
621+
`x = ` [[stdlib_linalg(module):solve(interface)]] `(a, b)`
622+
623+
Expert interface:
624+
625+
`x = ` [[stdlib_linalg(module):solve(interface)]] `(a, b [, overwrite_a], err)`
626+
627+
### Arguments
628+
629+
`a`: Shall be a rank-2 `real` or `complex` square array containing the coefficient matrix. It is normally an `intent(in)` argument. If `overwrite_a=.true.`, it is an `intent(inout)` argument and is destroyed by the call.
630+
631+
`b`: Shall be a rank-1 or rank-2 array of the same kind as `a`, containing the right-hand-side vector(s). It is an `intent(in)` argument.
632+
633+
`overwrite_a` (optional): Shall be an input logical flag. if `.true.`, input matrix `a` will be used as temporary storage and overwritten. This avoids internal data allocation. This is an `intent(in)` argument.
634+
635+
`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument. The function is not `pure` if this argument is provided.
636+
637+
### Return value
638+
639+
For a full-rank matrix, returns an array value that represents the solution to the linear system of equations.
640+
641+
Raises `LINALG_ERROR` if the matrix is singular to working precision.
642+
Raises `LINALG_VALUE_ERROR` if the matrix and rhs vectors have invalid/incompatible sizes.
643+
If `err` is not present, exceptions trigger an `error stop`.
644+
645+
### Example
646+
647+
```fortran
648+
{!example/linalg/example_solve1.f90!}
649+
650+
{!example/linalg/example_solve2.f90!}
651+
```
652+
653+
## `solve_lu` - Solves a linear matrix equation or a linear system of equations (subroutine interface).
654+
655+
### Status
656+
657+
Experimental
658+
659+
### Description
660+
661+
This subroutine computes the solution to a linear matrix equation \( A \cdot x = b \), where \( A \) is a square, full-rank, `real` or `complex` matrix.
662+
663+
Result vector or array `x` returns the exact solution to within numerical precision, provided that the matrix is not ill-conditioned.
664+
An error is returned if the matrix is rank-deficient or singular to working precision.
665+
If all optional arrays are provided by the user, no internal allocations take place.
666+
The solver is based on LAPACK's `*GESV` backends.
667+
668+
### Syntax
669+
670+
Simple (`Pure`) interface:
671+
672+
`call ` [[stdlib_linalg(module):solve_lu(interface)]] `(a, b, x)`
673+
674+
Expert (`Pure`) interface:
675+
676+
`call ` [[stdlib_linalg(module):solve_lu(interface)]] `(a, b, x [, pivot, overwrite_a, err])`
677+
678+
### Arguments
679+
680+
`a`: Shall be a rank-2 `real` or `complex` square array containing the coefficient matrix. It is normally an `intent(in)` argument. If `overwrite_a=.true.`, it is an `intent(inout)` argument and is destroyed by the call.
681+
682+
`b`: Shall be a rank-1 or rank-2 array of the same kind as `a`, containing the right-hand-side vector(s). It is an `intent(in)` argument.
683+
684+
`x`: Shall be a rank-1 or rank-2 array of the same kind and size as `b`, that returns the solution(s) to the system. It is an `intent(inout)` argument, and must have the `contiguous` property.
685+
686+
`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.
687+
688+
`overwrite_a` (optional): Shall be an input logical flag. if `.true.`, input matrix `a` will be used as temporary storage and overwritten. This avoids internal data allocation. This is an `intent(in)` argument.
689+
690+
### Return value
691+
692+
For a full-rank matrix, returns an array value that represents the solution to the linear system of equations.
693+
694+
Raises `LINALG_ERROR` if the matrix is singular to working precision.
695+
Raises `LINALG_VALUE_ERROR` if the matrix and rhs vectors have invalid/incompatible sizes.
696+
If `err` is not present, exceptions trigger an `error stop`.
697+
698+
### Example
699+
700+
```fortran
701+
{!example/linalg/example_solve3.f90!}
702+
```
703+
603704
## `lstsq` - Computes the least squares solution to a linear matrix equation.
604705

605706
### Status

example/linalg/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,8 @@ ADD_EXAMPLE(blas_gemv)
2020
ADD_EXAMPLE(lapack_getrf)
2121
ADD_EXAMPLE(lstsq1)
2222
ADD_EXAMPLE(lstsq2)
23+
ADD_EXAMPLE(solve1)
24+
ADD_EXAMPLE(solve2)
25+
ADD_EXAMPLE(solve3)
2326
ADD_EXAMPLE(determinant)
2427
ADD_EXAMPLE(determinant2)

example/linalg/example_solve1.f90

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
program example_solve1
2+
use stdlib_linalg_constants, only: sp
3+
use stdlib_linalg, only: solve, linalg_state_type
4+
implicit none
5+
6+
real(sp), allocatable :: A(:,:),b(:),x(:)
7+
8+
! Solve a system of 3 linear equations:
9+
! 4x + 3y + 2z = 25
10+
! -2x + 2y + 3z = -10
11+
! 3x - 5y + 2z = -4
12+
13+
! Note: Fortran is column-major! -> transpose
14+
A = transpose(reshape([ 4, 3, 2, &
15+
-2, 2, 3, &
16+
3,-5, 2], [3,3]))
17+
b = [25,-10,-4]
18+
19+
! Get coefficients of y = coef(1) + x*coef(2) + x^2*coef(3)
20+
x = solve(A,b)
21+
22+
print *, 'solution: ',x
23+
! 5.0, 3.0, -2.0
24+
25+
end program example_solve1
26+

example/linalg/example_solve2.f90

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
program example_solve2
2+
use stdlib_linalg_constants, only: sp
3+
use stdlib_linalg, only: solve, linalg_state_type
4+
implicit none
5+
6+
complex(sp), allocatable :: A(:,:),b(:),x(:)
7+
8+
! Solve a system of 3 complex linear equations:
9+
! 2x + iy + 2z = (5-i)
10+
! -ix + (4-3i)y + 6z = i
11+
! 4x + 3y + z = 1
12+
13+
! Note: Fortran is column-major! -> transpose
14+
A = transpose(reshape([(2.0, 0.0),(0.0, 1.0),(2.0,0.0), &
15+
(0.0,-1.0),(4.0,-3.0),(6.0,0.0), &
16+
(4.0, 0.0),(3.0, 0.0),(1.0,0.0)] , [3,3]))
17+
b = [(5.0,-1.0),(0.0,1.0),(1.0,0.0)]
18+
19+
! Get coefficients of y = coef(1) + x*coef(2) + x^2*coef(3)
20+
x = solve(A,b)
21+
22+
print *, 'solution: ',x
23+
! (1.0947,0.3674) (-1.519,-0.4539) (1.1784,-0.1078)
24+
25+
end program example_solve2
26+

example/linalg/example_solve3.f90

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
program example_solve3
2+
use stdlib_linalg_constants, only: sp,ilp
3+
use stdlib_linalg, only: solve_lu, linalg_state_type
4+
implicit none
5+
6+
integer(ilp) :: test
7+
integer(ilp), allocatable :: pivot(:)
8+
complex(sp), allocatable :: A(:,:),b(:),x(:)
9+
10+
! Solve a system of 3 complex linear equations:
11+
! 2x + iy + 2z = (5-i)
12+
! -ix + (4-3i)y + 6z = i
13+
! 4x + 3y + z = 1
14+
15+
! Note: Fortran is column-major! -> transpose
16+
A = transpose(reshape([(2.0, 0.0),(0.0, 1.0),(2.0,0.0), &
17+
(0.0,-1.0),(4.0,-3.0),(6.0,0.0), &
18+
(4.0, 0.0),(3.0, 0.0),(1.0,0.0)] , [3,3]))
19+
20+
! Pre-allocate x
21+
allocate(b(size(A,2)),pivot(size(A,2)))
22+
allocate(x,mold=b)
23+
24+
! Call system many times avoiding reallocation
25+
do test=1,100
26+
b = test*[(5.0,-1.0),(0.0,1.0),(1.0,0.0)]
27+
call solve_lu(A,b,x,pivot)
28+
print "(i3,'-th solution: ',*(1x,f12.6))", test,x
29+
end do
30+
31+
end program example_solve3
32+

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ set(fppFiles
2525
stdlib_linalg_outer_product.fypp
2626
stdlib_linalg_kronecker.fypp
2727
stdlib_linalg_cross_product.fypp
28+
stdlib_linalg_solve.fypp
2829
stdlib_linalg_determinant.fypp
2930
stdlib_linalg_state.fypp
3031
stdlib_optval.fypp

src/stdlib_linalg.fypp

+96
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module stdlib_linalg
2222
public :: eye
2323
public :: lstsq
2424
public :: lstsq_space
25+
public :: solve
26+
public :: solve_lu
2527
public :: solve_lstsq
2628
public :: trace
2729
public :: outer_product
@@ -228,6 +230,100 @@ module stdlib_linalg
228230
#:endfor
229231
end interface is_hessenberg
230232

233+
! Solve linear system system Ax=b.
234+
interface solve
235+
!! version: experimental
236+
!!
237+
!! Solves the linear system \( A \cdot x = b \) for the unknown vector \( x \) from a square matrix \( A \).
238+
!! ([Specification](../page/specs/stdlib_linalg.html#solve-solves-a-linear-matrix-equation-or-a-linear-system-of-equations))
239+
!!
240+
!!### Summary
241+
!! Interface for solving a linear system arising from a general matrix.
242+
!!
243+
!!### Description
244+
!!
245+
!! This interface provides methods for computing the solution of a linear matrix system.
246+
!! Supported data types include `real` and `complex`. No assumption is made on the matrix
247+
!! structure.
248+
!! The function can solve simultaneously either one (from a 1-d right-hand-side vector `b(:)`)
249+
!! or several (from a 2-d right-hand-side vector `b(:,:)`) systems.
250+
!!
251+
!!@note The solution is based on LAPACK's generic LU decomposition based solvers `*GESV`.
252+
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
253+
!!
254+
#:for nd,ndsuf,nde in ALL_RHS
255+
#:for rk,rt,ri in RC_KINDS_TYPES
256+
#:if rk!="xdp"
257+
module function stdlib_linalg_${ri}$_solve_${ndsuf}$(a,b,overwrite_a,err) result(x)
258+
!> Input matrix a[n,n]
259+
${rt}$, intent(inout), target :: a(:,:)
260+
!> Right hand side vector or array, b[n] or b[n,nrhs]
261+
${rt}$, intent(in) :: b${nd}$
262+
!> [optional] Can A data be overwritten and destroyed?
263+
logical(lk), optional, intent(in) :: overwrite_a
264+
!> [optional] state return flag. On error if not requested, the code will stop
265+
type(linalg_state_type), intent(out) :: err
266+
!> Result array/matrix x[n] or x[n,nrhs]
267+
${rt}$, allocatable, target :: x${nd}$
268+
end function stdlib_linalg_${ri}$_solve_${ndsuf}$
269+
pure module function stdlib_linalg_${ri}$_pure_solve_${ndsuf}$(a,b) result(x)
270+
!> Input matrix a[n,n]
271+
${rt}$, intent(in) :: a(:,:)
272+
!> Right hand side vector or array, b[n] or b[n,nrhs]
273+
${rt}$, intent(in) :: b${nd}$
274+
!> Result array/matrix x[n] or x[n,nrhs]
275+
${rt}$, allocatable, target :: x${nd}$
276+
end function stdlib_linalg_${ri}$_pure_solve_${ndsuf}$
277+
#:endif
278+
#:endfor
279+
#:endfor
280+
end interface solve
281+
282+
! Solve linear system Ax = b using LU decomposition (subroutine interface).
283+
interface solve_lu
284+
!! version: experimental
285+
!!
286+
!! Solves the linear system \( A \cdot x = b \) for the unknown vector \( x \) from a square matrix \( A \).
287+
!! ([Specification](../page/specs/stdlib_linalg.html#solve-lu-solves-a-linear-matrix-equation-or-a-linear-system-of-equations-subroutine-interface))
288+
!!
289+
!!### Summary
290+
!! Subroutine interface for solving a linear system using LU decomposition.
291+
!!
292+
!!### Description
293+
!!
294+
!! This interface provides methods for computing the solution of a linear matrix system using
295+
!! a subroutine. Supported data types include `real` and `complex`. No assumption is made on the matrix
296+
!! structure. Preallocated space for the solution vector `x` is user-provided, and it may be provided
297+
!! for the array of pivot indices, `pivot`. If all pre-allocated work spaces are provided, no internal
298+
!! memory allocations take place when using this interface.
299+
!! The function can solve simultaneously either one (from a 1-d right-hand-side vector `b(:)`)
300+
!! or several (from a 2-d right-hand-side vector `b(:,:)`) systems.
301+
!!
302+
!!@note The solution is based on LAPACK's generic LU decomposition based solvers `*GESV`.
303+
!!@note BLAS/LAPACK backends do not currently support extended precision (``xdp``).
304+
!!
305+
#:for nd,ndsuf,nde in ALL_RHS
306+
#:for rk,rt,ri in RC_KINDS_TYPES
307+
#:if rk!="xdp"
308+
pure module subroutine stdlib_linalg_${ri}$_solve_lu_${ndsuf}$(a,b,x,pivot,overwrite_a,err)
309+
!> Input matrix a[n,n]
310+
${rt}$, intent(inout), target :: a(:,:)
311+
!> Right hand side vector or array, b[n] or b[n,nrhs]
312+
${rt}$, intent(in) :: b${nd}$
313+
!> Result array/matrix x[n] or x[n,nrhs]
314+
${rt}$, intent(inout), contiguous, target :: x${nd}$
315+
!> [optional] Storage array for the diagonal pivot indices
316+
integer(ilp), optional, intent(inout), target :: pivot(:)
317+
!> [optional] Can A data be overwritten and destroyed?
318+
logical(lk), optional, intent(in) :: overwrite_a
319+
!> [optional] state return flag. On error if not requested, the code will stop
320+
type(linalg_state_type), optional, intent(out) :: err
321+
end subroutine stdlib_linalg_${ri}$_solve_lu_${ndsuf}$
322+
#:endif
323+
#:endfor
324+
#:endfor
325+
end interface solve_lu
326+
231327
! Least squares solution to system Ax=b, i.e. such that the 2-norm abs(b-Ax) is minimized.
232328
interface lstsq
233329
!! version: experimental

0 commit comments

Comments
 (0)