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

addition of stdlib_experimental_stats mean #124

Merged
merged 9 commits into from
Jan 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ jobs:
if: contains(matrix.os, 'ubuntu')
run: ci/install_cmake.sh

- name: Install fypp
run: pip install --upgrade fypp

- name: Install GFortran Linux
if: contains( matrix.os, 'ubuntu')
run: |
Expand All @@ -54,7 +57,7 @@ jobs:
run: brew install gcc@${GCC_V} || brew upgrade gcc@${GCC_V} || true

- name: Configure with CMake
run: cmake -Wdev -DCMAKE_BUILD_TYPE=Release -S . -B build
run: cmake -Wdev -DCMAKE_BUILD_TYPE=Release -DCMAKE_MAXIMUM_RANK=4 -S . -B build

- name: Build and compile
run: cmake --build build
Expand All @@ -77,6 +80,6 @@ jobs:
- name: Test manual makefiles
if: contains(matrix.os, 'ubuntu') && contains(matrix.gcc_v, '9')
run: |
make -f Makefile.manual
make -f Makefile.manual FYPPFLAGS="-DMAXRANK=4"
make -f Makefile.manual test
make -f Makefile.manual clean
5 changes: 4 additions & 1 deletion .github/workflows/ci_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ jobs:
steps:
- uses: actions/checkout@v1

- run: cmake -G "MinGW Makefiles" -DCMAKE_SH="CMAKE_SH-NOTFOUND" -Wdev -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_Fortran_FLAGS_DEBUG="-Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace"
- name: Install fypp
run: pip install fypp

- run: cmake -G "MinGW Makefiles" -DCMAKE_SH="CMAKE_SH-NOTFOUND" -Wdev -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_Fortran_FLAGS_DEBUG="-Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace" -DCMAKE_MAXIMUM_RANK=4

env:
FC: gfortran
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ endif()
include(CheckFortranSourceCompiles)
include(CheckFortranSourceRuns)
check_fortran_source_compiles("error stop i; end" f18errorstop SRC_EXT f90)
check_fortran_source_compiles("real, allocatable :: array(:, :, :, :, :, :, :, :, :, :); end" f03rank SRC_EXT f90)
check_fortran_source_runs("use, intrinsic :: iso_fortran_env, only : real128; real(real128) :: x; x = x+1; end" f03real128)

if(DEFINED CMAKE_MAXIMUM_RANK)
set(CMAKE_MAXIMUM_RANK ${CMAKE_MAXIMUM_RANK})
endif()

add_subdirectory(src)
2 changes: 2 additions & 0 deletions Makefile.manual
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

FC = gfortran
FFLAGS = -Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all
FYPPFLAGS=

export FC
export FFLAGS
export FYPPFLAGS

.PHONY: all clean test

Expand Down
49 changes: 49 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,59 @@
### Pre-process: .fpp -> .f90 via Fypp

# Create a list of the files to be preprocessed
set(fppFiles
stdlib_experimental_stats.fypp
stdlib_experimental_stats_mean.fypp
)

# Pre-process
foreach(infileName IN LISTS fppFiles)

# Generate output file name
string(REGEX REPLACE ".fypp\$" ".f90" outfileName "${infileName}")

# Create the full path for the new file
set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfileName}")

# Generate input file name
set(infile "${CMAKE_CURRENT_SOURCE_DIR}/${infileName}")

# Custom command to do the processing
if(DEFINED CMAKE_MAXIMUM_RANK)
add_custom_command(
OUTPUT "${outfile}"
COMMAND fypp -DMAXRANK=${CMAKE_MAXIMUM_RANK} "${infile}" "${outfile}"
MAIN_DEPENDENCY "${infile}"
VERBATIM)
elseif(f03rank)
add_custom_command(
OUTPUT "${outfile}"
COMMAND fypp "${infile}" "${outfile}"
MAIN_DEPENDENCY "${infile}"
VERBATIM)
else()
add_custom_command(
OUTPUT "${outfile}"
COMMAND fypp -DVERSION90 "${infile}" "${outfile}"
MAIN_DEPENDENCY "${infile}"
VERBATIM)
endif()

# Finally add output file to a list
set(outFiles ${outFiles} "${outfile}")

endforeach(infileName)



set(SRC
stdlib_experimental_ascii.f90
stdlib_experimental_io.f90
stdlib_experimental_error.f90
stdlib_experimental_kinds.f90
stdlib_experimental_optval.f90
stdlib_experimental_system.F90
${outFiles}
)

add_library(fortran_stdlib ${SRC})
Expand Down
12 changes: 11 additions & 1 deletion src/Makefile.manual
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ SRC = stdlib_experimental_ascii.f90 \
stdlib_experimental_io.f90 \
stdlib_experimental_optval.f90 \
stdlib_experimental_kinds.f90 \
f18estop.f90
f18estop.f90 \
stdlib_experimental_stats.f90 \
stdlib_experimental_stats_mean.f90

LIB = libstdlib.a

Expand All @@ -26,6 +28,8 @@ clean:
%.o: %.f90
$(FC) $(FFLAGS) -c $<

%.f90: %.fypp
fypp $(FYPPFLAGS) $< $@

# Fortran module dependencies
f18estop.o: stdlib_experimental_error.o
Expand All @@ -34,3 +38,9 @@ stdlib_experimental_io.o: \
stdlib_experimental_optval.o \
stdlib_experimental_kinds.o
stdlib_experimental_optval.o: stdlib_experimental_kinds.o
stdlib_experimental_stats_mean.o: \
stdlib_experimental_optval.o \
stdlib_experimental_kinds.o \
stdlib_experimental_stats.o
stdlib_experimental_stats.f90: stdlib_experimental_stats.fypp
stdlib_experimental_stats_mean.f90: stdlib_experimental_stats_mean.fypp
126 changes: 126 additions & 0 deletions src/stdlib_experimental_stats.fypp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
module stdlib_experimental_stats

#:set VERSION90 = defined('VERSION90')
#:set REALKINDS = ["sp", "dp", "qp"]
#:set INTKINDS = ["int8", "int16", "int32", "int64"]
#:set REALTYPES = ["real({})".format(k) for k in REALKINDS]
#:set INTTYPES = ["integer({})".format(k) for k in INTKINDS]
#:set iktr = list(zip(range(len(REALKINDS)), REALKINDS, REALTYPES))
#:set ikti = list(zip(range(len(INTKINDS)), INTKINDS, INTTYPES))

use stdlib_experimental_kinds, only: sp, dp, qp, &
int8, int16, int32, int64
implicit none
private
! Public API
public :: mean

interface mean
#:for i1, k1, t1 in iktr
module function mean_1_${k1}$_${k1}$(x) result(res)
${t1}$, intent(in) :: x(:)
${t1}$ :: res
end function mean_1_${k1}$_${k1}$
#:endfor

#:for i1, k1, t1 in ikti
module function mean_1_${k1}$_dp(x) result(res)
${t1}$, intent(in) :: x(:)
real(dp) :: res
end function mean_1_${k1}$_dp
#:endfor


#:for i1, k1, t1 in iktr
module function mean_2_all_${k1}$_${k1}$(x) result(res)
${t1}$, intent(in) :: x(:,:)
${t1}$ :: res
end function mean_2_all_${k1}$_${k1}$
#:endfor

#:for i1, k1, t1 in ikti
module function mean_2_all_${k1}$_dp(x) result(res)
${t1}$, intent(in) :: x(:,:)
real(dp) :: res
end function mean_2_all_${k1}$_dp
#:endfor

#:for i1, k1, t1 in iktr
module function mean_2_${k1}$_${k1}$(x, dim) result(res)
${t1}$, intent(in) :: x(:,:)
integer, intent(in) :: dim
${t1}$ :: res(merge(size(x, 1), size(x, 2), mask = 1 < dim ))
end function mean_2_${k1}$_${k1}$
#:endfor

#:for i1, k1, t1 in ikti
module function mean_2_${k1}$_dp(x, dim) result(res)
${t1}$, intent(in) :: x(:,:)
integer, intent(in) :: dim
real(dp) :: res(merge(size(x, 1), size(x, 2), mask = 1 < dim ))
end function mean_2_${k1}$_dp
#:endfor


#:def ranksuffix(rank)
#{if rank > 0}#(${":" + ",:" * (rank - 1)}$)#{endif}#
#:enddef

#:if defined('MAXRANK')
#:set ranks = range(3,MAXRANK+1)
#:elif VERSION90
#:set ranks = range(3,8)
#:else
#:set ranks = range(3,16)
#:endif


#:for i1, k1, t1 in iktr
#:for rank in ranks
module function mean_${rank}$_all_${k1}$_${k1}$(x) result(res)
${t1}$, intent(in) :: x${ranksuffix(rank)}$
${t1}$ :: res
end function mean_${rank}$_all_${k1}$_${k1}$
#:endfor
#:endfor

#:for i1, k1, t1 in ikti
#:for rank in ranks
module function mean_${rank}$_all_${k1}$_dp(x) result(res)
${t1}$, intent(in) :: x${ranksuffix(rank)}$
real(dp) :: res
end function mean_${rank}$_all_${k1}$_dp
#:endfor
#:endfor

#:for i1, k1, t1 in iktr
#:for rank in ranks
module function mean_${rank}$_${k1}$_${k1}$(x, dim) result(res)
${t1}$, intent(in) :: x${ranksuffix(rank)}$
integer, intent(in) :: dim
${t1}$ :: res( &
#:for imerge in range(1,rank-1)
merge(size(x,${imerge}$),size(x,${imerge + 1}$),mask = ${imerge}$ < dim ), &
#:endfor
merge(size(x,${rank-1}$),size(x,${rank}$),mask = ${rank-1}$ < dim ) )
end function mean_${rank}$_${k1}$_${k1}$
#:endfor
#:endfor

#:for i1, k1, t1 in ikti
#:for rank in ranks
module function mean_${rank}$_${k1}$_dp(x, dim) result(res)
${t1}$, intent(in) :: x${ranksuffix(rank)}$
integer, intent(in) :: dim
real(dp) :: res( &
#:for imerge in range(1,rank-1)
merge(size(x,${imerge}$),size(x,${imerge + 1}$),mask = ${imerge}$ < dim ), &
#:endfor
merge(size(x,${rank-1}$),size(x,${rank}$),mask = ${rank-1}$ < dim ) )
end function mean_${rank}$_${k1}$_dp
#:endfor
#:endfor

end interface

end module
43 changes: 43 additions & 0 deletions src/stdlib_experimental_stats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Descriptive statistics

## Implemented

* `mean`

## `mean` - mean of array elements

### Description

Returns the mean of all the elements of `array`, or of the elements of `array` along dimension `dim` if provided.

### Syntax

`result = mean(array)`

`result = mean(array, dim)`

### Arguments

`array`: Shall be an array of type `integer`, or `real`.

`dim`: Shall be a scalar of type `integer` with a value in the range from 1 to n, where n is the rank of `array`.

### Return value

If `array` is of type `real`, the result is of the same type as `array`.
If `array` is of type `integer`, the result is of type `double precision`.

If `dim` is absent, a scalar with the mean of all elements in `array` is returned. Otherwise, an array of rank n-1, where n equals the rank of `array`, and a shape similar to that of `array` with dimension `dim` dropped is returned.

### Example

```fortran
program test
use stdlib_experimental_stats, only: mean
implicit none
real :: x(1:6) = [ 1., 2., 3., 4., 5., 6. ]
print *, mean(x) !returns 21.
print *, mean( reshape(x, [ 2, 3 ] )) !returns 21.
print *, mean( reshape(x, [ 2, 3 ] ), 1) !returns [ 3., 7., 11. ]
end program
```
Loading