Skip to content
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

Provide BLAS, LAPACK backends and interfaces #772

Merged
merged 30 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f3ac970
Upload BLAS/LAPACK, create preprocessor directives
perazz Mar 11, 2024
5882ad6
enable fpm deployment
perazz Mar 11, 2024
ac65112
update `fpm` version in CI
perazz Mar 11, 2024
c25e3ff
add tests
perazz Mar 11, 2024
ce52faf
typo: `getri`
perazz Mar 11, 2024
3e8c5b6
safeguards for qp procedure templates
perazz Mar 11, 2024
29eeec2
public qp interfaces
perazz Mar 11, 2024
8be6484
more `WITH_QP` guards
perazz Mar 11, 2024
a937382
skip unsupported `xdp` precision
perazz Mar 11, 2024
a356f14
Delete .test_trapz.fypp.swp
perazz Mar 11, 2024
2ae057f
unify pre-processing of blas/lapack sources
perazz Mar 12, 2024
edfeb59
OpenMP: replace `cpp` macros with `!$` conditional compilation
perazz Mar 14, 2024
da5d90c
force `example.dat` back into repo
perazz Mar 14, 2024
d379e9c
free-form `!$omp` continuation style
perazz Mar 14, 2024
2be3340
indent OpenMP sentinels
perazz Mar 23, 2024
592e085
remove `FPM_DEPLOYMENT`
perazz Mar 24, 2024
5785f6c
Update src/stdlib_linalg_constants.fypp
perazz Mar 24, 2024
fa3f147
Merge branch 'blas_lapack_backend' of github.com:perazz/stdlib into b…
perazz Mar 24, 2024
281b068
Document BLAS/LAPACK backends
perazz Mar 26, 2024
4586f32
typo
perazz Mar 26, 2024
3c2349f
Update doc/specs/stdlib_linalg.md
perazz Mar 26, 2024
464aba4
Update doc/specs/stdlib_linalg.md
perazz Mar 26, 2024
a56d685
Update doc/specs/stdlib_linalg.md
perazz Mar 26, 2024
819f2b2
add Licensing information
perazz Mar 26, 2024
a46b86f
add `Syntax` section
perazz Mar 26, 2024
ae6c009
clarify fpm macros
perazz Mar 26, 2024
545b4c3
link to the conversion script
perazz Mar 26, 2024
e30b2ec
dnrm2/snrm2: fix missing interface type
perazz Mar 27, 2024
745bcf8
shorten doc comment
perazz Mar 27, 2024
c12b3c3
lapack interface: import procedure interfaces
perazz Mar 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/fpm-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ jobs:
--slave /usr/bin/gcov gcov /usr/bin/gcov-${{ env.GCC_V }}

- name: Install fpm latest release
uses: fortran-lang/setup-fpm@v3
uses: fortran-lang/setup-fpm@v5
with:
fpm-version: 'v0.4.0'
fpm-version: 'v0.10.0'

- name: Run fpm test ⚙
run: |
Expand Down
3 changes: 3 additions & 0 deletions ci/fpm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ copyright = "2019-2021 stdlib contributors"
[dev-dependencies]
test-drive.git = "https://github.com/fortran-lang/test-drive"
test-drive.tag = "v0.4.0"

[preprocess]
[preprocess.cpp]
7 changes: 7 additions & 0 deletions cmake/stdlib.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,10 @@ function (fypp_f90 fyppopts fyppfiles f90files)
preprocess("${FYPP}" "${fyppopts}" "fypp" "f90" "${fyppfiles}" _f90files)
set(${f90files} ${_f90files} PARENT_SCOPE)
endfunction()

# For fortran sources that contain C preprocessor flags: create ".F90" files
function (fypp_f90pp fyppopts fyppfiles F90files)
preprocess("${FYPP}" "${fyppopts}" "fypp" "F90" "${fyppfiles}" _F90files)
set(${F90files} ${_F90files} PARENT_SCOPE)
endfunction()

170 changes: 170 additions & 0 deletions doc/specs/stdlib_linalg.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,176 @@ title: linalg

[TOC]

The `stdlib` linear algebra library provides high-level APIs for dealing with common linear algebra operations.

## BLAS and LAPACK

### Status

Experimental

### Description

`BLAS` and `LAPACK` backends provide efficient low level implementations of many linear algebra algorithms, and are employed for non-trivial operators.
A Modern Fortran version of the [Reference-LAPACK 3.10.1](http://github.com/reference-LAPACK) implementation is provided as a backend.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my information (not a criticism): why did you use 3.10.1, instead of the version 3.12.0?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed that other libraries use older versions, so I wanted to stay on the safe side to avoid potential issues from the newest changes.
For example, NumPy uses 3.2: https://github.com/numpy/numpy/blob/c3694335faffe35e3d961feffefdc0a4b9a665da/numpy/linalg/lapack_lite/f2c_c_lapack.c#L76-L79
Apple uses 3.9.1: https://developer.apple.com/documentation/accelerate/blas/

I agree it would be nice to gradually move towards the newer versions and hopefully it shouldn't be a big deal, since most of the process is automated

Modern Fortran modules with full explicit typing features are provided after an
[automated conversion](https://github.com/perazz/fortran-lapack/blob/main/scripts/modularize_blas.py)
of the legacy codes:
- [stdlib_linalg_blas(module)], [stdlib_linalg_lapack(module)] provide kind-agnostic interfaces to all functions.
- Both libraries are available for 32- (`sp`), 64- (`dp`) and 128-bit (`qp`) `real` and `complex` numbers (the latter if available in the current build)
- Free format, lower-case style
- `implicit none(type, external)` applied to all procedures and modules
- `intent` added and all `pure` procedures where possible
- All procedure names are prefixed with `stdlib_`, while their generic interface is the same as the BLAS/LAPACK default, with the header character dropped. For example, `stdlib_dgemv`, `stdlib_sgemv`, etc. provide implementations for matrix-vector multiply, while the generic interface is named `gemv`
- F77-style `parameter`s removed, and all numeric constants have been generalized with KIND-dependent Fortran intrinsics.
- preprocessor-based OpenMP directives retained.
The single-source module structure hopefully allows for cross-procedural inlining which is otherwise impossible without link-time optimization.

When available, highly optimized libraries that take advantage of specialized processor instructions should be preferred over the `stdlib` implementation.
Examples of such libraries are: OpenBLAS, MKL (TM), Accelerate, and ATLAS. In order to enable their usage, simply ensure that the following pre-processor macros are defined:
perazz marked this conversation as resolved.
Show resolved Hide resolved

- `STDLIB_EXTERNAL_BLAS` wraps all BLAS procedures (except for the 128-bit ones) to an external library
- `STDLIB_EXTERNAL_LAPACK` wraps all LAPACK procedures (except for the 128-bit ones) to an external library

These can be enabled during the build process. For example, with CMake, one can enable these preprocessor directives using `add_compile_definitions(STDLIB_EXTERNAL_BLAS STDLIB_EXTERNAL_LAPACK)`.
The same is possible from the `fpm` branch, where the `cpp` preprocessor is enabled by default. For example, the macros can be added to the project's manifest:

```toml
[dependencies]
stdlib="*"

# Macros are only needed if using an external library
[preprocess]
[preprocess.cpp]
jvdp1 marked this conversation as resolved.
Show resolved Hide resolved
macros = ["STDLIB_EXTERNAL_BLAS", "STDLIB_EXTERNAL_LAPACK"]
```

or directly via compiler flags:

`fpm build --flag "-DSTDLIB_EXTERNAL_BLAS -DSTDLIB_EXTERNAL_LAPACK -lblas -llapack"`.

### Syntax

All procedures in the `BLAS` and `LAPACK` backends follow the standard interfaces from the
[Reference LAPACK](https://www.netlib.org/lapack/). So, the online [Users Guide](https://www.netlib.org/lapack/explore-html/)
should be consulted for the full API and descriptions of procedure arguments and their usage.

The `stdlib` implementation makes both kind-agnostic and specific procedure interfaces available via modules
[stdlib_linalg_blas(module)] and [stdlib_linalg_lapack(module)]. Because all procedures start with a letter
[that indicates the base datatype](https://www.netlib.org/lapack/lug/node24.html), the `stdlib` generic
interface drops the heading letter and contains all kind-dependent implementations. For example, the generic
interface to the `axpy` function looks like:

```fortran
!> AXPY: constant times a vector plus a vector.
interface axpy
module procedure stdlib_saxpy
module procedure stdlib_daxpy
module procedure stdlib_qaxpy
module procedure stdlib_caxpy
module procedure stdlib_zaxpy
module procedure stdlib_waxpy
end interface axpy
```

The generic interface is the endpoint for using an external library. Whenever the latter is used, references
to the internal `module procedure`s are replaced with interfaces to the external library,
for example:

```fortran
!> AXPY: constant times a vector plus a vector.
interface axpy
pure subroutine caxpy(n,ca,cx,incx,cy,incy)
import sp,dp,qp,ilp,lk
implicit none(type,external)
complex(sp), intent(in) :: ca,cx(*)
integer(ilp), intent(in) :: incx,incy,n
complex(sp), intent(inout) :: cy(*)
end subroutine caxpy
! [....]
module procedure stdlib_qaxpy
end interface axpy
```

Note that the 128-bit functions are only provided by `stdlib` and always point to the internal implementation.
Because 128-bit precision is identified as [stdlib_kinds(module):qp], initials for 128-bit procedures were
labelled as `q` (quadruple-precision reals) and `w` ("wide" or quadruple-precision complex numbers).
Extended precision ([stdlib_kinds(module):xdp]) calculations are currently not supported.

### Example

```fortran
{!example/linalg/example_blas_gemv.f90!}
```

```fortran
{!example/linalg/example_lapack_getrf.f90!}
```

### Licensing

The Fortran Standard Library is distributed under the MIT License. `LAPACK` and its contained `BLAS` are a
freely-available software package. They are available from [netlib](https://www.netlib.org/lapack/) via anonymous
ftp and the World Wide Web. Thus, they can be included in commercial software packages (and have been).
The license used for the `BLAS` and `LAPACK` backends is the [modified BSD license](https://www.netlib.org/lapack/LICENSE.txt).

The header of the `LICENSE.txt` file has as its licensing requirements:

Copyright (c) 1992-2013 The University of Tennessee and The University
of Tennessee Research Foundation. All rights
reserved.
Copyright (c) 2000-2013 The University of California Berkeley. All
rights reserved.
Copyright (c) 2006-2013 The University of Colorado Denver. All rights
reserved.

$COPYRIGHT$

Additional copyrights may follow

$HEADER$

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer listed
in this license in the documentation and/or other materials
provided with the distribution.

- Neither the name of the copyright holders nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

The copyright holders provide no reassurances that the source code
provided does not infringe any patent, copyright, or any other
intellectual property rights of third parties. The copyright holders
disclaim any liability to any recipient for claims brought against
recipient by any third party for infringement of that parties
intellectual property rights.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

So the license for the `LICENSE.txt` code is compatible with the use of
modified versions of the code in the Fortran Standard Library under the MIT license.
Credit for the `BLAS`, `LAPACK` libraries should be given to the [LAPACK authors](https://www.netlib.org/lapack/contributor-list.html).
According to the original license, we also changed the name of the routines and commented the changes made
to the original.

## `diag` - Create a diagonal array or extract the diagonal elements of an array

### Status
Expand Down
14 changes: 14 additions & 0 deletions example/linalg/example_blas_gemv.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
program example_gemv
use stdlib_linalg, only: eye
use stdlib_linalg_blas, only: sp,gemv
implicit none(type,external)
real(sp) :: A(2, 2), B(2)
B = [1.0,2.0]
A = eye(2)

! Use legacy BLAS interface
call gemv('No transpose',m=size(A,1),n=size(A,2),alpha=1.0,a=A,lda=size(A,1),x=B,incx=1,beta=0.0,y=B,incy=1)

print *, B ! returns 1.0 2.0

end program example_gemv
14 changes: 14 additions & 0 deletions example/linalg/example_lapack_getrf.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
program example_getrf
use stdlib_linalg, only: eye
use stdlib_linalg_lapack, only: dp,ilp,getrf
implicit none(type,external)
real(dp) :: A(3, 3)
integer(ilp) :: ipiv(3),info

A = eye(3)

! LAPACK matrix factorization interface (overwrite result)
call getrf(size(A,1),size(A,2),A,size(A,1),ipiv,info)
print *, info ! info==0: Success!

end program example_getrf
1 change: 0 additions & 1 deletion include/common.fypp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
#! Whether Fortran 90 compatible code should be generated
#:set VERSION90 = defined('VERSION90')


#! Ranks to be generated when templates are created
#:if not defined('MAXRANK')
#:if VERSION90
Expand Down
22 changes: 22 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,29 @@ set(fppFiles
stdlib_version.fypp
)

# Preprocessed files to contain preprocessor directives -> .F90
set(cppFiles
stdlib_linalg_constants.fypp
stdlib_linalg_blas.fypp
stdlib_linalg_blas_aux.fypp
stdlib_linalg_blas_s.fypp
stdlib_linalg_blas_d.fypp
stdlib_linalg_blas_q.fypp
stdlib_linalg_blas_c.fypp
stdlib_linalg_blas_z.fypp
stdlib_linalg_blas_w.fypp
stdlib_linalg_lapack.fypp
stdlib_linalg_lapack_aux.fypp
stdlib_linalg_lapack_s.fypp
stdlib_linalg_lapack_d.fypp
stdlib_linalg_lapack_q.fypp
stdlib_linalg_lapack_c.fypp
stdlib_linalg_lapack_z.fypp
stdlib_linalg_lapack_w.fypp
)

fypp_f90("${fyppFlags}" "${fppFiles}" outFiles)
fypp_f90pp("${fyppFlags}" "${cppFiles}" outPreprocFiles)

set(SRC
stdlib_ansi.f90
Expand All @@ -85,6 +106,7 @@ set(SRC
stdlib_quadrature_gauss.f90
stdlib_stringlist_type.f90
${outFiles}
${outPreprocFiles}
)

add_library(${PROJECT_NAME} ${SRC})
Expand Down
Loading
Loading