Skip to content

Commit eb77455

Browse files
authored
Merge branch 'fortran-lang:master' into subprocess
2 parents c03655a + 095219e commit eb77455

File tree

6 files changed

+155
-28
lines changed

6 files changed

+155
-28
lines changed

doc/specs/stdlib_linalg.md

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -239,37 +239,34 @@ Pure function.
239239

240240
### Description
241241

242-
Construct the identity matrix.
242+
Constructs the identity matrix.
243243

244244
### Syntax
245245

246-
`I = ` [[stdlib_linalg(module):eye(function)]] `(dim1 [, dim2])`
246+
`I = ` [[stdlib_linalg(module):eye(function)]] `(dim1 [, dim2] [, mold])`
247247

248248
### Arguments
249249

250-
`dim1`: Shall be a scalar of default type `integer`.
251-
This is an `intent(in)` argument.
252-
253-
`dim2`: Shall be a scalar of default type `integer`.
254-
This is an `intent(in)` and `optional` argument.
250+
- `dim1`: A scalar of type `integer`. This is an `intent(in)` argument and specifies the number of rows.
251+
- `dim2`: A scalar of type `integer`. This is an optional `intent(in)` argument specifying the number of columns. If not provided, the matrix is square (`dim1 = dim2`).
252+
- `mold`: A scalar of any supported `integer`, `real`, or `complex` type. This is an optional `intent(in)` argument. If provided, the returned identity matrix will have the same type and kind as `mold`. If not provided, the matrix will be of type `real(real64)` by default.
255253

256254
### Return value
257255

258-
Return the identity matrix, i.e. a matrix with ones on the main diagonal and zeros elsewhere. The return value is of type `integer(int8)`.
259-
The use of `int8` was suggested to save storage.
256+
Returns the identity matrix, with ones on the main diagonal and zeros elsewhere.
257+
258+
- By default, the return value is of type `real(real64)`, which is recommended for arithmetic safety.
259+
- If the `mold` argument is provided, the return value will match the type and kind of `mold`, allowing for arbitrary `integer`, `real`, or `complex` return types.
260260

261-
#### Warning
261+
### Example
262262

263-
Since the result of `eye` is of `integer(int8)` type, one should be careful about using it in arithmetic expressions. For example:
264263
```fortran
265-
!> Be careful
266-
A = eye(2,2)/2 !! A == 0.0
267-
!> Recommend
268-
A = eye(2,2)/2.0 !! A == diag([0.5, 0.5])
264+
!> Return default type (real64)
265+
A = eye(2,2)/2 !! A == diag([0.5_dp, 0.5_dp])
266+
!> Return 32-bit complex
267+
A = eye(2,2, mold=(0.0,0.0))/2 !! A == diag([(0.5,0.5), (0.5,0.5)])
269268
```
270269

271-
### Example
272-
273270
```fortran
274271
{!example/linalg/example_eye1.f90!}
275272
```
@@ -509,6 +506,37 @@ Returns a `logical` scalar that is `.true.` if the input matrix is skew-symmetri
509506
{!example/linalg/example_is_skew_symmetric.f90!}
510507
```
511508

509+
## `hermitian` - Compute the Hermitian version of a rank-2 matrix
510+
511+
### Status
512+
513+
Experimental
514+
515+
### Description
516+
517+
Compute the Hermitian version of a rank-2 matrix.
518+
For `complex` matrices, the function returns the conjugate transpose (`conjg(transpose(a))`).
519+
For `real` or `integer` matrices, the function returns the transpose (`transpose(a)`).
520+
521+
### Syntax
522+
523+
`h = ` [[stdlib_linalg(module):hermitian(interface)]] `(a)`
524+
525+
### Arguments
526+
527+
`a`: Shall be a rank-2 array of type `integer`, `real`, or `complex`. The input matrix `a` is not modified.
528+
529+
### Return value
530+
531+
Returns a rank-2 array of the same shape and type as `a`. If `a` is of type `complex`, the Hermitian matrix is computed as `conjg(transpose(a))`.
532+
For `real` or `integer` types, it is equivalent to the intrinsic `transpose(a)`.
533+
534+
### Example
535+
536+
```fortran
537+
{!example/linalg/example_hermitian.f90!}
538+
```
539+
512540
## `is_hermitian` - Checks if a matrix is Hermitian
513541

514542
### Status

example/linalg/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ADD_EXAMPLE(diag5)
66
ADD_EXAMPLE(eye1)
77
ADD_EXAMPLE(eye2)
88
ADD_EXAMPLE(is_diagonal)
9+
ADD_EXAMPLE(hermitian)
910
ADD_EXAMPLE(is_hermitian)
1011
ADD_EXAMPLE(is_hessenberg)
1112
ADD_EXAMPLE(is_skew_symmetric)

example/linalg/example_eye1.f90

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ program example_eye1
55
real :: a(3, 3)
66
real :: b(2, 3) !! Matrix is non-square.
77
complex :: c(2, 2)
8-
I = eye(2) !! [1,0; 0,1]
9-
A = eye(3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
10-
A = eye(3, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
11-
B = eye(2, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0]
12-
C = eye(2, 2) !! [(1.0,0.0),(0.0,0.0); (0.0,0.0),(1.0,0.0)]
8+
I = eye(2) !! [1,0; 0,1]
9+
A = eye(3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
10+
A = eye(3, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0; 0.0,0.0,1.0]
11+
B = eye(2, 3) !! [1.0,0.0,0.0; 0.0,1.0,0.0]
12+
C = eye(2, 2) !! [(1.0,0.0),(0.0,0.0); (0.0,0.0),(1.0,0.0)]
1313
C = (1.0, 1.0)*eye(2, 2) !! [(1.0,1.0),(0.0,0.0); (0.0,0.0),(1.0,1.0)]
1414
end program example_eye1

example/linalg/example_hermitian.f90

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
! Example program demonstrating the usage of hermitian
2+
program example_hermitian
3+
use stdlib_linalg, only: hermitian
4+
implicit none
5+
6+
complex, dimension(2, 2) :: A, AT
7+
8+
! Define input matrices
9+
A = reshape([(1,2),(3,4),(5,6),(7,8)],[2,2])
10+
11+
! Compute Hermitian matrices
12+
AT = hermitian(A)
13+
14+
print *, "Original Complex Matrix:"
15+
print *, A
16+
print *, "Hermitian Complex Matrix:"
17+
print *, AT
18+
19+
end program example_hermitian

src/stdlib_linalg.fypp

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ module stdlib_linalg
4949
public :: is_diagonal
5050
public :: is_symmetric
5151
public :: is_skew_symmetric
52+
public :: hermitian
5253
public :: is_hermitian
5354
public :: is_triangular
5455
public :: is_hessenberg
@@ -189,6 +190,16 @@ module stdlib_linalg
189190
#:endfor
190191
end interface
191192

193+
! Identity matrix
194+
interface eye
195+
!! version: experimental
196+
!!
197+
!! Constructs the identity matrix
198+
!! ([Specification](../page/specs/stdlib_linalg.html#eye-construct-the-identity-matrix))
199+
#:for k1, t1 in RCI_KINDS_TYPES
200+
module procedure eye_${t1[0]}$${k1}$
201+
#:endfor
202+
end interface eye
192203

193204
! Outer product (of two vectors)
194205
interface outer_product
@@ -299,6 +310,31 @@ module stdlib_linalg
299310
#:endfor
300311
end interface is_hermitian
301312

313+
interface hermitian
314+
!! version: experimental
315+
!!
316+
!! Computes the Hermitian version of a rank-2 matrix.
317+
!! For complex matrices, this returns `conjg(transpose(a))`.
318+
!! For real or integer matrices, this returns `transpose(a)`.
319+
!!
320+
!! Usage:
321+
!! ```
322+
!! A = reshape([(1, 2), (3, 4), (5, 6), (7, 8)], [2, 2])
323+
!! AH = hermitian(A)
324+
!! ```
325+
!!
326+
!! [Specification](../page/specs/stdlib_linalg.html#hermitian-compute-the-hermitian-version-of-a-rank-2-matrix)
327+
!!
328+
329+
#:for k1, t1 in RCI_KINDS_TYPES
330+
pure module function hermitian_${t1[0]}$${k1}$(a) result(ah)
331+
${t1}$, intent(in) :: a(:,:)
332+
${t1}$ :: ah(size(a, 2), size(a, 1))
333+
end function hermitian_${t1[0]}$${k1}$
334+
#:endfor
335+
336+
end interface hermitian
337+
302338

303339
! Check for triangularity
304340
interface is_triangular
@@ -1411,24 +1447,27 @@ contains
14111447
!>
14121448
!> Constructs the identity matrix.
14131449
!> ([Specification](../page/specs/stdlib_linalg.html#eye-construct-the-identity-matrix))
1414-
pure function eye(dim1, dim2) result(result)
1450+
#:for k1, t1 in RCI_KINDS_TYPES
1451+
pure function eye_${t1[0]}$${k1}$(dim1, dim2, mold) result(result)
14151452

14161453
integer, intent(in) :: dim1
14171454
integer, intent(in), optional :: dim2
1418-
integer(int8), allocatable :: result(:, :)
1455+
${t1}$, intent(in) #{if t1 == 'real(dp)'}#, optional #{endif}#:: mold
1456+
${t1}$, allocatable :: result(:, :)
14191457

14201458
integer :: dim2_
14211459
integer :: i
14221460

14231461
dim2_ = optval(dim2, dim1)
14241462
allocate(result(dim1, dim2_))
14251463

1426-
result = 0_int8
1464+
result = 0
14271465
do i = 1, min(dim1, dim2_)
1428-
result(i, i) = 1_int8
1466+
result(i, i) = 1
14291467
end do
14301468

1431-
end function eye
1469+
end function eye_${t1[0]}$${k1}$
1470+
#:endfor
14321471

14331472
#:for k1, t1 in RCI_KINDS_TYPES
14341473
function trace_${t1[0]}$${k1}$(A) result(res)
@@ -1555,6 +1594,17 @@ contains
15551594
end function is_hermitian_${t1[0]}$${k1}$
15561595
#:endfor
15571596

1597+
#:for k1, t1 in RCI_KINDS_TYPES
1598+
pure module function hermitian_${t1[0]}$${k1}$(a) result(ah)
1599+
${t1}$, intent(in) :: a(:,:)
1600+
${t1}$ :: ah(size(a, 2), size(a, 1))
1601+
#:if t1.startswith('complex')
1602+
ah = conjg(transpose(a))
1603+
#:else
1604+
ah = transpose(a)
1605+
#:endif
1606+
end function hermitian_${t1[0]}$${k1}$
1607+
#:endfor
15581608

15591609
#:for k1, t1 in RCI_KINDS_TYPES
15601610
function is_triangular_${t1[0]}$${k1}$(A,uplo) result(res)

test/linalg/test_linalg.fypp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
module test_linalg
55
use testdrive, only : new_unittest, unittest_type, error_type, check, skip_test
66
use stdlib_kinds, only: sp, dp, xdp, qp, int8, int16, int32, int64
7-
use stdlib_linalg, only: diag, eye, trace, outer_product, cross_product, kronecker_product
7+
use stdlib_linalg, only: diag, eye, trace, outer_product, cross_product, kronecker_product, hermitian
88
use stdlib_linalg_state, only: linalg_state_type, LINALG_SUCCESS, linalg_error_handling
99

1010
implicit none
@@ -52,6 +52,9 @@ contains
5252
new_unittest("trace_int64", test_trace_int64), &
5353
#:for k1, t1 in RCI_KINDS_TYPES
5454
new_unittest("kronecker_product_${t1[0]}$${k1}$", test_kronecker_product_${t1[0]}$${k1}$), &
55+
#:endfor
56+
#:for k1, t1 in CMPLX_KINDS_TYPES
57+
new_unittest("hermitian_${t1[0]}$${k1}$", test_hermitian_${t1[0]}$${k1}$), &
5558
#:endfor
5659
new_unittest("outer_product_rsp", test_outer_product_rsp), &
5760
new_unittest("outer_product_rdp", test_outer_product_rdp), &
@@ -597,6 +600,32 @@ contains
597600
end subroutine test_kronecker_product_${t1[0]}$${k1}$
598601
#:endfor
599602

603+
#:for k1, t1 in CMPLX_KINDS_TYPES
604+
subroutine test_hermitian_${t1[0]}$${k1}$(error)
605+
!> Error handling
606+
type(error_type), allocatable, intent(out) :: error
607+
integer, parameter :: m = 2, n = 3
608+
${t1}$, dimension(m,n) :: A
609+
${t1}$, dimension(n,m) :: AT, expected, diff
610+
real(${k1}$), parameter :: tol = 1.e-6_${k1}$
611+
612+
integer :: i,j
613+
614+
do concurrent (i=1:m,j=1:n)
615+
A (i,j) = cmplx(i,-j,kind=${k1}$)
616+
expected(j,i) = cmplx(i,+j,kind=${k1}$)
617+
end do
618+
619+
620+
AT = hermitian(A)
621+
622+
diff = AT - expected
623+
624+
call check(error, all(abs(diff) < abs(tol)), "hermitian: all(abs(diff) < abs(tol)) failed")
625+
626+
end subroutine test_hermitian_${t1[0]}$${k1}$
627+
#:endfor
628+
600629
subroutine test_outer_product_rsp(error)
601630
!> Error handling
602631
type(error_type), allocatable, intent(out) :: error

0 commit comments

Comments
 (0)