Skip to content

Commit 0de3e80

Browse files
committed
Merge branch 'master' of https://github.com/fortran-lang/stdlib into add-pkg-config-ci
2 parents 5eb04c9 + e33b3eb commit 0de3e80

29 files changed

Lines changed: 1820 additions & 74 deletions
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: CI - Big-Endian
2+
3+
on:
4+
# Always run on pushes to the main branch
5+
push:
6+
branches: [master, main]
7+
# For PRs, ONLY run if the hash files or this workflow change
8+
pull_request:
9+
paths:
10+
- '.github/workflows/ci_big_endian.yml'
11+
- 'src/hash/**'
12+
- 'test/hash_functions/**'
13+
# Allow manual triggers from the GitHub Actions tab
14+
workflow_dispatch:
15+
16+
env:
17+
CTEST_TIME_TIMEOUT: "5" # some failures hang forever
18+
19+
jobs:
20+
test-big-endian:
21+
runs-on: ubuntu-24.04
22+
name: Test on s390x (big-endian)
23+
strategy:
24+
fail-fast: false
25+
26+
steps:
27+
- name: Checkout code
28+
uses: actions/checkout@v4
29+
30+
- name: Build and test on s390x
31+
uses: uraimo/run-on-arch-action@v3
32+
with:
33+
arch: s390x
34+
distro: ubuntu24.04
35+
36+
# Cache Docker image layer in GitHub Package Registry
37+
githubToken: ${{ github.token }}
38+
39+
# Install dependencies (cached in Docker image layer)
40+
install: |
41+
apt-get update -q -y
42+
apt-get install -q -y gfortran gcc g++ cmake python3-pip ninja-build git
43+
pip3 install --break-system-packages fypp
44+
45+
# Build and run big-endian tests
46+
run: |
47+
echo "=== Architecture Info ==="
48+
uname -m
49+
echo "Byte order: $(python3 -c 'import sys; print(sys.byteorder)')"
50+
51+
echo "=== Compiler Version ==="
52+
gfortran --version
53+
54+
echo "=== CMake Configure ==="
55+
cmake -G Ninja \
56+
-DCMAKE_BUILD_TYPE=Release \
57+
-DCMAKE_MAXIMUM_RANK:String=4 \
58+
-DFIND_BLAS:STRING=FALSE \
59+
-S . -B build
60+
61+
echo "=== Build (Targeted) ==="
62+
cmake --build build --target test_hash_functions --parallel
63+
64+
echo "=== Run Big-Endian Tests ==="
65+
ctest --test-dir build \
66+
-R hash_functions \
67+
--output-on-failure \
68+
--no-tests=error

.github/workflows/fpm-deployment.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ jobs:
4646
python config/fypp_deployment.py --with_xdp --with_qp
4747
fpm test --profile release --flag '-DWITH_XDP -DWITH_QP'
4848
49+
- run: | # Tests without xdp and qp
50+
python config/fypp_deployment.py
51+
fpm test --profile release
52+
4953
# Update and deploy the f90 files generated by github-ci to the `stdlib-fpm` branch.
5054
- name: Deploy 🚀
5155
uses: JamesIves/github-pages-deploy-action@4.1.5

doc/specs/stdlib_hash_procedures.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,16 @@ generating seeds for `universal_mult_hash`.
394394
All assume a two's complement sign bit, and no out of
395395
range checks.
396396

397+
**Endianness note:** Both `pengy_hash` and `spooky_hash` will produce
398+
different hash values on big-endian processors (e.g., s390x, SPARC,
399+
PowerPC) compared to little-endian processors (e.g., x86, ARM, RISC-V)
400+
for the same input bytes. The hash quality is equally good on both
401+
architectures, but the outputs are not cross-architecture portable.
402+
Do not use these hashes for cross-architecture verification (e.g.,
403+
hashing a file on an x86 system and verifying the hash on an IBM
404+
mainframe). The 32-bit hashes `nmhash32`, `nmhash32x`, and
405+
`water_hash` produce identical results on all architectures.
406+
397407
The `stdlib_hash_32bit_fnv` and `stdlib_hash_64bit_fnv`
398408
submodules each provide implementations of the FNV-1 and FNV-1A
399409
algorithms in the form of two separate overloaded functions: `FNV_1`
@@ -1366,6 +1376,9 @@ performance on long keys. It passes all the SMHasher tests, and has
13661376
no known bad seeds.
13671377
It is a *pure* function for integer arrays, and an *elemental*
13681378
function for character strings.
1379+
Note that `pengy_hash` will produce different hash values on
1380+
big-endian and little-endian processors for the same input. The hash
1381+
quality is equally good on both architectures.
13691382

13701383
##### Example
13711384

doc/specs/stdlib_linalg.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,100 @@ call [stdlib_linalg(module):constrained_lstsq_space(interface)]`(a, c, lwork [
11111111
`c`: Shall be a rank-2 `real` or `complex` array of the same kind as `a` defining the linear equality constraints. It is an `intent(in)` argument.
11121112
`lwork`: Shall be an `integer` scalar returning the optimal size required for the workspace array to solve the constrained least-squares problem.
11131113

1114+
## `weighted_lstsq` - Computes the weighted least squares solution to a linear matrix equation {#weighted-lstsq}
1115+
1116+
### Status
1117+
1118+
Experimental
1119+
1120+
### Description
1121+
1122+
This function computes the weighted least-squares solution to a linear matrix equation \( A \cdot x = b \) where each observation has a different weight.
1123+
1124+
The solver minimizes the weighted 2-norm \( \| D(Ax - b) \|_2^2 \) where \( D = \mathrm{diag}(\sqrt{w}) \) is a diagonal matrix formed from the square roots of the weight vector. This is equivalent to transforming the problem to ordinary least-squares through row scaling. The solver is based on LAPACK's `*GELSD` backends.
1125+
1126+
### Syntax
1127+
1128+
`x = ` [[stdlib_linalg(module):weighted_lstsq(interface)]] `(w, a, b [, cond, overwrite_a, rank, err])`
1129+
1130+
### Arguments
1131+
1132+
`w`: Shall be a rank-1 `real` array containing the weight vector. For complex `a` and `b`, `w` shall use the same real kind as the components of `a`. All weights must be positive. It is an `intent(in)` argument.
1133+
1134+
`a`: Shall be a rank-2 `real` or `complex` array containing the coefficient matrix. It is an `intent(inout)` argument.
1135+
1136+
`b`: Shall be a rank-1 array of the same kind as `a`, containing the right-hand-side vector. It is an `intent(in)` argument.
1137+
1138+
`cond` (optional): Shall be a scalar `real` value cut-off threshold for rank evaluation: singular values with `s_i <= cond*maxval(s)` are treated as zero, and the rank counts values with `s_i > cond*maxval(s), i=1:rank`. Shall be a scalar, `intent(in)` argument.
1139+
1140+
`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.
1141+
1142+
`rank` (optional): Shall be an `integer` scalar value, that contains the rank of input matrix `a`. This is an `intent(out)` argument.
1143+
1144+
`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument.
1145+
1146+
### Return value
1147+
1148+
Returns an array value of the same kind as `a`, containing the weighted least-squares solution.
1149+
1150+
Raises `LINALG_VALUE_ERROR` if any weight is non-positive or if the matrix and weight/right-hand-side have incompatible sizes.
1151+
Raises `LINALG_ERROR` if the underlying Singular Value Decomposition process did not converge.
1152+
Exceptions trigger an `error stop`.
1153+
1154+
### Example
1155+
1156+
```fortran
1157+
{!example/linalg/example_weighted_lstsq.f90!}
1158+
```
1159+
1160+
## `solve_weighted_lstsq` - Compute the weighted least squares solution to a linear matrix equation (subroutine interface). {#solve-weighted-lstsq}
1161+
1162+
### Status
1163+
1164+
Experimental
1165+
1166+
### Description
1167+
1168+
This subroutine computes the weighted least-squares solution to a linear matrix equation \( A \cdot x = b \) where each observation has a different weight.
1169+
1170+
The solver minimizes the weighted 2-norm \( \| D(Ax - b) \|_2^2 \) where \( D = \mathrm{diag}(\sqrt{w}) \) is a diagonal matrix formed from the square roots of the weight vector. This is equivalent to transforming the problem to ordinary least-squares through row scaling. The solver is based on LAPACK's `*GELSD` backends.
1171+
1172+
### Syntax
1173+
1174+
`call ` [[stdlib_linalg(module):solve_weighted_lstsq(interface)]] `(w, a, b, x [, cond, overwrite_a, rank, err])`
1175+
1176+
### Arguments
1177+
1178+
`w`: Shall be a rank-1 `real` array containing the weight vector. For complex `a` and `b`, `w` shall use the same real kind as the components of `a`. All weights must be positive. It is an `intent(in)` argument.
1179+
1180+
`a`: Shall be a rank-2 `real` or `complex` array containing the coefficient matrix. It is an `intent(inout)` argument.
1181+
1182+
`b`: Shall be a rank-1 array of the same kind as `a`, containing the right-hand-side vector. It is an `intent(in)` argument.
1183+
1184+
`x`: Shall be a rank-1 array of the same kind as `a`, and size of at least `n`, containing the solution to the weighted least squares system. It is an `intent(inout)` argument.
1185+
1186+
`cond` (optional): Shall be a scalar `real` value cut-off threshold for rank evaluation: singular values with `s_i <= cond*maxval(s)` are treated as zero, and the rank counts values with `s_i > cond*maxval(s), i=1:rank`. Shall be a scalar, `intent(in)` argument.
1187+
1188+
`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.
1189+
1190+
`rank` (optional): Shall be an `integer` scalar value, that contains the rank of input matrix `a`. This is an `intent(out)` argument.
1191+
1192+
`err` (optional): Shall be a `type(linalg_state_type)` value. This is an `intent(out)` argument.
1193+
1194+
### Return value
1195+
1196+
Returns an array value of the same kind as `a`, containing the weighted least-squares solution.
1197+
1198+
Raises `LINALG_VALUE_ERROR` if any weight is non-positive or if the matrix and weight/right-hand-side have incompatible sizes.
1199+
Raises `LINALG_ERROR` if the underlying Singular Value Decomposition process did not converge.
1200+
Exceptions trigger an `error stop`.
1201+
1202+
### Example
1203+
1204+
```fortran
1205+
{!example/linalg/example_weighted_lstsq.f90!}
1206+
```
1207+
11141208
## `det` - Computes the determinant of a square matrix
11151209

11161210
### Status

doc/specs/stdlib_stats.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,110 @@ If `mask` is specified, the result is the _k_-th (central) moment of all elemen
283283
{!example/stats/example_moment.f90!}
284284
```
285285

286+
## `pca` - Principal Component Analysis
287+
288+
### Status
289+
290+
Experimental
291+
292+
### Description
293+
294+
Performs Principal Component Analysis (PCA) on a 2D array of observations and features.
295+
The input matrix `x` has shape `(m, n)`, where `m` is the number of observations and `n` is the number of features.
296+
The subroutine computes the principal components (loadings), the singular values, and optionally the feature means.
297+
298+
Two methods are supported:
299+
- `"svd"`: (Default) Computes PCA via Singular Value Decomposition of the centered data. This is generally more numerically stable.
300+
- `"eig"` or `"cov"`: Computes PCA via Eigendecomposition of the covariance matrix.
301+
302+
### Syntax
303+
304+
`call ` [[stdlib_stats(module):pca(interface)]] `(x, components, singular_values [, x_mean, method, overwrite_x, err])`
305+
306+
### Class
307+
308+
Generic subroutine
309+
310+
### Arguments
311+
312+
`x`: Shall be a rank-2 real array with shape `(m, n)`. It is an `intent(inout)` argument. If `overwrite_x` is `.true.`, `x` may be modified during computation.
313+
314+
`components`: Shall be a rank-2 real array with shape `(n_components, n)`. It stores the principal components as rows. It is an `intent(out)` argument.
315+
316+
`singular_values`: Shall be a rank-1 real array with shape `(n_components)`. It stores the singular values in descending order. It is an `intent(out)` argument.
317+
318+
`x_mean` (optional): Shall be a rank-1 real array with shape `(n)`. It stores the mean of each feature (column). It is an `intent(out)` argument.
319+
320+
`method` (optional): Shall be a character string. Either `"svd"` or `"eig"`/`"cov"`. It is an `intent(in)` argument.
321+
322+
`overwrite_x` (optional): Shall be a scalar of type `logical`. If `.true.`, the input matrix `x` can be used as a workspace and modified. It is an `intent(in)` argument.
323+
324+
`err` (optional): Shall be of type `linalg_state_type`. It is an `intent(out)` argument.
325+
326+
### Example
327+
328+
```fortran
329+
{!example/stats/example_pca.f90!}
330+
```
331+
332+
## `pca_transform` - Projects data into principal component space
333+
334+
### Status
335+
336+
Experimental
337+
338+
### Description
339+
340+
Projects the input data `x` into the reduced dimensional space defined by the provided principal components.
341+
The transformation is defined as `x_transformed = (x - x_mean) * components^T`.
342+
343+
### Syntax
344+
345+
`call ` [[stdlib_stats(module):pca_transform(interface)]] `(x, components, x_transformed [, x_mean])`
346+
347+
### Class
348+
349+
Generic subroutine
350+
351+
### Arguments
352+
353+
`x`: Shall be a rank-2 real array with shape `(m, n)`. It is an `intent(in)` argument.
354+
355+
`components`: Shall be a rank-2 real array with shape `(nc, n)`. It stores the principal components as rows. It is an `intent(in)` argument.
356+
357+
`x_transformed`: Shall be a rank-2 real array with shape `(m, nc)`. It stores the projected data. It is an `intent(out)` argument.
358+
359+
`x_mean` (optional): Shall be a rank-1 real array with shape `(n)`. It stores the feature means to subtract. It is an `intent(in)` argument.
360+
361+
## `pca_inverse_transform` - Reconstructs original data from principal component space
362+
363+
### Status
364+
365+
Experimental
366+
367+
### Description
368+
369+
Reconstructs the original data representation from the principal component space.
370+
The reconstruction is defined as `x_reconstructed = x_reduced * components + x_mean`.
371+
372+
### Syntax
373+
374+
`call ` [[stdlib_stats(module):pca_inverse_transform(interface)]] `(x_reduced, components, x_reconstructed [, x_mean])`
375+
376+
### Class
377+
378+
Generic subroutine
379+
380+
### Arguments
381+
382+
`x_reduced`: Shall be a rank-2 real array with shape `(m, nc)`. It is an `intent(in)` argument.
383+
384+
`components`: Shall be a rank-2 real array with shape `(nc, n)`. It stores the principal components as rows. It is an `intent(in)` argument.
385+
386+
`x_reconstructed`: Shall be a rank-2 real array with shape `(m, n)`. It stores the reconstructed data. It is an `intent(out)` argument.
387+
388+
`x_mean` (optional): Shall be a rank-1 real array with shape `(n)`. It stores the feature means to add back. It is an `intent(in)` argument.
389+
286390
## `var` - variance of array elements
287391

288392
### Status

doc/specs/stdlib_str2num.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ The accuracy of the conversion is implementation dependent; it is recommended th
7575

7676
`sp` : exact match
7777

78-
`dp` : precision up-to epsilon(0.0_dp)
78+
`dp` : precision up-to 10*epsilon(0.0_dp)
7979

80-
`qp` : precision around 200*epsilon(0.0_qp)
80+
`qp` : precision around 100*epsilon(0.0_qp)
8181

8282
Where precision refers to the relative difference between `to_num` and `read`. On the other hand, `to_num` provides speed-ups ranging from 4x to >10x compared to the intrinsic `read`.

example/linalg/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ ADD_EXAMPLE(lstsq1)
3737
ADD_EXAMPLE(lstsq2)
3838
ADD_EXAMPLE(constrained_lstsq1)
3939
ADD_EXAMPLE(constrained_lstsq2)
40+
ADD_EXAMPLE(weighted_lstsq)
4041
ADD_EXAMPLE(norm)
4142
ADD_EXAMPLE(mnorm)
4243
ADD_EXAMPLE(get_norm)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
! Weighted least-squares solver: function and subroutine interfaces
2+
program example_weighted_lstsq
3+
use stdlib_linalg_constants, only: dp
4+
use stdlib_linalg, only: weighted_lstsq, solve_weighted_lstsq
5+
implicit none
6+
7+
real(dp) :: A(4,2), b(4), w(4), x_sub(2)
8+
real(dp), allocatable :: x(:)
9+
10+
! Design matrix: intercept + slope
11+
A(:,1) = 1.0_dp
12+
A(:,2) = [1.0_dp, 2.0_dp, 3.0_dp, 4.0_dp]
13+
14+
! Observations (one outlier at position 3)
15+
b = [2.1_dp, 4.0_dp, 10.0_dp, 7.9_dp]
16+
17+
! Weights: downweight the outlier
18+
w = [1.0_dp, 1.0_dp, 0.1_dp, 1.0_dp]
19+
20+
! Solve weighted least-squares (function interface)
21+
x = weighted_lstsq(w, A, b)
22+
23+
print '("Function interface: intercept = ",f8.4,", slope = ",f8.4)', x(1), x(2)
24+
! Function interface: intercept = 0.1500, slope = 1.9911
25+
26+
! Solve weighted least-squares (subroutine interface)
27+
call solve_weighted_lstsq(w, A, b, x_sub)
28+
29+
print '("Subroutine interface: intercept = ",f8.4,", slope = ",f8.4)', x_sub(1), x_sub(2)
30+
! Subroutine interface: intercept = 0.1500, slope = 1.9911
31+
32+
end program example_weighted_lstsq

0 commit comments

Comments
 (0)