Module osl_core

module osl_core

    ! Variables
    integer, public, parameter :: osl_sp = selected_real_kind (6, 37)
    integer, public, parameter :: osl_dp = selected_real_kind (15, 307)
    integer, public, parameter :: osl_wp = osl_dp
    integer, public, parameter :: osl_i1b = selected_int_kind (2)
    integer, public, parameter :: osl_i2b = selected_int_kind (4)
    integer, public, parameter :: osl_i4b = selected_int_kind (9)
    integer, public, parameter :: osl_i8b = selected_int_kind (18)
    integer, private, parameter :: sp = osl_sp
    integer, private, parameter :: dp = osl_dp
    integer, private, parameter :: wp = osl_wp
    real (kind=wp), public, parameter :: osl_eps_sp = epsilon (1.0_sp)
    real (kind=wp), public, parameter :: osl_eps_dp = epsilon (1.0_dp)
    real (kind=wp), public, parameter :: osl_eps_wp = epsilon (1.0_wp)
    real (kind=wp), public, parameter :: osl_e = 2.71828182845904523536028747135_wp
    real (kind=wp), public, parameter :: osl_pi = 3.14159265358979323846264338327_wp
    real (kind=wp), public, parameter :: osl_pi_2 = 1.57079632679489661923132169163_wp
    real (kind=wp), public, parameter :: osl_pi_4 = 0.78539816339744830961566084582_wp
    real (kind=wp), public, parameter :: osl_2pi = 6.28318530717958647692528676655_wp
    real (kind=wp), public, parameter :: osl_1_pi = 0.31830988618379067153776752675_wp
    real (kind=wp), public, parameter :: osl_2_pi = 0.63661977236758134307553505349_wp
    real (kind=wp), public, parameter :: osl_sqrt2 = 1.41421356237309504880168872420_wp
    real (kind=wp), public, parameter :: osl_sqrt1_2 = 0.70710678118654752440084436210_wp
    real (kind=wp), public, parameter :: osl_sqrt3 = 1.73205080756887729352744634151_wp
    real (kind=wp), public, parameter :: osl_sqrtpi = 1.77245385090551602729816748334_wp
    real (kind=wp), public, parameter :: osl_euler = 0.57721566490153286060651209008_wp
    character (len=*), public, parameter :: osl_ed_i = 'i10'
    character (len=*), public, parameter :: osl_ed_wp = 'g17.5'
    integer, public, dimension(1), parameter :: osl_ctx = (/ 0 /)
    logical, private :: osl_error_halt = .true.
    integer, public, parameter :: osl_error_msg_len = 64
    integer, public, parameter :: OSL_FAIL = -1
    integer, public, parameter :: OSL_SUCCESS = 0
    integer, public, parameter :: OSL_EDOM = 1
    integer, public, parameter :: OSL_ERANGE = 2
    integer, public, parameter :: OSL_EINVAL = 3
    integer, public, parameter :: OSL_ESANITY = 7
    integer, public, parameter :: OSL_ENOMEM = 8
    integer, public, parameter :: OSL_EMAXITER = 11
    integer, public, parameter :: OSL_EUNDRFLW = 15
    integer, public, parameter :: OSL_EOVRFLW = 16
    integer, public, parameter :: OSL_EBADLEN = 19
    integer, public, parameter :: OSL_ENOTSQR = 20
    integer, public, parameter :: OSL_EINIT = 100

    ! Interfaces
    public interface osl_print
    public interface osl_sgn
    public interface osl_log_sum_exp
    public interface osl_is_finite
    public interface osl_is_nan
    public interface osl_swap
    public interface osl_reverse
    public interface osl_linspace

    ! Subroutines and functions
    public subroutine osl_print_mwp(msg, A)
    public subroutine osl_print_mi(msg, A)
    public subroutine osl_print_vwp(msg, vec)
    public subroutine osl_print_vi(msg, vec)
    public subroutine osl_print_swp(msg, x)
    public subroutine osl_print_si(msg, x)
    public subroutine osl_print_str(msg)
    public subroutine osl_print_header(text)
    public subroutine osl_print_subheader(text)
    public subroutine osl_error_behavior(halt)
    public subroutine osl_error(reason, errno)
    public function osl_error_msg(errno)
    public elemental function osl_sgn_i(x)
    public elemental function osl_sgn_wp(x)
    public elemental function osl_exp(x)
    public elemental function osl_log(x)
    public function osl_log_sum_exp_mwp(V) result (E)
    public function osl_log_sum_exp_vwp(v) result (e)
    public function osl_sigmoid(theta)
    public elemental function osl_is_nan_wp(x)
    public elemental function osl_is_finite_wp(x)
    public subroutine osl_swap_scalar_wp(a, b)
    public subroutine osl_swap_scalar_i(a, b)
    public subroutine osl_swap_vector_wp(a, b)
    public subroutine osl_swap_vector_i(a, b)
    public subroutine osl_reverse_vector_wp(a)
    public subroutine osl_reverse_vector_i(a)
    public function osl_outer_product(a, b) result (C)
    public function osl_linspace_swp(a, b, n)
    public function osl_linspace_vwp(a, b, n)

end module osl_core

Description of Variables

osl_sp

integer, public, parameter :: osl_sp = selected_real_kind (6, 37)

osl_dp

integer, public, parameter :: osl_dp = selected_real_kind (15, 307)

osl_wp

integer, public, parameter :: osl_wp = osl_dp

osl_i1b

integer, public, parameter :: osl_i1b = selected_int_kind (2)

osl_i2b

integer, public, parameter :: osl_i2b = selected_int_kind (4)

osl_i4b

integer, public, parameter :: osl_i4b = selected_int_kind (9)

osl_i8b

integer, public, parameter :: osl_i8b = selected_int_kind (18)

sp

integer, private, parameter :: sp = osl_sp

dp

integer, private, parameter :: dp = osl_dp

wp

integer, private, parameter :: wp = osl_wp

osl_eps_sp

real (kind=wp), public, parameter :: osl_eps_sp = epsilon (1.0_sp)

osl_eps_dp

real (kind=wp), public, parameter :: osl_eps_dp = epsilon (1.0_dp)

osl_eps_wp

real (kind=wp), public, parameter :: osl_eps_wp = epsilon (1.0_wp)

osl_e

real (kind=wp), public, parameter :: osl_e = 2.71828182845904523536028747135_wp

osl_pi

real (kind=wp), public, parameter :: osl_pi = 3.14159265358979323846264338327_wp

osl_pi_2

real (kind=wp), public, parameter :: osl_pi_2 = 1.57079632679489661923132169163_wp

osl_pi_4

real (kind=wp), public, parameter :: osl_pi_4 = 0.78539816339744830961566084582_wp

osl_2pi

real (kind=wp), public, parameter :: osl_2pi = 6.28318530717958647692528676655_wp

osl_1_pi

real (kind=wp), public, parameter :: osl_1_pi = 0.31830988618379067153776752675_wp

osl_2_pi

real (kind=wp), public, parameter :: osl_2_pi = 0.63661977236758134307553505349_wp

osl_sqrt2

real (kind=wp), public, parameter :: osl_sqrt2 = 1.41421356237309504880168872420_wp

osl_sqrt1_2

real (kind=wp), public, parameter :: osl_sqrt1_2 = 0.70710678118654752440084436210_wp

osl_sqrt3

real (kind=wp), public, parameter :: osl_sqrt3 = 1.73205080756887729352744634151_wp

osl_sqrtpi

real (kind=wp), public, parameter :: osl_sqrtpi = 1.77245385090551602729816748334_wp

osl_euler

real (kind=wp), public, parameter :: osl_euler = 0.57721566490153286060651209008_wp

osl_ed_i

character (len=*), public, parameter :: osl_ed_i = 'i10'

osl_ed_wp

character (len=*), public, parameter :: osl_ed_wp = 'g17.5'

osl_ctx

integer, public, dimension(1), parameter :: osl_ctx = (/ 0 /)

A context mold for generic interfaces.

osl_error_halt

logical, private :: osl_error_halt = .true.

osl_error_msg_len

integer, public, parameter :: osl_error_msg_len = 64

OSL_FAIL

integer, public, parameter :: OSL_FAIL = -1

OSL_SUCCESS

integer, public, parameter :: OSL_SUCCESS = 0

OSL_EDOM

integer, public, parameter :: OSL_EDOM = 1

OSL_ERANGE

integer, public, parameter :: OSL_ERANGE = 2

OSL_EINVAL

integer, public, parameter :: OSL_EINVAL = 3

OSL_ESANITY

integer, public, parameter :: OSL_ESANITY = 7

OSL_ENOMEM

integer, public, parameter :: OSL_ENOMEM = 8

OSL_EMAXITER

integer, public, parameter :: OSL_EMAXITER = 11

OSL_EUNDRFLW

integer, public, parameter :: OSL_EUNDRFLW = 15

OSL_EOVRFLW

integer, public, parameter :: OSL_EOVRFLW = 16

OSL_EBADLEN

integer, public, parameter :: OSL_EBADLEN = 19

OSL_ENOTSQR

integer, public, parameter :: OSL_ENOTSQR = 20

OSL_EINIT

integer, public, parameter :: OSL_EINIT = 100

Description of Interfaces

osl_print

public interface osl_print
    module procedure osl_print_str
    module procedure osl_print_swp
    module procedure osl_print_vwp
    module procedure osl_print_mwp
    module procedure osl_print_si
    module procedure osl_print_vi
    module procedure osl_print_mi
end interface osl_print

osl_sgn

public interface osl_sgn
    module procedure osl_sgn_i
    module procedure osl_sgn_wp
end interface osl_sgn

osl_log_sum_exp

public interface osl_log_sum_exp
    module procedure osl_log_sum_exp_vwp
    module procedure osl_log_sum_exp_mwp
end interface osl_log_sum_exp

osl_is_finite

public interface osl_is_finite
    module procedure osl_is_finite_wp
end interface osl_is_finite

osl_is_nan

public interface osl_is_nan
    module procedure osl_is_nan_wp
end interface osl_is_nan

osl_swap

public interface osl_swap
    module procedure osl_swap_scalar_wp
    module procedure osl_swap_scalar_i
    module procedure osl_swap_vector_wp
    module procedure osl_swap_vector_i
end interface osl_swap

osl_reverse

public interface osl_reverse
    module procedure osl_reverse_vector_wp
    module procedure osl_reverse_vector_i
end interface osl_reverse

osl_linspace

public interface osl_linspace
    module procedure osl_linspace_swp
    module procedure osl_linspace_vwp
end interface osl_linspace

Description of Subroutines and Functions

osl_print_mwp

public subroutine osl_print_mwp(msg, A)
    character (len=*), intent(in) :: msg
    real (kind=wp), dimension(:,:), intent(in) :: A
end subroutine osl_print_mwp

Print a message alongside a `real(wp)` matrix.

osl_print_mi

public subroutine osl_print_mi(msg, A)
    character (len=*), intent(in) :: msg
    integer, dimension(:,:), intent(in) :: A
end subroutine osl_print_mi

Print a message alongside an integer matrix.

osl_print_vwp

public subroutine osl_print_vwp(msg, vec)
    character (len=*), intent(in) :: msg
    real (kind=wp), dimension(:), intent(in) :: vec
end subroutine osl_print_vwp

Print a message above a `real(wp)` vector. If the vector has more than ten elements, then ten elements will be printed on each line.

osl_print_vi

public subroutine osl_print_vi(msg, vec)
    character (len=*), intent(in) :: msg
    integer, dimension(:), intent(in) :: vec
end subroutine osl_print_vi

Print a message above an integer vector. If the vector has more than ten elements, ten elements will be printed on each line.

osl_print_swp

public subroutine osl_print_swp(msg, x)
    character (len=*), intent(in) :: msg
    real (kind=wp), intent(in) :: x
end subroutine osl_print_swp

Print a message alongside a `real(wp)` scalar.

osl_print_si

public subroutine osl_print_si(msg, x)
    character (len=*), intent(in) :: msg
    integer, intent(in) :: x
end subroutine osl_print_si

Print a message alongside an integer scalar.

osl_print_str

public subroutine osl_print_str(msg)
    character (len=*), intent(in) :: msg
end subroutine osl_print_str

Prints a single string.

osl_print_header

public subroutine osl_print_header(text)
    character (len=*), intent(in) :: text
end subroutine osl_print_header

Print a header consisting of TEXT underlined by equals signs.

osl_print_subheader

public subroutine osl_print_subheader(text)
    character (len=*), intent(in) :: text
end subroutine osl_print_subheader

Print a subheader consisting of TEXT underlined by hyphens.

osl_error_behavior

public subroutine osl_error_behavior(halt)
    logical, optional, intent(in) :: halt
end subroutine osl_error_behavior

Configure OSL error handling behavior.

osl_error

public subroutine osl_error(reason, errno)
    character (len=*), intent(in) :: reason
    integer, intent(in) :: errno
end subroutine osl_error

Default error handler. If osl_error_halt is `.true.`, print the error message and terminate the program. Otherwise, the calling program is expected to handle the error.

osl_error_msg

public function osl_error_msg(errno)
    integer, intent(in) :: errno
    character (len=osl_error_msg_len) :: osl_error_msg
end function osl_error_msg

Return a string describing the error with number errno.

osl_sgn_i

public elemental function osl_sgn_i(x)
    integer, intent(in) :: x
    integer :: osl_sgn_i
end function osl_sgn_i

Return 1 if the X is nonnegative and -1 otherwise.

osl_sgn_wp

public elemental function osl_sgn_wp(x)
    real (kind=wp), intent(in) :: x
    integer :: osl_sgn_wp
end function osl_sgn_wp

Return 1 if X is nonnegative and -1 otherwise.

osl_exp

public elemental function osl_exp(x)
    real (kind=wp), intent(in) :: x
    real (kind=wp) :: osl_exp
end function osl_exp

Return the value of a bounded version of exp designed to prevent overflow.

osl_log

public elemental function osl_log(x)
    real (kind=wp), intent(in) :: x
    real (kind=wp) :: osl_log
end function osl_log

Return the value of a bounded version of log designed to prevent underflow.

osl_log_sum_exp_mwp

public function osl_log_sum_exp_mwp(V) result(E)
    real (kind=wp), dimension(:,:), intent(in) :: V
    real (kind=wp), dimension(size(V,1)) :: E
end function osl_log_sum_exp_mwp

Given a matrix V = ( v(k,j) ) for k = 1, ..., K and j = 1,...,J, this function returns a vector of length K where the k-th component is `log( exp( v(k,1) ) + ... + exp( v(k,J) ) )`. This function calls the real(wp) vector version of this function for each row of the matrix V.

Here, V is a K-by-J input matrix and E is a K-by-1 output vector.

osl_log_sum_exp_vwp

public function osl_log_sum_exp_vwp(v) result(e)
    real (kind=wp), dimension(:), intent(in) :: v
    real (kind=wp) :: e
end function osl_log_sum_exp_vwp

Given a vector v of length J, this function returns the value `log(exp(v(1)) + ... + exp(v(J)))`. In order to prevent numerical overflow, it first shifts the vector v by a constant c, applies exp and log, and then adjusts the result to account for the shift.

Consider the case when `v = (a, b)`. Note that we can write exp(a) + exp(b) = [exp(a-c) + exp(b-c)]*exp(c) for any c. Furthermore, we have log( ( exp(a-c) + exp(b-c) ) * exp(c) ) = log( exp(a-c) + exp(b-c) ) + c. By choosing c appropriately, we can attempt to ensure that exp is not evaluated at a number large enough to cause overflow. Underflow is also possible as taking log of a number close to zero may result in `-Inf`. Thus, this function also adjusts for large negative elements of v. Note that this function is still not completely robust to very poorly scaled vectors v. Overflow or underflow is still possible.

For a set of J constants u_1, ..., u_J, if e_j is iid with Type 1 Extreme value distribution, this function returns the expected value of `max(u_1 + e_1, ..., u_J + e_J)`.

osl_sigmoid

public function osl_sigmoid(theta)
    real (kind=wp), dimension(:), intent(in) :: theta
    real (kind=wp), dimension(size(theta,1)+1) :: osl_sigmoid
end function osl_sigmoid

Takes as input a vector of length n-1 and passes it through a multidimensional sigmoid mapping to return a vector of length n whose elements are nonnegative and sum to one. The i-th element of the input vector controls the relative magnitude of the i-th element of the output vector. The value corresponding to the n-th element is internally normalized to 1. Thus, if input element j is smaller than 1, then on output element j will be smaller than element n. Similarly if input element j is larger than 1.

This function is useful for performing unconstrained optimization on parameters which correspond to a complete set of probabilities, since each of them must be nonnegative and the set must sum to one.

osl_is_nan_wp

public elemental function osl_is_nan_wp(x)
    real (kind=wp), intent(in) :: x
    logical :: osl_is_nan_wp
end function osl_is_nan_wp

Return `.true.` if the value of the given real variable is NaN and `.false.` otherwise.

osl_is_finite_wp

public elemental function osl_is_finite_wp(x)
    real (kind=wp), intent(in) :: x
    logical :: osl_is_finite_wp
end function osl_is_finite_wp

Return `.true.` if the given real variable is finite and `.false.` otherwise. Finite is defined as value other than Inf or NaN.

osl_swap_scalar_wp

public subroutine osl_swap_scalar_wp(a, b)
    real (kind=wp), intent(inout) :: a
    real (kind=wp), intent(inout) :: b
end subroutine osl_swap_scalar_wp

Swap the values of two `real(wp)` scalars.

osl_swap_scalar_i

public subroutine osl_swap_scalar_i(a, b)
    integer, intent(inout) :: a
    integer, intent(inout) :: b
end subroutine osl_swap_scalar_i

Swap the values of two integer scalars.

osl_swap_vector_wp

public subroutine osl_swap_vector_wp(a, b)
    real (kind=wp), dimension(:), intent(inout) :: a
    real (kind=wp), dimension(:), intent(inout) :: b
end subroutine osl_swap_vector_wp

Swaps the contents of two `real(wp)` vectors.

osl_swap_vector_i

public subroutine osl_swap_vector_i(a, b)
    integer, dimension(:), intent(inout) :: a
    integer, dimension(:), intent(inout) :: b
end subroutine osl_swap_vector_i

Swaps the contents of two integer vectors.

osl_reverse_vector_wp

public subroutine osl_reverse_vector_wp(a)
    real (kind=wp), dimension(:), intent(inout) :: a
end subroutine osl_reverse_vector_wp

Reverse the elements of a `real(wp)` vector A.

osl_reverse_vector_i

public subroutine osl_reverse_vector_i(a)
    integer, dimension(:), intent(inout) :: a
end subroutine osl_reverse_vector_i

Reverse the elements of an integer vector A.

osl_outer_product

public function osl_outer_product(a, b) result(C)
    real (kind=wp), dimension(:), intent(in) :: a
    real (kind=wp), dimension(:), intent(in) :: b
    real (kind=wp), dimension(size(a), size(b)) :: C
end function osl_outer_product

Return the outer product of the vectors A and B.

osl_linspace_swp

public function osl_linspace_swp(a, b, n)
    real (kind=wp), intent(in) :: a
    real (kind=wp), intent(in) :: b
    integer, intent(in) :: n
    real (kind=wp), dimension(n) :: osl_linspace_swp
end function osl_linspace_swp

Return N evenly-spaced scalars from A to B.

osl_linspace_vwp

public function osl_linspace_vwp(a, b, n)
    real (kind=wp), dimension(:), intent(in) :: a
    real (kind=wp), dimension(:), intent(in) :: b
    integer, intent(in) :: n
    real (kind=wp), dimension(n,size(a)) :: osl_linspace_vwp
end function osl_linspace_vwp

Return N evenly-spaced vectors from A to B.