Blog articles using Fortran

As the post on research articles but for blogs :slight_smile:

Just read this blog in towardsdatascience that I think deserve a good applause: why you should consider using fortran as a data scientist

Shout out to the author, hope he is in community :+1:

12 Likes

It’s good to have blog posts promoting Fortran. Here are some comments on the post.

The first code shown

program example

    implicit none

    integer :: i

    i = 1

    write(*,*) 'Hello world'
    write(*,*) 1

end program example

has a bug because variable i is set but never used. The author meant write(*,*) i.

Here is a similar program that shows more Fortran features:

program example
    implicit none
    integer :: i, j
    i = 2
    j = 3
    write(*,*) 'Hello world'
    write(*,*) "i, j =", i, j
    ! ** is the power operator, and / between two integers truncates, as in Python 2 but not Python 3
    write(*,*) "i+j, i-j, i**2, i/j =", i+j, i-j, i**2, i/j
end program example
! output: note that other compilers may give different spacing
! Hello world
! i, j =           2           3
! i+j, i-j, i**2, i/j =           5          -1           4           0

In the author’s knapsack code, one could use list comprehension (in Fortran terms, an implied do-loop) instead of writing

weight = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220]

A code that does this and prints the elapsed time is

program knapsack
    implicit none
    ! define our variables
    integer, parameter :: num_items = 22, max_weight = 800
    integer :: i, j, k, m, new_weight, new_value, best_value
    integer :: weight(num_items), value(num_items), new_combination(num_items), best_combination(num_items)
    real :: t1, t2
    call cpu_time(t1)
    ! initialize our item weights and values
    weight = [(10*i, i=1, num_items)]
    value = [10, 2, 3, 4, 20, 68, 75, 58, 9, 29, 56, 43, 38, 91, 27, 33, 200, 18, 300, 18, 400, 200]
    best_value = 0
    do i = 0, 2**num_items-1  ! iterate through all possible subsets of items
        new_weight = 0
        new_value = 0
        ! convert subset number to binary representation
        k = i
        do j = num_items, 1, -1
            new_combination(j) = mod(k, 2) ! remainder is always 0 or 1, so we can make binary representation
            k = k/2 ! divide by two to shift the bits in 'k' to the right
        end do
        ! calculate total weight and value of items in subset
        do j = 1, num_items
            new_weight = new_weight + weight(j) * new_combination(j)
            new_value = new_value + value(j) * new_combination(j)
        end do
        ! check if subset is valid and update best value if necessary
        if (new_weight <= max_weight .and. new_value > best_value) then
            best_value = new_value
            best_combination = new_combination
        end if
    end do
    ! print the items and their weight and value in the best solution
    write(*,*) "Items in best combination:"
    do j = 1, num_items
        if (best_combination(j) == 1) then
            write(*,*) "Item:", j, "Weight:", weight(j), "Value:", value(j)
        end if
    end do
    write(*,*) "Best value: ", best_value
    call cpu_time(t2)
    print*,"elapsed time =", t2-t1
end program knapsack

The author finds that Fortran is 21 times faster than Python for his knapsack codes, but he compiles with gfortran -o brute brute_force.f90. In Python, to speed up your code, you can try numba, or translate it to Cython, or PyPy, or other approaches, but you need to install another tool, and you may need to change your code. In Fortran it is easier – just use optimization options. Compiling the code above with various options

gfortran xknapsack.f90 
gfortran -O3 xknapsack.f90
gfortran -O3 -march=native xknapsack.f90
gfortran -O3 -march=native -flto xknapsack.f90

gave times in seconds of

0.359375 
0.125000 
0.109375
0.093750

A further 4x speedup with no work is great. The author mentions

  • Historical Array Support: Fortran has had multi-dimensional array support from the beginning, which is essential for Machine Learning and Data Science such as Neural Networks.

Newcomers may not know that since the 1990 standard, Fortran has operations on arrays and array slices, as in Matlab and NumPy.

ChatGPT should expand the user base of Fortran, since it can translate Python or other languages to it. Asking ChatGPT-4 to translate the author’s Python code gives, with one correction as shown,

program knapsack
    implicit none
    integer, parameter :: num_items = 22, max_weight = 800
    integer :: best_value, new_weight, new_value, item
    integer, dimension(num_items) :: weight, value, best_combination, new_combination
    real(8) :: start_time, end_time, elapsed_time
    integer :: i, j
    logical :: in_knapsack

    ! Define weights and values
    data weight /10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220/
    data value /10, 2, 3, 4, 20, 68, 75, 58, 9, 29, 56, 43, 38, 91, 27, 33, 200, 18, 300, 18, 400, 200/

    best_value = 0
    best_combination = 0

    call cpu_time(start_time)

    ! Brute force search
    do i = 0, 2**num_items - 1
        new_combination = transfer(i, new_combination)
        new_combination = mod(new_combination, 2)
        new_weight = dot_product(weight, new_combination)
        new_value = dot_product(value, new_combination)
! original GPT line below
!        if (new_weight <= max_weight) .and. (new_value > best_value) then
        if (new_weight <= max_weight .and. new_value > best_value) then
            best_value = new_value
            best_combination = new_combination
        end if
    end do

    call cpu_time(end_time)

    ! Output results
    print *, "Items in best combination:"
    do item = 1, num_items
        in_knapsack = (best_combination(item) == 1)
        if (in_knapsack) then
            print '("Item ", i0, ": weight=", i0, ", value=", i0)', item, weight(item), value(item)
        end if
    end do

    print *, "Best value: ", best_value
    elapsed_time = end_time - start_time
    print '("Time taken: ", f0.6, " seconds")', elapsed_time

end program knapsack

Unfortunately, it gives the wrong answer. I will look at it later today.

7 Likes

Another blog article about Fortran (already recently cited in the Anecdotal Fortran thread):

5 Likes

You will also find interesting articles about OOP in Fortran, and Fortran on Windows:

I don’t know if the author is here, else we should invite him to join the Discourse. => done

4 Likes

well, I was obliged to edit this message to add that last @amasaki203 article (2023-08-28) because of that Discourse message:

An error occurred: No more than 3 consecutive replies are allowed. Please edit your previous reply, or wait for someone to reply to you.

Updated 2023-09-23:

And a few blogs already cited in Anecdotal Fortran:

9 Likes
1 Like

I wrote an article about regular expressions in Fortran. Read it if you would like .

10 Likes