Search code examples
pythonarraylistfortransparse-matrix

Fortran: sparse arrays or lists


Is there any implementation of sparse arrays or equivalent lists in Fortran.

In the stage of computation of large data set we pass say an array of size of n=10000 to a subroutine to do some stuff on them. For example, finding similar elements in it and listing them for each item sequentially. That is, for item one, to find all similar items through the list (array) and to store the resulting marks. The resulting could be large as the list for each element. Note that regarding the criteria the similarity we use is not symmetric which means we need to iterate the evaluation for all items fully. The resulting therefore could be in different length for each according to criteria being used. Storing all the results therefore requires sparse arrays/list which is available in Python as:


R = an array             # an array
L = []                   # list initialization
for e in R:              # iteration on all elements of R 
    r = similars(e,R,criteria)  # r is array & different in size for each element
    L.append(r)          # store the ranks in list L

For simplicity now we use usual arrays in Fortran where for n<=1000 it is n*n. As you see this is a very inefficient idea for larger sizes. Any solution?


Solution

  • A solution without linked list.

    Here, one assumes that the vectors "r" contain double precision values.

    Notice that this solution uses no pointer, just allocatable arrays, which warrants to avoid memory leaks. The number of reallocations is limited (log2(list%n)) but one accepts to allocate list%result with a size larger than really needed (maximum twice).

    At last, the vectors "r" are duplicated in the list (this is not the case in the python version).

    module extendable_list
    
    implicit none
    
    type result_type
      double precision,allocatable :: vector(:)
    end type
    
    type list_type
      integer :: n
      type(result_type),allocatable :: result(:)
    end type
    
    contains
    
    subroutine append(list,r)
      type(list_type),intent(inout) :: list
      double precision,intent(in)   :: r(:)
      type(result_type),allocatable :: temporary(:)
      integer :: i
      if(.not.allocated(list%result)) then
        allocate(list%result(10))
        list%n=0
      else if(list%n >= size(list%result)) then
        allocate(temporary(2*list%n))
        do i=1,list%n
          call move_alloc(list%result(i)%vector,temporary(i)%vector)
        enddo
        call move_alloc(temporary,list%result)
      endif
      list%n=list%n+1
      allocate(list%result(list%n)%vector(size(r)))
      list%result(list%n)%vector=r
    end subroutine
    
    end module
    
    program main
      use extendable_list
      implicit none
      type(list_type) :: list
      integer :: i
      do i=1,10
        call append(list,(/1.d0,3.d0/))
        call append(list,(/7.d0,-9.d0,45.d0/))
      enddo
      do i=1,list%n
        write(*,*) list%result(i)%vector
      enddo
    end program
    

    Result :

    coul@b10p5001:~/test$ ifort t65.f90
    coul@b10p5001:~/test$ ./a.out
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000     
       1.00000000000000        3.00000000000000     
       7.00000000000000       -9.00000000000000        45.0000000000000