math_sets.f90 Source File


Contents

Source Code


Source Code

module foreng_math_sets
!! Contains functions that deal with the mathematical definition of sets. Find the union of two rank 1 arrays with \(\verb|union|\). Find 
!! the intersection with \(\verb|intersection|\). Check if a given x belongs to a set with \(\verb|belongs_to|\)
use foreng_env

implicit none

!=============================================================================!
!=                               Set Interface                               =!
!=============================================================================!
interface intersection 
!! Compute the intersection of two sets
    module procedure intersection_int
    module procedure intersection_r32
    module procedure intersection_r64

end interface

interface union
!! Compute the union of two sets
    module procedure union_int
    module procedure union_r32
    module procedure union_r64
end interface

interface belongs_to
!! Check if \(x \in \textrm{A}\) <br>
!! \(x\) belongs to \(A\) if there is at least one element \(y\) in \(A\) for which \(x = y\)
    module procedure belongs_to_int
    module procedure belongs_to_r32
    module procedure belongs_to_r64
end interface

interface array_epsilon
    module procedure array_epsilon_r32
    module procedure array_epsilon_r64
end interface

interface abs_max_val
    module procedure abs_max_val_r32
    module procedure abs_max_val_r64   
end interface 

!=============================================================================!
!=                               Set Functions                               =!
!=============================================================================!
contains 

    function intersection_int(A, B) result(inters)
        integer, dimension(:), intent(in) :: A !! set A
        integer, dimension(:), intent(in) :: B !! set B
        integer, dimension(:), allocatable :: inters !! \( A \cap B\)

        integer :: A_card
        integer :: i
        integer :: zero = 0

        A_card = size(A)

        do i = 1, A_card

            if (belongs_to(A(i), B)) then
                ! If element of set1 is ALSO in set2...

                if (allocated(inters)) then
                    inters = [inters, A(i)]
                else
                    allocate(inters(1))
                    inters = A(i)
                end if
            else 
                cycle
            end if

        end do

        if (.not. allocated(inters)) then 
            ! If the intersection is the empty set
            allocate(inters(1))
            inters = zero/zero

        end if

    end function

    function intersection_r32(A, B) result(inters)
        real(real32), dimension(:), intent(in) :: A !! set A
        real(real32), dimension(:), intent(in) :: B !! set B
        real(real32), dimension(:), allocatable :: inters !! \( A \cap B\)

        integer :: A_card
        integer :: i
        real(real32) :: zero = 0
        real(real32) :: eps

        eps = array_epsilon([A, B])
    
        A_card = size(A)

        do i = 1, A_card

            if (belongs_to(A(i), B, eps)) then
                ! If element of set1 is ALSO in set2...
                if (allocated(inters)) then
                    inters = [inters, A(i)]
                else
                    allocate(inters(1))
                    inters = A(i)
                end if
            else 
                cycle
            end if

        end do

        if (.not. allocated(inters)) then 
            ! If the intersection is the empty set
            allocate(inters(1))
            inters = zero/zero

        end if

    end function

    function intersection_r64(A, B) result(inters)
        real(real64), dimension(:), intent(in) :: A !! set A
        real(real64), dimension(:), intent(in) :: B !! set B
        real(real64), dimension(:), allocatable :: inters !! \( A \cap B\)

        integer :: A_card
        integer :: i
        real(real64) :: zero = 0
        real(real64) :: eps

        eps = array_epsilon([A, B])

        A_card = size(A)

        do i = 1, A_card

            if (belongs_to(A(i), B, eps)) then
                ! If element of set1 is ALSO in set2...

                if (allocated(inters)) then
                    inters = [inters, A(i)]
                else
                    allocate(inters(1))
                    inters = A(i)
                end if
            else 
                cycle
            end if

        end do

        if (.not. allocated(inters)) then 
            ! If the intersection is the empty set
            allocate(inters(1))
            inters = zero/zero

        end if

    end function

    function union_int(A, B) result(union_set)
        integer, intent(in), dimension(:) :: A !! set A
        integer, intent(in), dimension(:) :: B !! set B
        integer, dimension(:), allocatable :: union_set !! \( A \cup B\)

        integer :: B_cardinality
        integer :: i


        B_cardinality = size(B)

        ! Set union right away to A

        union_set = A

        do i = 1, B_cardinality

            if(belongs_to(B(i), union_set)) then
            ! If set2(i) is already a part of the union, then don't add it
                cycle
            else
                union_set = [union_set, B(i)]
            end if

        end do

    end function

    function union_r32(A, B) result(union_set)
        real(real32), intent(in), dimension(:) :: A !! set A
        real(real32), intent(in), dimension(:) :: B !! set B
        real(real32), dimension(:), allocatable :: union_set !! \( A \cup B\)

        integer :: B_cardinality
        integer :: i


        B_cardinality = size(B)

        ! Set union right away to A

        union_set = A

        do i = 1, B_cardinality

            if(belongs_to(B(i), union_set)) then
            ! If set2(i) is already a part of the union, then don't add it
                print *, "MATCH FOUND!!"
                cycle
            else
                union_set = [union_set, B(i)]
            end if

        end do

    end function

    function union_r64(A, B) result(union_set)
        real(real64), intent(in), dimension(:) :: A !! set A
        real(real64), intent(in), dimension(:) :: B !! set B
        real(real64), dimension(:), allocatable :: union_set !! \( A \cup B\)

        integer :: B_cardinality
        integer :: i


        B_cardinality = size(B)

        ! Set union right away to A

        union_set = A

        do i = 1, B_cardinality

            if(belongs_to(B(i), union_set)) then
            ! If set2(i) is already a part of the union, then don't add it
                cycle
            else
                union_set = [union_set, B(i)]
            end if

        end do

    end function

    logical function belongs_to_int(x, A) result(bool)
    !! Check if a value \(x\) belongs to a set \(\textrm{A}\)
        integer, intent(in) :: x 
        integer, dimension(:) :: A
        ! Check if an element belongs to a set

        integer :: cardinality ! Cardinality (size) of the set to check
        integer :: i

        cardinality = size(A)

        do i = 1, cardinality

            bool = .false.

            if (A(i) == x) then 
                bool = .true.
                return
            else
                cycle
            end if

        end do

    end function

    logical function belongs_to_r32(x, A, eps) result(bool)
    !! Check if a value \(x\) belongs to a set within a certain tolerance \(\epsilon\). If \(\epsilon\) is not specified, it will automatically
    !! calculated using the \(\verb|array_epsilon|\) function
        real(real32), intent(in) :: x 
        real(real32), dimension(:) :: A
        real(real32), optional :: eps !! \(x = y \iff \textrm{abs}(x - y) < \epsilon\)
        ! Check if an element belongs to a set

        integer :: cardinality ! Cardinality (size) of the set to check
        integer :: i
        real(real32) :: eps_

        if(.not. present(eps)) then
            eps_ = array_epsilon(A)
        else
            eps_ = eps
        end if

        cardinality = size([A, x])

        do i = 1, cardinality

            bool = .false.

            if (abs(A(i) - x) <= eps_) then 
                bool = .true.
                return
            else
                cycle
            end if

        end do

    end function

    logical function belongs_to_r64(x, A, eps) result(bool)
    !! Check if a value \(x\) belongs to a set within a certain tolerance \(\epsilon\). If \(\epsilon\) is not specified, it will automatically
    !! calculated using the \(\verb|array_epsilon|\) function
        real(real64), intent(in) :: x 
        real(real64), dimension(:) :: A
        real(real64), optional :: eps !! \(x = y \iff \textrm{abs}(x - y) < \epsilon\)
        ! Check if an element belongs to a set
    
            integer :: cardinality ! Cardinality (size) of the set to check
            integer :: i
    
            if(.not. present(eps)) then
                eps = array_epsilon([A, x])
            end if
    
            cardinality = size(A)
    
            do i = 1, cardinality
    
                bool = .false.
    
                if (abs(A(i) - x) < eps) then 
                    bool = .true.
                    return
                else
                    cycle
                end if
    
            end do
    
    end function    

    real(real32) function array_epsilon_r32(array) result(eps)
        real(real32), dimension(:), intent(in) :: array   

        real(real32) :: max_val
        
        max_val = abs_max_val(array)
        eps = epsilon(max_val)

    end function

    real(real64) function array_epsilon_r64(array) result(eps)
        real(real64), dimension(:), intent(in) :: array  

        real(real64) :: max_val
        
        max_val = abs_max_val(array)
        eps = epsilon(max_val)

    end function

    real(real32) function abs_max_val_r32(array) result(abs_max_val)
        real(real32), dimension(:), intent(in) :: array
        abs_max_val = maxval(abs(array))
    end function

    real(real64) function abs_max_val_r64(array) result(abs_max_val)
        real(real64), dimension(:), intent(in) :: array
        abs_max_val = maxval(abs(array))
    end function



end module